aboutsummaryrefslogtreecommitdiffstats
path: root/swaybar/render.c
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2018-03-28 23:04:20 -0400
committerLibravatar Drew DeVault <sir@cmpwn.com>2018-03-29 22:11:08 -0400
commitcab1352801b62d1b8a12ca1c995cb24445ce4bc9 (patch)
treebc67373916c06d48700c4f69b8c2470a2f86887f /swaybar/render.c
parentAllow sway IPC clients to fall back to i3 socket (diff)
downloadsway-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.c388
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 */
19static int margin = 3;
20static int ws_horizontal_padding = 5;
21static double ws_vertical_padding = 1.5;
22static 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 */
30static 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
56static 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 13static 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
191static 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
215void 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
224static 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
260static 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
284void 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 34void 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
357void 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}