diff options
author | Drew DeVault <sir@cmpwn.com> | 2018-03-28 23:04:20 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2018-03-29 22:11:08 -0400 |
commit | cab1352801b62d1b8a12ca1c995cb24445ce4bc9 (patch) | |
tree | bc67373916c06d48700c4f69b8c2470a2f86887f /swaybar/render.c | |
parent | Allow sway IPC clients to fall back to i3 socket (diff) | |
download | sway-cab1352801b62d1b8a12ca1c995cb24445ce4bc9.tar.gz sway-cab1352801b62d1b8a12ca1c995cb24445ce4bc9.tar.zst sway-cab1352801b62d1b8a12ca1c995cb24445ce4bc9.zip |
Start port of swaybar to layer shell
This starts up the event loop and wayland display and shims out the
basic top level rendering concepts. Also includes some changes to
incorporate pango into the 1.x codebase properly.
Diffstat (limited to 'swaybar/render.c')
-rw-r--r-- | swaybar/render.c | 388 |
1 files changed, 42 insertions, 346 deletions
diff --git a/swaybar/render.c b/swaybar/render.c index 6fc09078..2eaa0195 100644 --- a/swaybar/render.c +++ b/swaybar/render.c | |||
@@ -1,367 +1,63 @@ | |||
1 | #include <stdlib.h> | 1 | #include <stdlib.h> |
2 | #include <stdint.h> | 2 | #include <stdint.h> |
3 | #include <string.h> | 3 | #include <string.h> |
4 | 4 | #include <wlr/util/log.h> | |
5 | #include "client/cairo.h" | 5 | #include "cairo.h" |
6 | #include "client/pango.h" | 6 | #include "pango.h" |
7 | #include "client/window.h" | 7 | #include "pool-buffer.h" |
8 | #include "swaybar/bar.h" | ||
8 | #include "swaybar/config.h" | 9 | #include "swaybar/config.h" |
9 | #include "swaybar/status_line.h" | ||
10 | #include "swaybar/render.h" | 10 | #include "swaybar/render.h" |
11 | #ifdef ENABLE_TRAY | 11 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" |
12 | #include "swaybar/tray/tray.h" | ||
13 | #include "swaybar/tray/sni.h" | ||
14 | #endif | ||
15 | #include "log.h" | ||
16 | |||
17 | |||
18 | /* internal spacing */ | ||
19 | static int margin = 3; | ||
20 | static int ws_horizontal_padding = 5; | ||
21 | static double ws_vertical_padding = 1.5; | ||
22 | static int ws_spacing = 1; | ||
23 | |||
24 | /** | ||
25 | * Renders a sharp line of any width and height. | ||
26 | * | ||
27 | * The line is drawn from (x,y) to (x+width,y+height) where width/height is 0 | ||
28 | * if the line has a width/height of one pixel, respectively. | ||
29 | */ | ||
30 | static void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y, double width, double height) { | ||
31 | cairo_set_source_u32(cairo, color); | ||
32 | |||
33 | if (width > 1 && height > 1) { | ||
34 | cairo_rectangle(cairo, x, y, width, height); | ||
35 | cairo_fill(cairo); | ||
36 | } else { | ||
37 | if (width == 1) { | ||
38 | x += 0.5; | ||
39 | height += y; | ||
40 | width = x; | ||
41 | } | ||
42 | |||
43 | if (height == 1) { | ||
44 | y += 0.5; | ||
45 | width += x; | ||
46 | height = y; | ||
47 | } | ||
48 | |||
49 | cairo_move_to(cairo, x, y); | ||
50 | cairo_set_line_width(cairo, 1.0); | ||
51 | cairo_line_to(cairo, width, height); | ||
52 | cairo_stroke(cairo); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | static void render_block(struct window *window, struct config *config, struct status_block *block, double *x, bool edge, bool is_focused) { | ||
57 | int width, height, sep_width; | ||
58 | get_text_size(window->cairo, window->font, &width, &height, | ||
59 | window->scale, block->markup, "%s", block->full_text); | ||
60 | |||
61 | int textwidth = width; | ||
62 | double block_width = width; | ||
63 | |||
64 | if (width < block->min_width) { | ||
65 | width = block->min_width; | ||
66 | } | ||
67 | |||
68 | *x -= width; | ||
69 | |||
70 | if (block->border != 0 && block->border_left > 0) { | ||
71 | *x -= (block->border_left + margin); | ||
72 | block_width += block->border_left + margin; | ||
73 | } | ||
74 | |||
75 | if (block->border != 0 && block->border_right > 0) { | ||
76 | *x -= (block->border_right + margin); | ||
77 | block_width += block->border_right + margin; | ||
78 | } | ||
79 | |||
80 | // Add separator | ||
81 | if (!edge) { | ||
82 | if (config->sep_symbol) { | ||
83 | get_text_size(window->cairo, window->font, &sep_width, &height, | ||
84 | window->scale, false, "%s", config->sep_symbol); | ||
85 | if (sep_width > block->separator_block_width) { | ||
86 | block->separator_block_width = sep_width + margin * 2; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | *x -= block->separator_block_width; | ||
91 | } else { | ||
92 | *x -= margin; | ||
93 | } | ||
94 | |||
95 | double pos = *x; | ||
96 | |||
97 | block->x = (int)pos; | ||
98 | block->width = (int)block_width; | ||
99 | |||
100 | // render background | ||
101 | if (block->background != 0x0) { | ||
102 | cairo_set_source_u32(window->cairo, block->background); | ||
103 | cairo_rectangle(window->cairo, pos - 0.5, 1, block_width, (window->height * window->scale) - 2); | ||
104 | cairo_fill(window->cairo); | ||
105 | } | ||
106 | |||
107 | // render top border | ||
108 | if (block->border != 0 && block->border_top > 0) { | ||
109 | render_sharp_line(window->cairo, block->border, | ||
110 | pos - 0.5, | ||
111 | 1, | ||
112 | block_width, | ||
113 | block->border_top); | ||
114 | } | ||
115 | |||
116 | // render bottom border | ||
117 | if (block->border != 0 && block->border_bottom > 0) { | ||
118 | render_sharp_line(window->cairo, block->border, | ||
119 | pos - 0.5, | ||
120 | (window->height * window->scale) - 1 - block->border_bottom, | ||
121 | block_width, | ||
122 | block->border_bottom); | ||
123 | } | ||
124 | |||
125 | // render left border | ||
126 | if (block->border != 0 && block->border_left > 0) { | ||
127 | render_sharp_line(window->cairo, block->border, | ||
128 | pos - 0.5, | ||
129 | 1, | ||
130 | block->border_left, | ||
131 | (window->height * window->scale) - 2); | ||
132 | |||
133 | pos += block->border_left + margin; | ||
134 | } | ||
135 | |||
136 | // render text | ||
137 | double offset = 0; | ||
138 | |||
139 | if (strncmp(block->align, "left", 5) == 0) { | ||
140 | offset = pos; | ||
141 | } else if (strncmp(block->align, "right", 5) == 0) { | ||
142 | offset = pos + width - textwidth; | ||
143 | } else if (strncmp(block->align, "center", 6) == 0) { | ||
144 | offset = pos + (width - textwidth) / 2; | ||
145 | } | ||
146 | |||
147 | cairo_move_to(window->cairo, offset, margin); | ||
148 | cairo_set_source_u32(window->cairo, block->color); | ||
149 | pango_printf(window->cairo, window->font, window->scale, | ||
150 | block->markup, "%s", block->full_text); | ||
151 | |||
152 | pos += width; | ||
153 | 12 | ||
154 | // render right border | 13 | static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar *bar, |
155 | if (block->border != 0 && block->border_right > 0) { | 14 | struct swaybar_output *output) { |
156 | pos += margin; | 15 | struct swaybar_config *config = bar->config; |
157 | |||
158 | render_sharp_line(window->cairo, block->border, | ||
159 | pos - 0.5, | ||
160 | 1, | ||
161 | block->border_right, | ||
162 | (window->height * window->scale) - 2); | ||
163 | |||
164 | pos += block->border_right; | ||
165 | } | ||
166 | |||
167 | // render separator | ||
168 | if (!edge && block->separator) { | ||
169 | if (is_focused) { | ||
170 | cairo_set_source_u32(window->cairo, config->colors.focused_separator); | ||
171 | } else { | ||
172 | cairo_set_source_u32(window->cairo, config->colors.separator); | ||
173 | } | ||
174 | if (config->sep_symbol) { | ||
175 | offset = pos + (block->separator_block_width - sep_width) / 2; | ||
176 | cairo_move_to(window->cairo, offset, margin); | ||
177 | pango_printf(window->cairo, window->font, window->scale, | ||
178 | false, "%s", config->sep_symbol); | ||
179 | } else { | ||
180 | cairo_set_line_width(window->cairo, 1); | ||
181 | cairo_move_to(window->cairo, pos + block->separator_block_width/2, | ||
182 | margin); | ||
183 | cairo_line_to(window->cairo, pos + block->separator_block_width/2, | ||
184 | (window->height * window->scale) - margin); | ||
185 | cairo_stroke(window->cairo); | ||
186 | } | ||
187 | } | ||
188 | 16 | ||
189 | } | ||
190 | |||
191 | static const char *strip_workspace_name(bool strip_num, const char *ws_name) { | ||
192 | bool strip = false; | ||
193 | int i; | ||
194 | |||
195 | if (strip_num) { | ||
196 | int len = strlen(ws_name); | ||
197 | for (i = 0; i < len; ++i) { | ||
198 | if (!('0' <= ws_name[i] && ws_name[i] <= '9')) { | ||
199 | if (':' == ws_name[i] && i < len-1 && i > 0) { | ||
200 | strip = true; | ||
201 | ++i; | ||
202 | } | ||
203 | break; | ||
204 | } | ||
205 | } | ||
206 | } | ||
207 | |||
208 | if (strip) { | ||
209 | return ws_name + i; | ||
210 | } | ||
211 | |||
212 | return ws_name; | ||
213 | } | ||
214 | |||
215 | void workspace_button_size(struct window *window, const char *workspace_name, int *width, int *height) { | ||
216 | const char *stripped_name = strip_workspace_name(swaybar.config->strip_workspace_numbers, workspace_name); | ||
217 | |||
218 | get_text_size(window->cairo, window->font, width, height, | ||
219 | window->scale, true, "%s", stripped_name); | ||
220 | *width += 2 * ws_horizontal_padding; | ||
221 | *height += 2 * ws_vertical_padding; | ||
222 | } | ||
223 | |||
224 | static void render_workspace_button(struct window *window, struct config *config, struct workspace *ws, double *x) { | ||
225 | const char *stripped_name = strip_workspace_name(config->strip_workspace_numbers, ws->name); | ||
226 | |||
227 | struct box_colors box_colors; | ||
228 | if (ws->urgent) { | ||
229 | box_colors = config->colors.urgent_workspace; | ||
230 | } else if (ws->focused) { | ||
231 | box_colors = config->colors.focused_workspace; | ||
232 | } else if (ws->visible) { | ||
233 | box_colors = config->colors.active_workspace; | ||
234 | } else { | ||
235 | box_colors = config->colors.inactive_workspace; | ||
236 | } | ||
237 | |||
238 | int width, height; | ||
239 | workspace_button_size(window, stripped_name, &width, &height); | ||
240 | |||
241 | // background | ||
242 | cairo_set_source_u32(window->cairo, box_colors.background); | ||
243 | cairo_rectangle(window->cairo, *x, 1.5, width - 1, height); | ||
244 | cairo_fill(window->cairo); | ||
245 | |||
246 | // border | ||
247 | cairo_set_source_u32(window->cairo, box_colors.border); | ||
248 | cairo_rectangle(window->cairo, *x, 1.5, width - 1, height); | ||
249 | cairo_stroke(window->cairo); | ||
250 | |||
251 | // text | ||
252 | cairo_set_source_u32(window->cairo, box_colors.text); | ||
253 | cairo_move_to(window->cairo, (int)*x + ws_horizontal_padding, margin); | ||
254 | pango_printf(window->cairo, window->font, window->scale, | ||
255 | true, "%s", stripped_name); | ||
256 | |||
257 | *x += width + ws_spacing; | ||
258 | } | ||
259 | |||
260 | static void render_binding_mode_indicator(struct window *window, struct config *config, double pos) { | ||
261 | int width, height; | ||
262 | get_text_size(window->cairo, window->font, &width, &height, | ||
263 | window->scale, false, "%s", config->mode); | ||
264 | |||
265 | // background | ||
266 | cairo_set_source_u32(window->cairo, config->colors.binding_mode.background); | ||
267 | cairo_rectangle(window->cairo, pos, 1.5, width + ws_horizontal_padding * 2 - 1, | ||
268 | height + ws_vertical_padding * 2); | ||
269 | cairo_fill(window->cairo); | ||
270 | |||
271 | // border | ||
272 | cairo_set_source_u32(window->cairo, config->colors.binding_mode.border); | ||
273 | cairo_rectangle(window->cairo, pos, 1.5, width + ws_horizontal_padding * 2 - 1, | ||
274 | height + ws_vertical_padding * 2); | ||
275 | cairo_stroke(window->cairo); | ||
276 | |||
277 | // text | ||
278 | cairo_set_source_u32(window->cairo, config->colors.binding_mode.text); | ||
279 | cairo_move_to(window->cairo, (int)pos + ws_horizontal_padding, margin); | ||
280 | pango_printf(window->cairo, window->font, window->scale, | ||
281 | false, "%s", config->mode); | ||
282 | } | ||
283 | |||
284 | void render(struct output *output, struct config *config, struct status_line *line) { | ||
285 | int i; | ||
286 | |||
287 | struct window *window = output->window; | ||
288 | cairo_t *cairo = window->cairo; | ||
289 | bool is_focused = output->focused; | ||
290 | |||
291 | // Clear | ||
292 | cairo_save(cairo); | 17 | cairo_save(cairo); |
293 | cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); | 18 | cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); |
294 | cairo_paint(cairo); | 19 | cairo_paint(cairo); |
295 | cairo_restore(cairo); | 20 | cairo_restore(cairo); |
296 | 21 | ||
297 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | 22 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); |
298 | 23 | if (output->focused) { | |
299 | // Background | ||
300 | if (is_focused) { | ||
301 | cairo_set_source_u32(cairo, config->colors.focused_background); | 24 | cairo_set_source_u32(cairo, config->colors.focused_background); |
302 | } else { | 25 | } else { |
303 | cairo_set_source_u32(cairo, config->colors.background); | 26 | cairo_set_source_u32(cairo, config->colors.background); |
304 | } | 27 | } |
305 | cairo_paint(cairo); | 28 | cairo_paint(cairo); |
306 | 29 | ||
307 | #ifdef ENABLE_TRAY | 30 | // TODO: use actual height |
308 | uint32_t tray_width = tray_render(output, config); | 31 | return 20; |
309 | #else | 32 | } |
310 | const uint32_t tray_width = window->width * window->scale; | 33 | |
311 | #endif | 34 | void render_frame(struct swaybar *bar, |
312 | 35 | struct swaybar_output *output) { | |
313 | // Command output | 36 | cairo_surface_t *recorder = cairo_recording_surface_create( |
314 | if (is_focused) { | 37 | CAIRO_CONTENT_COLOR_ALPHA, NULL); |
315 | cairo_set_source_u32(cairo, config->colors.focused_statusline); | 38 | cairo_t *cairo = cairo_create(recorder); |
39 | uint32_t height = render_to_cairo(cairo, bar, output); | ||
40 | if (height != output->height) { | ||
41 | // Reconfigure surface | ||
42 | zwlr_layer_surface_v1_set_size( | ||
43 | output->layer_surface, 0, height); | ||
44 | // TODO: this could infinite loop if the compositor assigns us a | ||
45 | // different height than what we asked for | ||
46 | wl_surface_commit(output->surface); | ||
47 | wl_display_roundtrip(bar->display); | ||
316 | } else { | 48 | } else { |
317 | cairo_set_source_u32(cairo, config->colors.statusline); | 49 | // Replay recording into shm and send it off |
318 | } | 50 | output->current_buffer = get_next_buffer(bar->shm, |
319 | 51 | output->buffers, output->width, output->height); | |
320 | int width, height; | 52 | cairo_t *shm = output->current_buffer->cairo; |
321 | 53 | cairo_set_source_surface(shm, recorder, 0.0, 0.0); | |
322 | if (line->protocol == TEXT) { | 54 | cairo_paint(shm); |
323 | get_text_size(window->cairo, window->font, &width, &height, | 55 | wl_surface_attach(output->surface, |
324 | window->scale, config->pango_markup, "%s", line->text_line); | 56 | output->current_buffer->buffer, 0, 0); |
325 | cairo_move_to(cairo, tray_width - margin - width, margin); | 57 | wl_surface_damage(output->surface, 0, 0, output->width, output->height); |
326 | pango_printf(window->cairo, window->font, window->scale, | 58 | wl_surface_commit(output->surface); |
327 | config->pango_markup, "%s", line->text_line); | 59 | wl_display_roundtrip(bar->display); |
328 | } else if (line->protocol == I3BAR && line->block_line) { | 60 | } |
329 | double pos = tray_width - 0.5; | 61 | cairo_surface_destroy(recorder); |
330 | bool edge = true; | 62 | cairo_destroy(cairo); |
331 | for (i = line->block_line->length - 1; i >= 0; --i) { | ||
332 | struct status_block *block = line->block_line->items[i]; | ||
333 | if (block->full_text && block->full_text[0]) { | ||
334 | render_block(window, config, block, &pos, edge, is_focused); | ||
335 | edge = false; | ||
336 | } | ||
337 | } | ||
338 | } | ||
339 | |||
340 | cairo_set_line_width(cairo, 1.0); | ||
341 | double x = 0.5; | ||
342 | |||
343 | // Workspaces | ||
344 | if (config->workspace_buttons) { | ||
345 | for (i = 0; i < output->workspaces->length; ++i) { | ||
346 | struct workspace *ws = output->workspaces->items[i]; | ||
347 | render_workspace_button(window, config, ws, &x); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | // binding mode indicator | ||
352 | if (config->mode && config->binding_mode_indicator) { | ||
353 | render_binding_mode_indicator(window, config, x); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | void set_window_height(struct window *window, int height) { | ||
358 | int text_width, text_height; | ||
359 | get_text_size(window->cairo, window->font, | ||
360 | &text_width, &text_height, window->scale, false, | ||
361 | "Test string for measuring purposes"); | ||
362 | if (height > 0) { | ||
363 | margin = (height - text_height) / 2; | ||
364 | ws_vertical_padding = margin - 1.5; | ||
365 | } | ||
366 | window->height = (text_height + margin * 2) / window->scale; | ||
367 | } | 63 | } |