summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2016-03-30 07:41:13 -0400
committerLibravatar Drew DeVault <sir@cmpwn.com>2016-03-30 07:41:13 -0400
commit4bf10d77713f5ea9fdc05c084a26a5eb1d5bc3c5 (patch)
treeac04166d4e75b4cf7617705e31214f73f2398655
parentMerge pull request #555 from mikkeloscar/mode-name-spaces (diff)
parentFix borders with floating windows (diff)
downloadsway-4bf10d77713f5ea9fdc05c084a26a5eb1d5bc3c5.tar.gz
sway-4bf10d77713f5ea9fdc05c084a26a5eb1d5bc3c5.tar.zst
sway-4bf10d77713f5ea9fdc05c084a26a5eb1d5bc3c5.zip
Merge pull request #551 from mikkeloscar/window-borders
Implement Window borders
-rw-r--r--include/border.h11
-rw-r--r--include/client/pango.h10
-rw-r--r--include/config.h30
-rw-r--r--include/container.h18
-rw-r--r--sway/CMakeLists.txt6
-rw-r--r--sway/border.c266
-rw-r--r--sway/commands.c111
-rw-r--r--sway/config.c42
-rw-r--r--sway/container.c21
-rw-r--r--sway/focus.c5
-rw-r--r--sway/handlers.c6
-rw-r--r--sway/layout.c116
-rw-r--r--sway/sway.5.txt12
-rw-r--r--swaybar/config.c4
-rw-r--r--swaybar/render.c22
-rw-r--r--wayland/pango.c22
16 files changed, 655 insertions, 47 deletions
diff --git a/include/border.h b/include/border.h
new file mode 100644
index 00000000..85c656e0
--- /dev/null
+++ b/include/border.h
@@ -0,0 +1,11 @@
1#ifndef _SWAY_BORDER_H
2#define _SWAY_BORDER_H
3#include <wlc/wlc.h>
4#include "container.h"
5
6void render_view_borders(wlc_handle view);
7void update_view_border(swayc_t *view);
8void map_update_view_border(swayc_t *view, void *data);
9int get_font_text_height(const char *font);
10
11#endif
diff --git a/include/client/pango.h b/include/client/pango.h
index e25a2211..97c31e38 100644
--- a/include/client/pango.h
+++ b/include/client/pango.h
@@ -1,12 +1,12 @@
1#ifndef _SWAY_CLIENT_PANGO_H 1#ifndef _SWAY_CLIENT_PANGO_H
2#define _SWAY_CLIENT_PANGO_H 2#define _SWAY_CLIENT_PANGO_H
3 3
4#include "client/window.h" 4#include <cairo/cairo.h>
5#include "client/buffer.h" 5#include <pango/pangocairo.h>
6#include <stdarg.h> 6#include <stdarg.h>
7 7
8PangoLayout *get_pango_layout(struct window *window, struct buffer *buffer, const char *text); 8PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, const char *text);
9void get_text_size(struct window *window, int *width, int *height, const char *fmt, ...); 9void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, const char *fmt, ...);
10void pango_printf(struct window *window, const char *fmt, ...); 10void pango_printf(cairo_t *cairo, const char *font, const char *fmt, ...);
11 11
12#endif 12#endif
diff --git a/include/config.h b/include/config.h
index 4bcf55e8..fb84423c 100644
--- a/include/config.h
+++ b/include/config.h
@@ -148,6 +148,21 @@ struct bar_config {
148 } colors; 148 } colors;
149}; 149};
150 150
151struct border_colors {
152 uint32_t border;
153 uint32_t background;
154 uint32_t text;
155 uint32_t indicator;
156 uint32_t child_border;
157};
158
159enum edge_border_types {
160 E_NONE, /**< Don't hide edge borders */
161 E_VERTICAL, /**< hide vertical edge borders */
162 E_HORIZONTAL, /**< hide horizontal edge borders */
163 E_BOTH /**< hide vertical and horizontal edge borders */
164};
165
151/** 166/**
152 * The configuration struct. The result of loading a config file. 167 * The configuration struct. The result of loading a config file.
153 */ 168 */
@@ -169,6 +184,7 @@ struct sway_config {
169 enum swayc_layouts default_orientation; 184 enum swayc_layouts default_orientation;
170 enum swayc_layouts default_layout; 185 enum swayc_layouts default_layout;
171 char *font; 186 char *font;
187 int font_height;
172 188
173 // Flags 189 // Flags
174 bool focus_follows_mouse; 190 bool focus_follows_mouse;
@@ -187,6 +203,20 @@ struct sway_config {
187 203
188 list_t *config_chain; 204 list_t *config_chain;
189 const char *current_config; 205 const char *current_config;
206
207 enum swayc_border_types border;
208 int border_thickness;
209 enum edge_border_types hide_edge_borders;
210
211 // border colors
212 struct {
213 struct border_colors focused;
214 struct border_colors focused_inactive;
215 struct border_colors unfocused;
216 struct border_colors urgent;
217 struct border_colors placeholder;
218 uint32_t background;
219 } border_colors;
190}; 220};
191 221
192/** 222/**
diff --git a/include/container.h b/include/container.h
index a96beab9..26da851e 100644
--- a/include/container.h
+++ b/include/container.h
@@ -8,7 +8,7 @@ typedef struct sway_container swayc_t;
8 8
9/** 9/**
10 * Different kinds of containers. 10 * Different kinds of containers.
11 * 11 *
12 * This enum is in order. A container will never be inside of a container below 12 * This enum is in order. A container will never be inside of a container below
13 * it on this list. 13 * it on this list.
14 */ 14 */
@@ -36,6 +36,12 @@ enum swayc_layouts {
36 L_LAYOUTS, 36 L_LAYOUTS,
37}; 37};
38 38
39enum swayc_border_types {
40 B_NONE, /**< No border */
41 B_PIXEL, /**< 1px border */
42 B_NORMAL /**< Normal border with title bar */
43};
44
39/** 45/**
40 * Stores information about a container. 46 * Stores information about a container.
41 * 47 *
@@ -109,6 +115,16 @@ struct sway_container {
109 * If this container's children include a fullscreen view, this is that view. 115 * If this container's children include a fullscreen view, this is that view.
110 */ 116 */
111 struct sway_container *fullscreen; 117 struct sway_container *fullscreen;
118 /**
119 * If this container is a view, this may be set to the window's decoration
120 * buffer (or NULL).
121 */
122 unsigned char *border;
123 enum swayc_border_types border_type;
124 struct wlc_geometry border_geometry;
125 struct wlc_geometry title_bar_geometry;
126 struct wlc_geometry actual_geometry;
127 int border_thickness;
112}; 128};
113 129
114enum visibility_mask { 130enum visibility_mask {
diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt
index 5b6104f3..51f27a05 100644
--- a/sway/CMakeLists.txt
+++ b/sway/CMakeLists.txt
@@ -5,6 +5,8 @@ include_directories(
5 ${JSONC_INCLUDE_DIRS} 5 ${JSONC_INCLUDE_DIRS}
6 ${XKBCOMMON_INCLUDE_DIRS} 6 ${XKBCOMMON_INCLUDE_DIRS}
7 ${LIBINPUT_INCLUDE_DIRS} 7 ${LIBINPUT_INCLUDE_DIRS}
8 ${CAIRO_INCLUDE_DIRS}
9 ${PANGO_INCLUDE_DIRS}
8) 10)
9 11
10add_executable(sway 12add_executable(sway
@@ -24,6 +26,7 @@ add_executable(sway
24 output.c 26 output.c
25 resize.c 27 resize.c
26 workspace.c 28 workspace.c
29 border.c
27) 30)
28 31
29add_definitions( 32add_definitions(
@@ -33,12 +36,15 @@ add_definitions(
33target_link_libraries(sway 36target_link_libraries(sway
34 sway-common 37 sway-common
35 sway-protocols 38 sway-protocols
39 sway-wayland
36 ${WLC_LIBRARIES} 40 ${WLC_LIBRARIES}
37 ${XKBCOMMON_LIBRARIES} 41 ${XKBCOMMON_LIBRARIES}
38 ${PCRE_LIBRARIES} 42 ${PCRE_LIBRARIES}
39 ${JSONC_LIBRARIES} 43 ${JSONC_LIBRARIES}
40 ${WAYLAND_SERVER_LIBRARIES} 44 ${WAYLAND_SERVER_LIBRARIES}
41 ${LIBINPUT_LIBRARIES} 45 ${LIBINPUT_LIBRARIES}
46 ${PANGO_LIBRARIES}
47 ${JSONC_LIBRARIES}
42 m 48 m
43) 49)
44 50
diff --git a/sway/border.c b/sway/border.c
new file mode 100644
index 00000000..ab4b70f6
--- /dev/null
+++ b/sway/border.c
@@ -0,0 +1,266 @@
1#include "border.h"
2#include <wlc/wlc-render.h>
3#include <cairo/cairo.h>
4#include <pango/pangocairo.h>
5#include <stdlib.h>
6#include <stdio.h>
7#include "container.h"
8#include "config.h"
9#include "client/pango.h"
10
11void cairo_set_source_u32(cairo_t *cairo, uint32_t color) {
12 int endian = 1;
13 if (*(char *)&endian == 1) { // little endian
14 cairo_set_source_rgba(cairo,
15 (color >> (1*8) & 0xFF) / 255.0,
16 (color >> (2*8) & 0xFF) / 255.0,
17 (color >> (3*8) & 0xFF) / 255.0,
18 (color >> (0*8) & 0xFF) / 255.0);
19 } else { // big endian
20 cairo_set_source_rgba(cairo,
21 (color >> (0*8) & 0xFF) / 255.0,
22 (color >> (3*8) & 0xFF) / 255.0,
23 (color >> (2*8) & 0xFF) / 255.0,
24 (color >> (1*8) & 0xFF) / 255.0);
25 }
26}
27
28static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry geo, cairo_surface_t **surface) {
29 cairo_t *cr;
30 view->border_geometry = geo;
31 int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, geo.size.w);
32 view->border = calloc(stride * geo.size.h, sizeof(unsigned char));
33 if (!view->border) {
34 sway_log(L_DEBUG, "Unable to allocate buffer");
35 return NULL;
36 }
37 *surface = cairo_image_surface_create_for_data(view->border,
38 CAIRO_FORMAT_ARGB32, geo.size.w, geo.size.h, stride);
39 if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) {
40 free(view->border);
41 view->border = NULL;
42 sway_log(L_DEBUG, "Unable to allocate surface");
43 return NULL;
44 }
45 cr = cairo_create(*surface);
46 if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) {
47 cairo_surface_destroy(*surface);
48 free(view->border);
49 view->border = NULL;
50 sway_log(L_DEBUG, "Unable to create cairo context");
51 return NULL;
52 }
53 return cr;
54}
55
56// TODO: move to client/cairo.h when local set_source_u32 is fixed.
57/**
58 * Renders a sharp line of any width and height.
59 *
60 * The line is drawn from (x,y) to (x+width,y+height) where width/height is 0
61 * if the line has a width/height of one pixel, respectively.
62 */
63static void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y, double width, double height) {
64 cairo_set_source_u32(cairo, color);
65
66 if (width > 1 && height > 1) {
67 cairo_rectangle(cairo, x, y, width, height);
68 cairo_fill(cairo);
69 } else {
70 if (width == 1) {
71 x += 0.5;
72 height += y;
73 width = x;
74 }
75
76 if (height == 1) {
77 y += 0.5;
78 width += x;
79 height = y;
80 }
81
82 cairo_move_to(cairo, x, y);
83 cairo_set_line_width(cairo, 1.0);
84 cairo_line_to(cairo, width, height);
85 cairo_stroke(cairo);
86 }
87}
88
89int get_font_text_height(const char *font) {
90 cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 200, 200);
91 cairo_t *cr = cairo_create(surface);
92 int width, height;
93 get_text_size(cr, font, &width, &height, "Gg");
94 return height;
95}
96
97static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *colors) {
98 struct wlc_geometry *b = &view->border_geometry;
99 struct wlc_geometry *v = &view->actual_geometry;
100
101 // left border
102 int left_border = v->origin.x - b->origin.x;
103 if (left_border > 0) {
104 render_sharp_line(cr,
105 colors->child_border,
106 0, 0,
107 left_border,
108 b->size.h);
109 }
110
111 // right border
112 int right_border = b->size.w - v->size.w - left_border;
113 if (right_border > 0) {
114 render_sharp_line(cr,
115 colors->child_border,
116 b->size.w - right_border,
117 0,
118 right_border,
119 b->size.h);
120 }
121
122 // top border
123 int top_border = v->origin.y - b->origin.y;
124 if (top_border > 0) {
125 render_sharp_line(cr,
126 colors->child_border,
127 0, 0,
128 b->size.w,
129 top_border);
130 }
131
132 // bottom border
133 int bottom_border = b->size.h - (top_border + v->size.h);
134 if (bottom_border > 0) {
135 render_sharp_line(cr,
136 colors->child_border,
137 0,
138 b->size.h - bottom_border,
139 b->size.w,
140 bottom_border);
141 }
142}
143
144static void render_with_title_bar(swayc_t *view, cairo_t *cr, struct border_colors *colors) {
145 struct wlc_geometry *tb = &view->title_bar_geometry;
146 struct wlc_geometry *b = &view->border_geometry;
147
148 // borders
149 render_borders(view, cr, colors);
150
151 // title bar background
152 cairo_set_source_u32(cr, colors->child_border);
153 cairo_rectangle(cr, 0, 0, tb->size.w, tb->size.h);
154 cairo_fill(cr);
155
156 // header top line
157 render_sharp_line(cr, colors->border, 0, 0, tb->size.w, 1);
158
159 // text
160 if (view->name) {
161 int width, height;
162 get_text_size(cr, config->font, &width, &height, "%s", view->name);
163 cairo_move_to(cr, view->border_thickness, 2);
164 cairo_set_source_u32(cr, colors->text);
165 pango_printf(cr, config->font, "%s", view->name);
166 }
167
168 // header bottom line
169 render_sharp_line(cr, colors->border,
170 view->actual_geometry.origin.x - b->origin.x,
171 tb->size.h - 1,
172 view->actual_geometry.size.w, 1);
173}
174
175void map_update_view_border(swayc_t *view, void *data) {
176 if (view->type == C_VIEW) {
177 update_view_border(view);
178 }
179}
180
181void update_view_border(swayc_t *view) {
182 cairo_t *cr = NULL;
183 cairo_surface_t *surface = NULL;
184
185 if (view->border) {
186 free(view->border);
187 view->border = NULL;
188 }
189
190 swayc_t *focused = get_focused_view(&root_container);
191 swayc_t *container = swayc_parent_by_type(view, C_CONTAINER);
192 swayc_t *focused_inactive = NULL;
193 if (container) {
194 focused_inactive = swayc_focus_by_type(container, C_VIEW);
195 } else {
196 container = swayc_parent_by_type(view, C_WORKSPACE);
197 if (container) {
198 focused_inactive = swayc_focus_by_type(container, C_VIEW);
199 }
200 }
201
202 switch (view->border_type) {
203 case B_NONE:
204 break;
205 case B_PIXEL:
206 cr = create_border_buffer(view, view->border_geometry, &surface);
207 if (!cr) {
208 break;
209 }
210
211 if (focused == view) {
212 render_borders(view, cr, &config->border_colors.focused);
213 } else if (focused_inactive == view) {
214 render_borders(view, cr, &config->border_colors.focused_inactive);
215 } else {
216 render_borders(view, cr, &config->border_colors.unfocused);
217 }
218
219 break;
220 case B_NORMAL:
221 cr = create_border_buffer(view, view->border_geometry, &surface);
222 if (!cr) {
223 break;
224 }
225
226 if (focused == view) {
227 render_with_title_bar(view, cr, &config->border_colors.focused);
228 } else if (focused_inactive == view) {
229 render_with_title_bar(view, cr, &config->border_colors.focused_inactive);
230 } else {
231 render_with_title_bar(view, cr, &config->border_colors.unfocused);
232 }
233
234 break;
235 }
236 if (surface) {
237 cairo_surface_flush(surface);
238 cairo_surface_destroy(surface);
239 }
240 if (cr) {
241 cairo_destroy(cr);
242 }
243}
244
245void render_view_borders(wlc_handle view) {
246 swayc_t *c = swayc_by_handle(view);
247
248 if (!c || c->border_type == B_NONE) {
249 return;
250 }
251
252 if (c->border_type == B_NORMAL) {
253 // update window title
254 const char *new_name = wlc_view_get_title(view);
255
256 if (new_name && strcmp(c->name, new_name) != 0) {
257 free(c->name);
258 c->name = strdup(new_name);
259 update_view_border(c);
260 }
261 }
262
263 if (c->border) {
264 wlc_pixels_write(WLC_RGBA8888, &c->border_geometry, c->border);
265 }
266}
diff --git a/sway/commands.c b/sway/commands.c
index d2be2f9b..c621fa92 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -31,6 +31,7 @@
31#include "ipc-server.h" 31#include "ipc-server.h"
32#include "list.h" 32#include "list.h"
33#include "input.h" 33#include "input.h"
34#include "border.h"
34 35
35typedef struct cmd_results *sway_cmd(int argc, char **argv); 36typedef struct cmd_results *sway_cmd(int argc, char **argv);
36 37
@@ -43,6 +44,7 @@ static sway_cmd cmd_assign;
43static sway_cmd cmd_bar; 44static sway_cmd cmd_bar;
44static sway_cmd cmd_bindcode; 45static sway_cmd cmd_bindcode;
45static sway_cmd cmd_bindsym; 46static sway_cmd cmd_bindsym;
47static sway_cmd cmd_border;
46static sway_cmd cmd_debuglog; 48static sway_cmd cmd_debuglog;
47static sway_cmd cmd_exec; 49static sway_cmd cmd_exec;
48static sway_cmd cmd_exec_always; 50static sway_cmd cmd_exec_always;
@@ -55,6 +57,7 @@ static sway_cmd cmd_font;
55static sway_cmd cmd_for_window; 57static sway_cmd cmd_for_window;
56static sway_cmd cmd_fullscreen; 58static sway_cmd cmd_fullscreen;
57static sway_cmd cmd_gaps; 59static sway_cmd cmd_gaps;
60static sway_cmd cmd_hide_edge_borders;
58static sway_cmd cmd_include; 61static sway_cmd cmd_include;
59static sway_cmd cmd_input; 62static sway_cmd cmd_input;
60static sway_cmd cmd_kill; 63static sway_cmd cmd_kill;
@@ -345,6 +348,71 @@ static struct cmd_results *cmd_bindcode(int argc, char **argv) {
345 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 348 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
346} 349}
347 350
351static struct cmd_results *cmd_border(int argc, char **argv) {
352 struct cmd_results *error = NULL;
353 if ((error = checkarg(argc, "border", EXPECTED_AT_LEAST, 1))) {
354 return error;
355 }
356
357 if (argc > 2) {
358 return cmd_results_new(CMD_FAILURE, "border",
359 "Expected 'border <normal|pixel|none|toggle> [<n>]");
360 }
361
362 enum swayc_border_types border = config->border;
363 int thickness = config->border_thickness;
364
365 swayc_t *view = NULL;
366 if (config->active) {
367 view = get_focused_view(&root_container);
368 border = view->border_type;
369 thickness = view->border_thickness;
370 }
371
372 if (strcasecmp(argv[0], "none") == 0) {
373 border = B_NONE;
374 } else if (strcasecmp(argv[0], "normal") == 0) {
375 border = B_NORMAL;
376 } else if (strcasecmp(argv[0], "pixel") == 0) {
377 border = B_PIXEL;
378 } else if (strcasecmp(argv[0], "toggle") == 0) {
379 switch (border) {
380 case B_NONE:
381 border = B_PIXEL;
382 break;
383 case B_NORMAL:
384 border = B_NONE;
385 break;
386 case B_PIXEL:
387 border = B_NORMAL;
388 break;
389 }
390 } else {
391 return cmd_results_new(CMD_FAILURE, "border",
392 "Expected 'border <normal|pixel|none|toggle>");
393 }
394
395
396 if (argc == 2 && (border == B_NORMAL || border == B_PIXEL)) {
397 thickness = (int)strtol(argv[1], NULL, 10);
398 if (errno == ERANGE || thickness < 0) {
399 errno = 0;
400 return cmd_results_new(CMD_INVALID, "border", "Number is out out of range.");
401 }
402 }
403
404 if (config->active && view) {
405 view->border_type = border;
406 view->border_thickness = thickness;
407 update_geometry(view);
408 } else {
409 config->border = border;
410 config->border_thickness = thickness;
411 }
412
413 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
414}
415
348static struct cmd_results *cmd_exec_always(int argc, char **argv) { 416static struct cmd_results *cmd_exec_always(int argc, char **argv) {
349 struct cmd_results *error = NULL; 417 struct cmd_results *error = NULL;
350 if (!config->active) return cmd_results_new(CMD_DEFER, NULL, NULL); 418 if (!config->active) return cmd_results_new(CMD_DEFER, NULL, NULL);
@@ -847,9 +915,9 @@ static struct cmd_results *cmd_move(int argc, char **argv) {
847 } else if (strcasecmp(argv[0], "position") == 0 && strcasecmp(argv[1], "mouse") == 0) { 915 } else if (strcasecmp(argv[0], "position") == 0 && strcasecmp(argv[1], "mouse") == 0) {
848 if (view->is_floating) { 916 if (view->is_floating) {
849 swayc_t *output = swayc_parent_by_type(view, C_OUTPUT); 917 swayc_t *output = swayc_parent_by_type(view, C_OUTPUT);
850 const struct wlc_geometry *geometry = wlc_view_get_geometry(view->handle); 918 struct wlc_geometry g;
919 wlc_view_get_visible_geometry(view->handle, &g);
851 const struct wlc_size *size = wlc_output_get_resolution(output->handle); 920 const struct wlc_size *size = wlc_output_get_resolution(output->handle);
852 struct wlc_geometry g = *geometry;
853 921
854 struct wlc_point origin; 922 struct wlc_point origin;
855 wlc_pointer_get_position(&origin); 923 wlc_pointer_get_position(&origin);
@@ -1500,6 +1568,29 @@ static struct cmd_results *cmd_smart_gaps(int argc, char **argv) {
1500 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 1568 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1501} 1569}
1502 1570
1571static struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) {
1572 struct cmd_results *error = NULL;
1573 if ((error = checkarg(argc, "hide_edge_borders", EXPECTED_EQUAL_TO, 1))) {
1574 return error;
1575 }
1576
1577 if (strcasecmp(argv[0], "none") == 0) {
1578 config->hide_edge_borders = E_NONE;
1579 } else if (strcasecmp(argv[0], "vertical") == 0) {
1580 config->hide_edge_borders = E_VERTICAL;
1581 } else if (strcasecmp(argv[0], "horizontal") == 0) {
1582 config->hide_edge_borders = E_HORIZONTAL;
1583 } else if (strcasecmp(argv[0], "both") == 0) {
1584 config->hide_edge_borders = E_BOTH;
1585 } else {
1586 return cmd_results_new(CMD_INVALID, "hide_edge_borders",
1587 "Expected 'hide_edge_borders <none|vertical|horizontal|both>'");
1588 }
1589
1590 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1591}
1592
1593
1503static struct cmd_results *cmd_kill(int argc, char **argv) { 1594static struct cmd_results *cmd_kill(int argc, char **argv) {
1504 if (config->reading) return cmd_results_new(CMD_FAILURE, "kill", "Can't be used in config file."); 1595 if (config->reading) return cmd_results_new(CMD_FAILURE, "kill", "Can't be used in config file.");
1505 if (!config->active) return cmd_results_new(CMD_FAILURE, "kill", "Can only be used when sway is running."); 1596 if (!config->active) return cmd_results_new(CMD_FAILURE, "kill", "Can only be used when sway is running.");
@@ -1866,16 +1957,18 @@ static struct cmd_results *cmd_font(int argc, char **argv) {
1866 } 1957 }
1867 1958
1868 char *font = join_args(argv, argc); 1959 char *font = join_args(argv, argc);
1960 free(config->font);
1869 if (strlen(font) > 6 && strncmp("pango:", font, 6) == 0) { 1961 if (strlen(font) > 6 && strncmp("pango:", font, 6) == 0) {
1870 free(config->font); 1962 config->font = strdup(font + 6);
1871 config->font = font;
1872 sway_log(L_DEBUG, "Settings font %s", config->font);
1873 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1874 } else {
1875 free(font); 1963 free(font);
1876 return cmd_results_new(CMD_FAILURE, "font", "non-pango font detected"); 1964 } else {
1965 config->font = font;
1877 } 1966 }
1878 1967
1968 config->font_height = get_font_text_height(config->font);
1969
1970 sway_log(L_DEBUG, "Settings font %s", config->font);
1971 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
1879} 1972}
1880 1973
1881 1974
@@ -2044,6 +2137,7 @@ static struct cmd_handler handlers[] = {
2044 { "bar", cmd_bar }, 2137 { "bar", cmd_bar },
2045 { "bindcode", cmd_bindcode }, 2138 { "bindcode", cmd_bindcode },
2046 { "bindsym", cmd_bindsym }, 2139 { "bindsym", cmd_bindsym },
2140 { "border", cmd_border },
2047 { "debuglog", cmd_debuglog }, 2141 { "debuglog", cmd_debuglog },
2048 { "default_orientation", cmd_orientation }, 2142 { "default_orientation", cmd_orientation },
2049 { "exec", cmd_exec }, 2143 { "exec", cmd_exec },
@@ -2057,6 +2151,7 @@ static struct cmd_handler handlers[] = {
2057 { "for_window", cmd_for_window }, 2151 { "for_window", cmd_for_window },
2058 { "fullscreen", cmd_fullscreen }, 2152 { "fullscreen", cmd_fullscreen },
2059 { "gaps", cmd_gaps }, 2153 { "gaps", cmd_gaps },
2154 { "hide_edge_borders", cmd_hide_edge_borders },
2060 { "include", cmd_include }, 2155 { "include", cmd_include },
2061 { "input", cmd_input }, 2156 { "input", cmd_input },
2062 { "kill", cmd_kill }, 2157 { "kill", cmd_kill },
diff --git a/sway/config.c b/sway/config.c
index a877261c..5501ab31 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -22,6 +22,7 @@
22#include "input_state.h" 22#include "input_state.h"
23#include "criteria.h" 23#include "criteria.h"
24#include "input.h" 24#include "input.h"
25#include "border.h"
25 26
26struct sway_config *config = NULL; 27struct sway_config *config = NULL;
27 28
@@ -160,7 +161,8 @@ static void config_defaults(struct sway_config *config) {
160 config->resizing_key = M_RIGHT_CLICK; 161 config->resizing_key = M_RIGHT_CLICK;
161 config->default_layout = L_NONE; 162 config->default_layout = L_NONE;
162 config->default_orientation = L_NONE; 163 config->default_orientation = L_NONE;
163 config->font = strdup("pango:monospace 10"); 164 config->font = strdup("monospace 10");
165 config->font_height = get_font_text_height(config->font);
164 166
165 // Flags 167 // Flags
166 config->focus_follows_mouse = true; 168 config->focus_follows_mouse = true;
@@ -181,6 +183,44 @@ static void config_defaults(struct sway_config *config) {
181 183
182 config->config_chain = create_list(); 184 config->config_chain = create_list();
183 config->current_config = NULL; 185 config->current_config = NULL;
186
187 // borders
188 config->border = B_NORMAL;
189 config->border_thickness = 2;
190 config->hide_edge_borders = E_NONE;
191
192 // border colors
193 config->border_colors.focused.border = 0x4C7899FF;
194 config->border_colors.focused.background = 0x285577FF;
195 config->border_colors.focused.text = 0xFFFFFFFF;
196 config->border_colors.focused.indicator = 0x2E9EF4FF;
197 config->border_colors.focused.child_border = 0x285577FF;
198
199 config->border_colors.focused_inactive.border = 0x333333FF;
200 config->border_colors.focused_inactive.background = 0x5F676AFF;
201 config->border_colors.focused_inactive.text = 0xFFFFFFFF;
202 config->border_colors.focused_inactive.indicator = 0x484E50FF;
203 config->border_colors.focused_inactive.child_border = 0x5F676AFF;
204
205 config->border_colors.unfocused.border = 0x333333FF;
206 config->border_colors.unfocused.background = 0x222222FF;
207 config->border_colors.unfocused.text = 0x888888FF;
208 config->border_colors.unfocused.indicator = 0x292D2EFF;
209 config->border_colors.unfocused.child_border = 0x222222FF;
210
211 config->border_colors.urgent.border = 0x2F343AFF;
212 config->border_colors.urgent.background = 0x900000FF;
213 config->border_colors.urgent.text = 0xFFFFFFFF;
214 config->border_colors.urgent.indicator = 0x900000FF;
215 config->border_colors.urgent.child_border = 0x900000FF;
216
217 config->border_colors.placeholder.border = 0x000000FF;
218 config->border_colors.placeholder.background = 0x0C0C0CFF;
219 config->border_colors.placeholder.text = 0xFFFFFFFF;
220 config->border_colors.placeholder.indicator = 0x000000FF;
221 config->border_colors.placeholder.child_border = 0x0C0C0CFF;
222
223 config->border_colors.background = 0xFFFFFFFF;
184} 224}
185 225
186static int compare_modifiers(const void *left, const void *right) { 226static int compare_modifiers(const void *left, const void *right) {
diff --git a/sway/container.c b/sway/container.c
index 9330a3de..21a929b9 100644
--- a/sway/container.c
+++ b/sway/container.c
@@ -22,8 +22,11 @@ static swayc_t *new_swayc(enum swayc_types type) {
22 c->gaps = -1; 22 c->gaps = -1;
23 c->layout = L_NONE; 23 c->layout = L_NONE;
24 c->type = type; 24 c->type = type;
25 c->border_type = config->border;
26 c->border_thickness = config->border_thickness;
25 if (type != C_VIEW) { 27 if (type != C_VIEW) {
26 c->children = create_list(); 28 c->children = create_list();
29 c->border_type = B_NONE;
27 } 30 }
28 return c; 31 return c;
29} 32}
@@ -266,11 +269,12 @@ swayc_t *new_view(swayc_t *sibling, wlc_handle handle) {
266 view->is_focused = true; 269 view->is_focused = true;
267 view->sticky = false; 270 view->sticky = false;
268 // Setup geometry 271 // Setup geometry
269 const struct wlc_geometry* geometry = wlc_view_get_geometry(handle); 272 struct wlc_geometry geometry;
273 wlc_view_get_visible_geometry(handle, &geometry);
270 view->width = 0; 274 view->width = 0;
271 view->height = 0; 275 view->height = 0;
272 view->desired_width = geometry->size.w; 276 view->desired_width = geometry.size.w;
273 view->desired_height = geometry->size.h; 277 view->desired_height = geometry.size.h;
274 278
275 view->is_floating = false; 279 view->is_floating = false;
276 280
@@ -303,13 +307,14 @@ swayc_t *new_floating_view(wlc_handle handle) {
303 view->sticky = false; 307 view->sticky = false;
304 308
305 // Set the geometry of the floating view 309 // Set the geometry of the floating view
306 const struct wlc_geometry* geometry = wlc_view_get_geometry(handle); 310 struct wlc_geometry geometry;
311 wlc_view_get_visible_geometry(handle, &geometry);
307 312
308 // give it requested geometry, but place in center 313 // give it requested geometry, but place in center
309 view->x = (swayc_active_workspace()->width - geometry->size.w) / 2; 314 view->x = (swayc_active_workspace()->width - geometry.size.w) / 2;
310 view->y = (swayc_active_workspace()->height- geometry->size.h) / 2; 315 view->y = (swayc_active_workspace()->height- geometry.size.h) / 2;
311 view->width = geometry->size.w; 316 view->width = geometry.size.w;
312 view->height = geometry->size.h; 317 view->height = geometry.size.h;
313 318
314 view->desired_width = view->width; 319 view->desired_width = view->width;
315 view->desired_height = view->height; 320 view->desired_height = view->height;
diff --git a/sway/focus.c b/sway/focus.c
index 7f96eda7..0c9719b0 100644
--- a/sway/focus.c
+++ b/sway/focus.c
@@ -7,6 +7,7 @@
7#include "config.h" 7#include "config.h"
8#include "input_state.h" 8#include "input_state.h"
9#include "ipc-server.h" 9#include "ipc-server.h"
10#include "border.h"
10 11
11bool locked_container_focus = false; 12bool locked_container_focus = false;
12bool locked_view_focus = false; 13bool locked_view_focus = false;
@@ -28,6 +29,8 @@ static void update_focus(swayc_t *c) {
28 29
29 // Case where output changes 30 // Case where output changes
30 case C_OUTPUT: 31 case C_OUTPUT:
32 // update borders for views in prev
33 container_map(prev, map_update_view_border, NULL);
31 wlc_output_focus(c->handle); 34 wlc_output_focus(c->handle);
32 break; 35 break;
33 36
@@ -130,6 +133,7 @@ bool set_focused_container(swayc_t *c) {
130 // unactivate previous focus 133 // unactivate previous focus
131 if (focused->type == C_VIEW) { 134 if (focused->type == C_VIEW) {
132 wlc_view_set_state(focused->handle, WLC_BIT_ACTIVATED, false); 135 wlc_view_set_state(focused->handle, WLC_BIT_ACTIVATED, false);
136 update_view_border(focused);
133 } 137 }
134 // activate current focus 138 // activate current focus
135 if (p->type == C_VIEW) { 139 if (p->type == C_VIEW) {
@@ -137,6 +141,7 @@ bool set_focused_container(swayc_t *c) {
137 // set focus if view_focus is unlocked 141 // set focus if view_focus is unlocked
138 if (!locked_view_focus) { 142 if (!locked_view_focus) {
139 wlc_view_focus(p->handle); 143 wlc_view_focus(p->handle);
144 update_view_border(p);
140 } 145 }
141 } 146 }
142 } else if (p->type == C_WORKSPACE) { 147 } else if (p->type == C_WORKSPACE) {
diff --git a/sway/handlers.c b/sway/handlers.c
index 7d4ea263..54326dd0 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -9,6 +9,7 @@
9#include <ctype.h> 9#include <ctype.h>
10 10
11#include "handlers.h" 11#include "handlers.h"
12#include "border.h"
12#include "log.h" 13#include "log.h"
13#include "layout.h" 14#include "layout.h"
14#include "config.h" 15#include "config.h"
@@ -150,6 +151,10 @@ static void handle_output_post_render(wlc_handle output) {
150 ipc_get_pixels(output); 151 ipc_get_pixels(output);
151} 152}
152 153
154static void handle_view_pre_render(wlc_handle view) {
155 render_view_borders(view);
156}
157
153static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) { 158static void handle_output_resolution_change(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to) {
154 sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h); 159 sway_log(L_DEBUG, "Output %u resolution changed to %d x %d", (unsigned int)output, to->w, to->h);
155 swayc_t *c = swayc_by_handle(output); 160 swayc_t *c = swayc_by_handle(output);
@@ -716,6 +721,7 @@ void register_wlc_handlers() {
716 wlc_set_view_created_cb(handle_view_created); 721 wlc_set_view_created_cb(handle_view_created);
717 wlc_set_view_destroyed_cb(handle_view_destroyed); 722 wlc_set_view_destroyed_cb(handle_view_destroyed);
718 wlc_set_view_focus_cb(handle_view_focus); 723 wlc_set_view_focus_cb(handle_view_focus);
724 wlc_set_view_render_pre_cb(handle_view_pre_render);
719 wlc_set_view_request_geometry_cb(handle_view_geometry_request); 725 wlc_set_view_request_geometry_cb(handle_view_geometry_request);
720 wlc_set_view_request_state_cb(handle_view_state_request); 726 wlc_set_view_request_state_cb(handle_view_state_request);
721 wlc_set_keyboard_key_cb(handle_key); 727 wlc_set_keyboard_key_cb(handle_key);
diff --git a/sway/layout.c b/sway/layout.c
index d9c4598f..3f271caf 100644
--- a/sway/layout.c
+++ b/sway/layout.c
@@ -12,6 +12,7 @@
12#include "focus.h" 12#include "focus.h"
13#include "output.h" 13#include "output.h"
14#include "ipc-server.h" 14#include "ipc-server.h"
15#include "border.h"
15 16
16swayc_t root_container; 17swayc_t root_container;
17list_t *scratchpad; 18list_t *scratchpad;
@@ -373,6 +374,46 @@ void move_workspace_to(swayc_t* workspace, swayc_t* destination) {
373 update_visibility(src_op); 374 update_visibility(src_op);
374} 375}
375 376
377static void update_border_geometry_floating(swayc_t *c, struct wlc_geometry *geometry) {
378 struct wlc_geometry g = *geometry;
379 c->actual_geometry = g;
380
381 switch (c->border_type) {
382 case B_NONE:
383 break;
384 case B_PIXEL:
385 g.origin.x -= c->border_thickness;
386 g.origin.y -= c->border_thickness;
387 g.size.w += (c->border_thickness * 2);
388 g.size.h += (c->border_thickness * 2);
389 break;
390 case B_NORMAL:
391 g.origin.x -= c->border_thickness;
392 uint32_t title_bar_height = config->font_height + 4; // borders + padding
393 g.origin.y -= title_bar_height;
394 g.size.w += (c->border_thickness * 2);
395 g.size.h += (c->border_thickness + title_bar_height);
396
397 struct wlc_geometry title_bar = {
398 .origin = {
399 .x = g.origin.x,
400 .y = g.origin.y
401 },
402 .size = {
403 .w = g.size.w,
404 .h = title_bar_height
405 }
406 };
407 c->title_bar_geometry = title_bar;
408 break;
409 }
410
411 c->border_geometry = g;
412 *geometry = c->actual_geometry;
413
414 update_view_border(c);
415}
416
376void update_geometry(swayc_t *container) { 417void update_geometry(swayc_t *container) {
377 if (container->type != C_VIEW) { 418 if (container->type != C_VIEW) {
378 return; 419 return;
@@ -426,6 +467,81 @@ void update_geometry(swayc_t *container) {
426 geometry.size.h = ws->y + ws->height - geometry.origin.y; 467 geometry.size.h = ws->y + ws->height - geometry.origin.y;
427 } 468 }
428 } 469 }
470
471 if (swayc_is_fullscreen(container)) {
472 container->border_geometry = (const struct wlc_geometry){0};
473 container->title_bar_geometry = (const struct wlc_geometry){0};
474 } else if (container->is_floating) { // allocate border for floating window
475 update_border_geometry_floating(container, &geometry);
476 } else if (!container->is_floating) { // allocate border for titled window
477 container->border_geometry = geometry;
478
479 int border_top = container->border_thickness;
480 int border_bottom = container->border_thickness;
481 int border_left = container->border_thickness;
482 int border_right = container->border_thickness;
483
484 // handle hide_edge_borders
485 if (config->hide_edge_borders != E_NONE && gap <= 0) {
486 swayc_t *output = swayc_parent_by_type(container, C_OUTPUT);
487 const struct wlc_size *size = wlc_output_get_resolution(output->handle);
488
489 if (config->hide_edge_borders == E_HORIZONTAL || config->hide_edge_borders == E_BOTH) {
490 if (geometry.origin.x == 0) {
491 border_left = 0;
492 }
493
494 if (geometry.origin.x + geometry.size.w == size->w) {
495 border_right = 0;
496 }
497 }
498
499 if (config->hide_edge_borders == E_VERTICAL || config->hide_edge_borders == E_BOTH) {
500 if (geometry.origin.y == 0) {
501 border_top = 0;
502 }
503
504 if (geometry.origin.y + geometry.size.h == size->h) {
505 border_bottom = 0;
506 }
507 }
508 }
509
510 switch (container->border_type) {
511 case B_NONE:
512 break;
513 case B_PIXEL:
514 geometry.origin.x += border_left;
515 geometry.origin.y += border_top;
516 geometry.size.w -= (border_left + border_right);
517 geometry.size.h -= (border_top + border_bottom);
518 break;
519 case B_NORMAL:
520 {
521 struct wlc_geometry title_bar = {
522 .origin = {
523 .x = container->border_geometry.origin.x,
524 .y = container->border_geometry.origin.y
525 },
526 .size = {
527 .w = container->border_geometry.size.w,
528 .h = config->font_height + 4 // borders + padding
529 }
530 };
531 geometry.origin.x += border_left;
532 geometry.origin.y += title_bar.size.h;
533 geometry.size.w -= (border_left + border_right);
534 geometry.size.h -= (border_bottom + title_bar.size.h);
535 container->title_bar_geometry = title_bar;
536 break;
537 }
538 }
539
540 container->actual_geometry = geometry;
541
542 update_view_border(container);
543 }
544
429 wlc_view_set_geometry(container->handle, 0, &geometry); 545 wlc_view_set_geometry(container->handle, 0, &geometry);
430} 546}
431 547
diff --git a/sway/sway.5.txt b/sway/sway.5.txt
index 1bb5cd3b..2eb0276c 100644
--- a/sway/sway.5.txt
+++ b/sway/sway.5.txt
@@ -43,6 +43,15 @@ The following commands may only be used in the configuration file.
43The following commands cannot be used directly in the configuration file. 43The following commands cannot be used directly in the configuration file.
44They are expected to be used with **bindsym** or at runtime through **swaymsg**(1). 44They are expected to be used with **bindsym** or at runtime through **swaymsg**(1).
45 45
46**border** <normal|pixel> [<n>]::
47 Set border style for windows. _normal_ includes a border of thickness _n_ and
48 a title bar. _pixel_ is just the border without title bar. Default is _normal_
49 with border thickness 2.
50
51**border** <none|toggle>::
52 Set border style to _none_ or _toggle_ between the available border styles:
53 _normal_, _pixel_, _none_.
54
46**exit**:: 55**exit**::
47 Exit sway and end your Wayland session. 56 Exit sway and end your Wayland session.
48 57
@@ -67,6 +76,9 @@ They are expected to be used with **bindsym** or at runtime through **swaymsg**(
67**fullscreen**:: 76**fullscreen**::
68 Toggles fullscreen status for the focused view. 77 Toggles fullscreen status for the focused view.
69 78
79**hide_edge_borders** <none|vertical|horizontal|both>::
80 Hide window borders adjacent to the screen edges. Default is _none_.
81
70**layout** <mode>:: 82**layout** <mode>::
71 Sets the layout mode of the focused container. _mode_ can be one of _splith_, 83 Sets the layout mode of the focused container. _mode_ can be one of _splith_,
72 _splitv_, or _toggle split_. 84 _splitv_, or _toggle split_.
diff --git a/swaybar/config.c b/swaybar/config.c
index fddea791..6b9ff86b 100644
--- a/swaybar/config.c
+++ b/swaybar/config.c
@@ -35,9 +35,11 @@ uint32_t parse_position(const char *position) {
35char *parse_font(const char *font) { 35char *parse_font(const char *font) {
36 char *new_font = NULL; 36 char *new_font = NULL;
37 if (strncmp("pango:", font, 6) == 0) { 37 if (strncmp("pango:", font, 6) == 0) {
38 new_font = strdup(font + 6); 38 font += 6;
39 } 39 }
40 40
41 new_font = strdup(font);
42
41 return new_font; 43 return new_font;
42} 44}
43 45
diff --git a/swaybar/render.c b/swaybar/render.c
index 1573a373..fff47ab0 100644
--- a/swaybar/render.c
+++ b/swaybar/render.c
@@ -50,7 +50,7 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y
50 50
51static void render_block(struct window *window, struct config *config, struct status_block *block, double *x, bool edge) { 51static void render_block(struct window *window, struct config *config, struct status_block *block, double *x, bool edge) {
52 int width, height, sep_width; 52 int width, height, sep_width;
53 get_text_size(window, &width, &height, "%s", block->full_text); 53 get_text_size(window->cairo, window->font, &width, &height, "%s", block->full_text);
54 54
55 int textwidth = width; 55 int textwidth = width;
56 double block_width = width; 56 double block_width = width;
@@ -74,7 +74,7 @@ static void render_block(struct window *window, struct config *config, struct st
74 // Add separator 74 // Add separator
75 if (!edge) { 75 if (!edge) {
76 if (config->sep_symbol) { 76 if (config->sep_symbol) {
77 get_text_size(window, &sep_width, &height, "%s", config->sep_symbol); 77 get_text_size(window->cairo, window->font, &sep_width, &height, "%s", config->sep_symbol);
78 if (sep_width > block->separator_block_width) { 78 if (sep_width > block->separator_block_width) {
79 block->separator_block_width = sep_width + margin * 2; 79 block->separator_block_width = sep_width + margin * 2;
80 } 80 }
@@ -136,7 +136,7 @@ static void render_block(struct window *window, struct config *config, struct st
136 136
137 cairo_move_to(window->cairo, offset, margin); 137 cairo_move_to(window->cairo, offset, margin);
138 cairo_set_source_u32(window->cairo, block->color); 138 cairo_set_source_u32(window->cairo, block->color);
139 pango_printf(window, "%s", block->full_text); 139 pango_printf(window->cairo, window->font, "%s", block->full_text);
140 140
141 pos += width; 141 pos += width;
142 142
@@ -159,7 +159,7 @@ static void render_block(struct window *window, struct config *config, struct st
159 if (config->sep_symbol) { 159 if (config->sep_symbol) {
160 offset = pos + (block->separator_block_width - sep_width) / 2; 160 offset = pos + (block->separator_block_width - sep_width) / 2;
161 cairo_move_to(window->cairo, offset, margin); 161 cairo_move_to(window->cairo, offset, margin);
162 pango_printf(window, "%s", config->sep_symbol); 162 pango_printf(window->cairo, window->font, "%s", config->sep_symbol);
163 } else { 163 } else {
164 cairo_set_line_width(window->cairo, 1); 164 cairo_set_line_width(window->cairo, 1);
165 cairo_move_to(window->cairo, pos + block->separator_block_width/2, 165 cairo_move_to(window->cairo, pos + block->separator_block_width/2,
@@ -201,7 +201,7 @@ static void render_workspace_button(struct window *window, struct config *config
201 char *name = handle_workspace_number(config->strip_workspace_numbers, ws->name); 201 char *name = handle_workspace_number(config->strip_workspace_numbers, ws->name);
202 202
203 int width, height; 203 int width, height;
204 get_text_size(window, &width, &height, "%s", name); 204 get_text_size(window->cairo, window->font, &width, &height, "%s", name);
205 struct box_colors box_colors; 205 struct box_colors box_colors;
206 if (ws->urgent) { 206 if (ws->urgent) {
207 box_colors = config->colors.urgent_workspace; 207 box_colors = config->colors.urgent_workspace;
@@ -228,7 +228,7 @@ static void render_workspace_button(struct window *window, struct config *config
228 // text 228 // text
229 cairo_set_source_u32(window->cairo, box_colors.text); 229 cairo_set_source_u32(window->cairo, box_colors.text);
230 cairo_move_to(window->cairo, (int)*x + ws_horizontal_padding, margin); 230 cairo_move_to(window->cairo, (int)*x + ws_horizontal_padding, margin);
231 pango_printf(window, "%s", name); 231 pango_printf(window->cairo, window->font, "%s", name);
232 232
233 *x += width + ws_horizontal_padding * 2 + ws_spacing; 233 *x += width + ws_horizontal_padding * 2 + ws_spacing;
234 234
@@ -237,7 +237,7 @@ static void render_workspace_button(struct window *window, struct config *config
237 237
238static void render_binding_mode_indicator(struct window *window, struct config *config, double pos) { 238static void render_binding_mode_indicator(struct window *window, struct config *config, double pos) {
239 int width, height; 239 int width, height;
240 get_text_size(window, &width, &height, "%s", config->mode); 240 get_text_size(window->cairo, window->font, &width, &height, "%s", config->mode);
241 241
242 // background 242 // background
243 cairo_set_source_u32(window->cairo, config->colors.binding_mode.background); 243 cairo_set_source_u32(window->cairo, config->colors.binding_mode.background);
@@ -254,7 +254,7 @@ static void render_binding_mode_indicator(struct window *window, struct config *
254 // text 254 // text
255 cairo_set_source_u32(window->cairo, config->colors.binding_mode.text); 255 cairo_set_source_u32(window->cairo, config->colors.binding_mode.text);
256 cairo_move_to(window->cairo, (int)pos + ws_horizontal_padding, margin); 256 cairo_move_to(window->cairo, (int)pos + ws_horizontal_padding, margin);
257 pango_printf(window, "%s", config->mode); 257 pango_printf(window->cairo, window->font, "%s", config->mode);
258} 258}
259 259
260void render(struct output *output, struct config *config, struct status_line *line) { 260void render(struct output *output, struct config *config, struct status_line *line) {
@@ -278,9 +278,9 @@ void render(struct output *output, struct config *config, struct status_line *li
278 int width, height; 278 int width, height;
279 279
280 if (line->protocol == TEXT) { 280 if (line->protocol == TEXT) {
281 get_text_size(window, &width, &height, "%s", line->text_line); 281 get_text_size(window->cairo, window->font, &width, &height, "%s", line->text_line);
282 cairo_move_to(cairo, window->width - margin - width, margin); 282 cairo_move_to(cairo, window->width - margin - width, margin);
283 pango_printf(window, "%s", line->text_line); 283 pango_printf(window->cairo, window->font, "%s", line->text_line);
284 } else if (line->protocol == I3BAR && line->block_line) { 284 } else if (line->protocol == I3BAR && line->block_line) {
285 double pos = window->width - 0.5; 285 double pos = window->width - 0.5;
286 bool edge = true; 286 bool edge = true;
@@ -312,7 +312,7 @@ void render(struct output *output, struct config *config, struct status_line *li
312 312
313void set_window_height(struct window *window, int height) { 313void set_window_height(struct window *window, int height) {
314 int text_width, text_height; 314 int text_width, text_height;
315 get_text_size(window, &text_width, &text_height, "Test string for measuring purposes"); 315 get_text_size(window->cairo, window->font, &text_width, &text_height, "Test string for measuring purposes");
316 if (height > 0) { 316 if (height > 0) {
317 margin = (height - text_height) / 2; 317 margin = (height - text_height) / 2;
318 ws_vertical_padding = margin - 1.5; 318 ws_vertical_padding = margin - 1.5;
diff --git a/wayland/pango.c b/wayland/pango.c
index 9766be6a..d79d89b3 100644
--- a/wayland/pango.c
+++ b/wayland/pango.c
@@ -4,21 +4,19 @@
4#include <stdlib.h> 4#include <stdlib.h>
5#include <string.h> 5#include <string.h>
6#include <stdio.h> 6#include <stdio.h>
7#include "client/window.h"
8#include "client/buffer.h"
9#include "log.h" 7#include "log.h"
10 8
11PangoLayout *get_pango_layout(struct window *window, const char *text) { 9PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, const char *text) {
12 PangoLayout *layout = pango_cairo_create_layout(window->cairo); 10 PangoLayout *layout = pango_cairo_create_layout(cairo);
13 pango_layout_set_text(layout, text, -1); 11 pango_layout_set_text(layout, text, -1);
14 PangoFontDescription *desc = pango_font_description_from_string(window->font); 12 PangoFontDescription *desc = pango_font_description_from_string(font);
15 pango_layout_set_font_description(layout, desc); 13 pango_layout_set_font_description(layout, desc);
16 pango_layout_set_single_paragraph_mode(layout, 1); 14 pango_layout_set_single_paragraph_mode(layout, 1);
17 pango_font_description_free(desc); 15 pango_font_description_free(desc);
18 return layout; 16 return layout;
19} 17}
20 18
21void get_text_size(struct window *window, int *width, int *height, const char *fmt, ...) { 19void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, const char *fmt, ...) {
22 char *buf = malloc(2048); 20 char *buf = malloc(2048);
23 21
24 va_list args; 22 va_list args;
@@ -28,8 +26,8 @@ void get_text_size(struct window *window, int *width, int *height, const char *f
28 } 26 }
29 va_end(args); 27 va_end(args);
30 28
31 PangoLayout *layout = get_pango_layout(window, buf); 29 PangoLayout *layout = get_pango_layout(cairo, font, buf);
32 pango_cairo_update_layout(window->cairo, layout); 30 pango_cairo_update_layout(cairo, layout);
33 31
34 pango_layout_get_pixel_size(layout, width, height); 32 pango_layout_get_pixel_size(layout, width, height);
35 33
@@ -38,7 +36,7 @@ void get_text_size(struct window *window, int *width, int *height, const char *f
38 free(buf); 36 free(buf);
39} 37}
40 38
41void pango_printf(struct window *window, const char *fmt, ...) { 39void pango_printf(cairo_t *cairo, const char *font, const char *fmt, ...) {
42 char *buf = malloc(2048); 40 char *buf = malloc(2048);
43 41
44 va_list args; 42 va_list args;
@@ -48,10 +46,10 @@ void pango_printf(struct window *window, const char *fmt, ...) {
48 } 46 }
49 va_end(args); 47 va_end(args);
50 48
51 PangoLayout *layout = get_pango_layout(window, buf); 49 PangoLayout *layout = get_pango_layout(cairo, font, buf);
52 pango_cairo_update_layout(window->cairo, layout); 50 pango_cairo_update_layout(cairo, layout);
53 51
54 pango_cairo_show_layout(window->cairo, layout); 52 pango_cairo_show_layout(cairo, layout);
55 53
56 g_object_unref(layout); 54 g_object_unref(layout);
57 55