diff options
Diffstat (limited to 'sway/old/border.c')
-rw-r--r-- | sway/old/border.c | 510 |
1 files changed, 0 insertions, 510 deletions
diff --git a/sway/old/border.c b/sway/old/border.c deleted file mode 100644 index df0022ce..00000000 --- a/sway/old/border.c +++ /dev/null | |||
@@ -1,510 +0,0 @@ | |||
1 | #define _XOPEN_SOURCE 700 | ||
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 <string.h> | ||
8 | #include <strings.h> | ||
9 | #include <arpa/inet.h> | ||
10 | #include "sway/border.h" | ||
11 | #include "sway/container.h" | ||
12 | #include "sway/config.h" | ||
13 | #include "client/pango.h" | ||
14 | |||
15 | void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { | ||
16 | color = htonl(color); | ||
17 | |||
18 | cairo_set_source_rgba(cairo, | ||
19 | (color >> (2*8) & 0xFF) / 255.0, | ||
20 | (color >> (1*8) & 0xFF) / 255.0, | ||
21 | (color >> (0*8) & 0xFF) / 255.0, | ||
22 | (color >> (3*8) & 0xFF) / 255.0); | ||
23 | } | ||
24 | |||
25 | void border_clear(struct border *border) { | ||
26 | if (border && border->buffer) { | ||
27 | free(border->buffer); | ||
28 | border->buffer = NULL; | ||
29 | } | ||
30 | } | ||
31 | |||
32 | static cairo_t *create_border_buffer(swayc_t *view, struct wlc_geometry g, cairo_surface_t **surface) { | ||
33 | if (view->border == NULL) { | ||
34 | view->border = malloc(sizeof(struct border)); | ||
35 | if (!view->border) { | ||
36 | sway_log(L_ERROR, "Unable to allocate window border information"); | ||
37 | return NULL; | ||
38 | } | ||
39 | } | ||
40 | cairo_t *cr; | ||
41 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, g.size.w); | ||
42 | view->border->buffer = calloc(stride * g.size.h, sizeof(unsigned char)); | ||
43 | view->border->geometry = g; | ||
44 | if (!view->border->buffer) { | ||
45 | sway_log(L_ERROR, "Unable to allocate window border buffer"); | ||
46 | return NULL; | ||
47 | } | ||
48 | *surface = cairo_image_surface_create_for_data(view->border->buffer, | ||
49 | CAIRO_FORMAT_ARGB32, g.size.w, g.size.h, stride); | ||
50 | if (cairo_surface_status(*surface) != CAIRO_STATUS_SUCCESS) { | ||
51 | border_clear(view->border); | ||
52 | sway_log(L_ERROR, "Unable to allocate window border surface"); | ||
53 | return NULL; | ||
54 | } | ||
55 | cr = cairo_create(*surface); | ||
56 | cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); | ||
57 | if (cairo_status(cr) != CAIRO_STATUS_SUCCESS) { | ||
58 | cairo_surface_destroy(*surface); | ||
59 | border_clear(view->border); | ||
60 | sway_log(L_ERROR, "Unable to create cairo context"); | ||
61 | return NULL; | ||
62 | } | ||
63 | return cr; | ||
64 | } | ||
65 | |||
66 | // TODO: move to client/cairo.h when local set_source_u32 is fixed. | ||
67 | /** | ||
68 | * Renders a sharp line of any width and height. | ||
69 | * | ||
70 | * The line is drawn from (x,y) to (x+width,y+height) where width/height is 0 | ||
71 | * if the line has a width/height of one pixel, respectively. | ||
72 | */ | ||
73 | static void render_sharp_line(cairo_t *cairo, uint32_t color, double x, double y, double width, double height) { | ||
74 | cairo_set_source_u32(cairo, color); | ||
75 | |||
76 | if (width > 1 && height > 1) { | ||
77 | cairo_rectangle(cairo, x, y, width, height); | ||
78 | cairo_fill(cairo); | ||
79 | } else { | ||
80 | if (width == 1) { | ||
81 | x += 0.5; | ||
82 | height += y; | ||
83 | width = x; | ||
84 | } | ||
85 | |||
86 | if (height == 1) { | ||
87 | y += 0.5; | ||
88 | width += x; | ||
89 | height = y; | ||
90 | } | ||
91 | |||
92 | cairo_move_to(cairo, x, y); | ||
93 | cairo_set_line_width(cairo, 1.0); | ||
94 | cairo_line_to(cairo, width, height); | ||
95 | cairo_stroke(cairo); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | int get_font_text_height(const char *font) { | ||
100 | cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 200, 200); | ||
101 | cairo_t *cr = cairo_create(surface); | ||
102 | int width, height; | ||
103 | get_text_size(cr, font, &width, &height, 1, false, "Gg"); | ||
104 | cairo_surface_destroy(surface); | ||
105 | cairo_destroy(cr); | ||
106 | return height; | ||
107 | } | ||
108 | |||
109 | static void render_borders(swayc_t *view, cairo_t *cr, struct border_colors *colors, bool top) { | ||
110 | struct wlc_geometry *g = &view->border->geometry; | ||
111 | struct wlc_geometry *b = &view->border_geometry; | ||
112 | struct wlc_geometry *v = &view->actual_geometry; | ||
113 | enum swayc_layouts layout = view->parent->layout; | ||
114 | uint32_t color; | ||
115 | |||
116 | int x = b->origin.x - g->origin.x; | ||
117 | int y = b->origin.y - g->origin.y; | ||
118 | |||
119 | // draw vertical/horizontal indicator if container is the only child of its parent container | ||
120 | bool is_only_child = view->parent && view->parent->children && view->parent->children->length == 1; | ||
121 | |||
122 | // left border | ||
123 | int left_border = v->origin.x - b->origin.x; | ||
124 | if (left_border > 0) { | ||
125 | render_sharp_line(cr, | ||
126 | colors->child_border, | ||
127 | x, y, | ||
128 | left_border, | ||
129 | b->size.h); | ||
130 | } | ||
131 | |||
132 | // right border | ||
133 | int right_border = b->size.w - v->size.w - left_border; | ||
134 | if (right_border > 0) { | ||
135 | if (is_only_child && layout == L_HORIZ && !view->is_floating) { | ||
136 | color = colors->indicator; | ||
137 | } else { | ||
138 | color = colors->child_border; | ||
139 | } | ||
140 | render_sharp_line(cr, | ||
141 | color, | ||
142 | x + b->size.w - right_border, | ||
143 | y, | ||
144 | right_border, | ||
145 | b->size.h); | ||
146 | } | ||
147 | |||
148 | // top border | ||
149 | int top_border = v->origin.y - b->origin.y; | ||
150 | if (top && top_border > 0) { | ||
151 | render_sharp_line(cr, | ||
152 | colors->child_border, | ||
153 | x, y, | ||
154 | b->size.w, | ||
155 | top_border); | ||
156 | } | ||
157 | |||
158 | // bottom border | ||
159 | int bottom_border = b->size.h - (top_border + v->size.h); | ||
160 | if (bottom_border > 0) { | ||
161 | if (is_only_child && layout == L_VERT && !view->is_floating) { | ||
162 | color = colors->indicator; | ||
163 | } else { | ||
164 | color = colors->child_border; | ||
165 | } | ||
166 | render_sharp_line(cr, | ||
167 | color, | ||
168 | x, | ||
169 | y + b->size.h - bottom_border, | ||
170 | b->size.w, | ||
171 | bottom_border); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | static void render_title_bar(swayc_t *view, cairo_t *cr, struct wlc_geometry *b, struct border_colors *colors) { | ||
176 | struct wlc_geometry *tb = &view->title_bar_geometry; | ||
177 | int x = MIN(tb->origin.x, tb->origin.x - b->origin.x); | ||
178 | int y = MIN(tb->origin.y, tb->origin.y - b->origin.y); | ||
179 | |||
180 | // title bar background | ||
181 | cairo_set_source_u32(cr, colors->background); | ||
182 | cairo_rectangle(cr, x, y, tb->size.w, tb->size.h); | ||
183 | cairo_fill(cr); | ||
184 | |||
185 | // header top line | ||
186 | render_sharp_line(cr, colors->border, x, y, tb->size.w, 1); | ||
187 | |||
188 | // text | ||
189 | if (view->name) { | ||
190 | int width, height; | ||
191 | get_text_size(cr, config->font, &width, &height, 1, false, "%s", view->name); | ||
192 | cairo_move_to(cr, x + 2, y + 2); | ||
193 | cairo_set_source_u32(cr, colors->text); | ||
194 | pango_printf(cr, config->font, 1, false, "%s", view->name); | ||
195 | } | ||
196 | // Marks | ||
197 | if (config->show_marks && view->marks) { | ||
198 | int total_len = 0; | ||
199 | |||
200 | for(int i = view->marks->length - 1; i >= 0; --i) { | ||
201 | char *mark = (char *)view->marks->items[i]; | ||
202 | if (*mark != '_') { | ||
203 | int width, height; | ||
204 | get_text_size(cr, config->font, &width, &height, 1, false, "[%s]", mark); | ||
205 | total_len += width; | ||
206 | if ((int)tb->size.w + x - (total_len + 2) < x + 2) { | ||
207 | break; | ||
208 | } else { | ||
209 | cairo_move_to(cr, (int)tb->size.w + x - (total_len + 2), y + 2); | ||
210 | cairo_set_source_u32(cr, colors->text); | ||
211 | pango_printf(cr, config->font, 1, false, "[%s]", mark); | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | |||
217 | // titlebars has a border all around for tabbed layouts | ||
218 | if (view->parent->layout == L_TABBED) { | ||
219 | // header bottom line | ||
220 | render_sharp_line(cr, colors->border, x, y + tb->size.h - 1, | ||
221 | tb->size.w, 1); | ||
222 | |||
223 | // left border | ||
224 | render_sharp_line(cr, colors->border, x, y, 1, tb->size.h); | ||
225 | |||
226 | // right border | ||
227 | render_sharp_line(cr, colors->border, x + tb->size.w - 1, y, | ||
228 | 1, tb->size.h); | ||
229 | |||
230 | return; | ||
231 | } | ||
232 | |||
233 | if ((uint32_t)(view->actual_geometry.origin.y - tb->origin.y) == tb->size.h) { | ||
234 | // header bottom line | ||
235 | render_sharp_line(cr, colors->border, | ||
236 | x + view->actual_geometry.origin.x - tb->origin.x, | ||
237 | y + tb->size.h - 1, | ||
238 | view->actual_geometry.size.w, 1); | ||
239 | } else { | ||
240 | // header bottom line | ||
241 | render_sharp_line(cr, colors->border, x, | ||
242 | y + tb->size.h - 1, | ||
243 | tb->size.w, 1); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * Generate nested container title for tabbed/stacked layouts | ||
249 | */ | ||
250 | static char *generate_container_title(swayc_t *container) { | ||
251 | char layout = 'H'; | ||
252 | char *name, *prev_name = NULL; | ||
253 | switch (container->layout) { | ||
254 | case L_TABBED: | ||
255 | layout = 'T'; | ||
256 | break; | ||
257 | case L_STACKED: | ||
258 | layout = 'S'; | ||
259 | break; | ||
260 | case L_VERT: | ||
261 | layout = 'V'; | ||
262 | break; | ||
263 | default: | ||
264 | layout = 'H'; | ||
265 | } | ||
266 | int len = 9; | ||
267 | name = malloc(len * sizeof(char)); | ||
268 | if (!name) { | ||
269 | sway_log(L_ERROR, "Unable to allocate container title"); | ||
270 | return NULL; | ||
271 | } | ||
272 | snprintf(name, len, "sway: %c[", layout); | ||
273 | |||
274 | int i; | ||
275 | for (i = 0; i < container->children->length; ++i) { | ||
276 | prev_name = name; | ||
277 | swayc_t* child = container->children->items[i]; | ||
278 | const char *title = NULL; | ||
279 | if (child->type == C_VIEW) { | ||
280 | title = child->app_id ? child->app_id : | ||
281 | (child->instance ? child->instance : | ||
282 | (child->class ? child->class :"(null)")); | ||
283 | } else { //child->type == C_CONTAINER | ||
284 | title = generate_container_title(child); | ||
285 | } | ||
286 | |||
287 | len = strlen(name) + strlen(title) + 1; | ||
288 | if (i < container->children->length-1) { | ||
289 | len++; | ||
290 | } | ||
291 | |||
292 | name = malloc(len * sizeof(char)); | ||
293 | if (!name) { | ||
294 | free(prev_name); | ||
295 | sway_log(L_ERROR, "Unable to allocate container title"); | ||
296 | return NULL; | ||
297 | } | ||
298 | if (i < container->children->length-1) { | ||
299 | snprintf(name, len, "%s%s ", prev_name, title); | ||
300 | } else { | ||
301 | snprintf(name, len, "%s%s", prev_name, title); | ||
302 | } | ||
303 | free(prev_name); | ||
304 | } | ||
305 | |||
306 | prev_name = name; | ||
307 | len = strlen(name) + 2; | ||
308 | name = malloc(len * sizeof(char)); | ||
309 | if (!name) { | ||
310 | free(prev_name); | ||
311 | sway_log(L_ERROR, "Unable to allocate container title"); | ||
312 | return NULL; | ||
313 | } | ||
314 | snprintf(name, len, "%s]", prev_name); | ||
315 | free(prev_name); | ||
316 | free(container->name); | ||
317 | container->name = name; | ||
318 | return container->name + 6; // don't include "sway: " | ||
319 | } | ||
320 | |||
321 | void update_tabbed_stacked_titlebars(swayc_t *c, cairo_t *cr, struct wlc_geometry *g, swayc_t *focused, swayc_t *focused_inactive) { | ||
322 | if (c->type == C_CONTAINER) { | ||
323 | if (c->parent->focused == c) { | ||
324 | render_title_bar(c, cr, g, &config->border_colors.focused_inactive); | ||
325 | } else { | ||
326 | render_title_bar(c, cr, g, &config->border_colors.unfocused); | ||
327 | } | ||
328 | |||
329 | if (!c->visible) { | ||
330 | return; | ||
331 | } | ||
332 | |||
333 | int i; | ||
334 | for (i = 0; i < c->children->length; ++i) { | ||
335 | swayc_t *child = c->children->items[i]; | ||
336 | update_tabbed_stacked_titlebars(child, cr, g, focused, focused_inactive); | ||
337 | } | ||
338 | } else { | ||
339 | bool is_child_of_focused = swayc_is_child_of(c, get_focused_container(&root_container)); | ||
340 | |||
341 | if (focused == c || is_child_of_focused) { | ||
342 | render_title_bar(c, cr, g, &config->border_colors.focused); | ||
343 | } else if (focused_inactive == c) { | ||
344 | render_title_bar(c, cr, g, &config->border_colors.focused_inactive); | ||
345 | } else { | ||
346 | render_title_bar(c, cr, g, &config->border_colors.unfocused); | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | |||
351 | static void update_view_border(swayc_t *view) { | ||
352 | if (!view->visible) { | ||
353 | return; | ||
354 | } | ||
355 | |||
356 | cairo_t *cr = NULL; | ||
357 | cairo_surface_t *surface = NULL; | ||
358 | |||
359 | // clear previous border buffer. | ||
360 | border_clear(view->border); | ||
361 | |||
362 | // get focused and focused_inactive views | ||
363 | swayc_t *focused = get_focused_view(&root_container); | ||
364 | swayc_t *container = swayc_parent_by_type(view, C_CONTAINER); | ||
365 | swayc_t *focused_inactive = NULL; | ||
366 | |||
367 | bool is_child_of_focused = swayc_is_parent_of(get_focused_container(&root_container), view); | ||
368 | |||
369 | if (container) { | ||
370 | focused_inactive = swayc_focus_by_type(container, C_VIEW); | ||
371 | } else { | ||
372 | container = swayc_parent_by_type(view, C_WORKSPACE); | ||
373 | if (container) { | ||
374 | focused_inactive = swayc_focus_by_type(container, C_VIEW); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | // for tabbed/stacked layouts the focused view has to draw all the | ||
379 | // titlebars of the hidden views. | ||
380 | swayc_t *p = NULL; | ||
381 | if (view->parent->focused == view && (p = swayc_tabbed_stacked_ancestor(view))) { | ||
382 | struct wlc_geometry g = { | ||
383 | .origin = { | ||
384 | .x = p->x, | ||
385 | .y = p->y | ||
386 | }, | ||
387 | .size = { | ||
388 | .w = p->width, | ||
389 | .h = p->height | ||
390 | } | ||
391 | }; | ||
392 | cr = create_border_buffer(view, g, &surface); | ||
393 | if (!cr) { | ||
394 | goto cleanup; | ||
395 | } | ||
396 | |||
397 | bool render_top = !should_hide_top_border(view, view->y); | ||
398 | if (view == focused || is_child_of_focused) { | ||
399 | render_borders(view, cr, &config->border_colors.focused, render_top); | ||
400 | } else { | ||
401 | render_borders(view, cr, &config->border_colors.focused_inactive, render_top); | ||
402 | } | ||
403 | |||
404 | // generate container titles | ||
405 | int i; | ||
406 | for (i = 0; i < p->children->length; ++i) { | ||
407 | swayc_t *child = p->children->items[i]; | ||
408 | if (child->type == C_CONTAINER) { | ||
409 | generate_container_title(child); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | update_tabbed_stacked_titlebars(p, cr, &g, focused, focused_inactive); | ||
414 | } else { | ||
415 | switch (view->border_type) { | ||
416 | case B_NONE: | ||
417 | break; | ||
418 | case B_PIXEL: | ||
419 | cr = create_border_buffer(view, view->border_geometry, &surface); | ||
420 | if (!cr) { | ||
421 | break; | ||
422 | } | ||
423 | |||
424 | if (focused == view || is_child_of_focused) { | ||
425 | render_borders(view, cr, &config->border_colors.focused, true); | ||
426 | } else if (focused_inactive == view) { | ||
427 | render_borders(view, cr, &config->border_colors.focused_inactive, true); | ||
428 | } else { | ||
429 | render_borders(view, cr, &config->border_colors.unfocused, true); | ||
430 | } | ||
431 | |||
432 | break; | ||
433 | case B_NORMAL: | ||
434 | cr = create_border_buffer(view, view->border_geometry, &surface); | ||
435 | if (!cr) { | ||
436 | break; | ||
437 | } | ||
438 | |||
439 | if (focused == view || is_child_of_focused) { | ||
440 | render_borders(view, cr, &config->border_colors.focused, false); | ||
441 | render_title_bar(view, cr, &view->border_geometry, | ||
442 | &config->border_colors.focused); | ||
443 | } else if (focused_inactive == view) { | ||
444 | render_borders(view, cr, &config->border_colors.focused_inactive, false); | ||
445 | render_title_bar(view, cr, &view->border_geometry, | ||
446 | &config->border_colors.focused_inactive); | ||
447 | } else { | ||
448 | render_borders(view, cr, &config->border_colors.unfocused, false); | ||
449 | render_title_bar(view, cr, &view->border_geometry, | ||
450 | &config->border_colors.unfocused); | ||
451 | } | ||
452 | |||
453 | break; | ||
454 | } | ||
455 | } | ||
456 | |||
457 | cleanup: | ||
458 | |||
459 | if (surface) { | ||
460 | cairo_surface_flush(surface); | ||
461 | cairo_surface_destroy(surface); | ||
462 | } | ||
463 | |||
464 | if (cr) { | ||
465 | cairo_destroy(cr); | ||
466 | } | ||
467 | } | ||
468 | |||
469 | void update_container_border(swayc_t *container) { | ||
470 | if (container->type == C_VIEW) { | ||
471 | update_view_border(container); | ||
472 | return; | ||
473 | } else { | ||
474 | for (int i = 0; i < container->children->length; ++i) { | ||
475 | update_container_border(container->children->items[i]); | ||
476 | } | ||
477 | } | ||
478 | } | ||
479 | |||
480 | void render_view_borders(wlc_handle view) { | ||
481 | swayc_t *c = swayc_by_handle(view); | ||
482 | |||
483 | |||
484 | // emulate i3 behavior for drawing borders for tabbed and stacked layouts: | ||
485 | // if we are not the only child in the container, always draw borders, | ||
486 | // regardless of the border setting on the individual view | ||
487 | if (!c || (c->border_type == B_NONE | ||
488 | && !((c->parent->layout == L_TABBED || c->parent->layout == L_STACKED) | ||
489 | && c->parent->children->length > 1))) { | ||
490 | return; | ||
491 | } | ||
492 | |||
493 | if (c->border && c->border->buffer) { | ||
494 | wlc_pixels_write(WLC_RGBA8888, &c->border->geometry, c->border->buffer); | ||
495 | } | ||
496 | } | ||
497 | |||
498 | bool should_hide_top_border(swayc_t *con, double y) { | ||
499 | // returns true if container is child of tabbed/stacked layout and is | ||
500 | // sharing top border with tabbed titlebar | ||
501 | swayc_t *par = con->parent; | ||
502 | while (par->type != C_WORKSPACE) { | ||
503 | if (par->layout == L_TABBED || par->layout == L_STACKED) { | ||
504 | return con->y == y; | ||
505 | } | ||
506 | con = par; | ||
507 | par = par->parent; | ||
508 | } | ||
509 | return false; | ||
510 | } | ||