aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Alexander Orzechowski <alex@ozal.ski>2023-11-21 19:51:57 -0500
committerLibravatar Kirill Primak <vyivel@eclair.cafe>2024-01-18 18:36:54 +0300
commit6d7b1321db54155cf78305dbafdcfc7de9b78415 (patch)
treeacf9f02681b1d5a40416be5f4151641920176a93
parentscene_graph: Port layer_shell (diff)
downloadsway-6d7b1321db54155cf78305dbafdcfc7de9b78415.tar.gz
sway-6d7b1321db54155cf78305dbafdcfc7de9b78415.tar.zst
sway-6d7b1321db54155cf78305dbafdcfc7de9b78415.zip
scene_graph: Port container server side decorations
-rw-r--r--include/sway/tree/container.h37
-rw-r--r--sway/commands/client.c7
-rw-r--r--sway/commands/mark.c2
-rw-r--r--sway/commands/reload.c7
-rw-r--r--sway/commands/show_marks.c6
-rw-r--r--sway/commands/title_align.c6
-rw-r--r--sway/commands/unmark.c11
-rw-r--r--sway/tree/container.c545
-rw-r--r--sway/tree/view.c10
9 files changed, 378 insertions, 253 deletions
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 6f72439c..4920e064 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -76,6 +76,9 @@ struct sway_container {
76 76
77 struct wlr_scene_tree *border; 77 struct wlr_scene_tree *border;
78 struct wlr_scene_tree *background; 78 struct wlr_scene_tree *background;
79
80 struct sway_text_node *title_text;
81 struct sway_text_node *marks_text;
79 } title_bar; 82 } title_bar;
80 83
81 struct { 84 struct {
@@ -94,6 +97,7 @@ struct sway_container {
94 97
95 char *title; // The view's title (unformatted) 98 char *title; // The view's title (unformatted)
96 char *formatted_title; // The title displayed in the title bar 99 char *formatted_title; // The title displayed in the title bar
100 int title_width;
97 101
98 enum sway_container_layout prev_split_layout; 102 enum sway_container_layout prev_split_layout;
99 103
@@ -141,18 +145,7 @@ struct sway_container {
141 145
142 float alpha; 146 float alpha;
143 147
144 struct wlr_texture *title_focused;
145 struct wlr_texture *title_focused_inactive;
146 struct wlr_texture *title_focused_tab_title;
147 struct wlr_texture *title_unfocused;
148 struct wlr_texture *title_urgent;
149
150 list_t *marks; // char * 148 list_t *marks; // char *
151 struct wlr_texture *marks_focused;
152 struct wlr_texture *marks_focused_inactive;
153 struct wlr_texture *marks_focused_tab_title;
154 struct wlr_texture *marks_unfocused;
155 struct wlr_texture *marks_urgent;
156 149
157 struct { 150 struct {
158 struct wl_signal destroy; 151 struct wl_signal destroy;
@@ -194,7 +187,9 @@ void container_reap_empty(struct sway_container *con);
194 187
195struct sway_container *container_flatten(struct sway_container *container); 188struct sway_container *container_flatten(struct sway_container *container);
196 189
197void container_update_title_textures(struct sway_container *container); 190void container_update_title_bar(struct sway_container *container);
191
192void container_update_marks(struct sway_container *container);
198 193
199size_t container_build_representation(enum sway_container_layout layout, 194size_t container_build_representation(enum sway_container_layout layout,
200 list_t *children, char *buffer); 195 list_t *children, char *buffer);
@@ -231,11 +226,6 @@ void container_set_geometry_from_content(struct sway_container *con);
231bool container_is_floating(struct sway_container *container); 226bool container_is_floating(struct sway_container *container);
232 227
233/** 228/**
234 * Same as above, but for current container state.
235 */
236bool container_is_current_floating(struct sway_container *container);
237
238/**
239 * Get a container's box in layout coordinates. 229 * Get a container's box in layout coordinates.
240 */ 230 */
241void container_get_box(struct sway_container *container, struct wlr_box *box); 231void container_get_box(struct sway_container *container, struct wlr_box *box);
@@ -308,15 +298,10 @@ void container_discover_outputs(struct sway_container *con);
308 298
309enum sway_container_layout container_parent_layout(struct sway_container *con); 299enum sway_container_layout container_parent_layout(struct sway_container *con);
310 300
311enum sway_container_layout container_current_parent_layout(
312 struct sway_container *con);
313
314list_t *container_get_siblings(struct sway_container *container); 301list_t *container_get_siblings(struct sway_container *container);
315 302
316int container_sibling_index(struct sway_container *child); 303int container_sibling_index(struct sway_container *child);
317 304
318list_t *container_get_current_siblings(struct sway_container *container);
319
320void container_handle_fullscreen_reparent(struct sway_container *con); 305void container_handle_fullscreen_reparent(struct sway_container *con);
321 306
322void container_add_child(struct sway_container *parent, 307void container_add_child(struct sway_container *parent,
@@ -364,8 +349,6 @@ bool container_has_mark(struct sway_container *container, char *mark);
364 349
365void container_add_mark(struct sway_container *container, char *mark); 350void container_add_mark(struct sway_container *container, char *mark);
366 351
367void container_update_marks_textures(struct sway_container *container);
368
369void container_raise_floating(struct sway_container *con); 352void container_raise_floating(struct sway_container *con);
370 353
371bool container_is_scratchpad_hidden(struct sway_container *con); 354bool container_is_scratchpad_hidden(struct sway_container *con);
@@ -389,4 +372,10 @@ bool container_is_sticky_or_child(struct sway_container *con);
389 */ 372 */
390int container_squash(struct sway_container *con); 373int container_squash(struct sway_container *con);
391 374
375void container_arrange_title_bar(struct sway_container *con);
376
377void container_update(struct sway_container *con);
378
379void container_update_itself_and_parents(struct sway_container *con);
380
392#endif 381#endif
diff --git a/sway/commands/client.c b/sway/commands/client.c
index 77263145..7a9cff2c 100644
--- a/sway/commands/client.c
+++ b/sway/commands/client.c
@@ -5,9 +5,8 @@
5#include "sway/tree/container.h" 5#include "sway/tree/container.h"
6#include "util.h" 6#include "util.h"
7 7
8static void rebuild_textures_iterator(struct sway_container *con, void *data) { 8static void container_update_iterator(struct sway_container *con, void *data) {
9 container_update_marks_textures(con); 9 container_update(con);
10 container_update_title_textures(con);
11} 10}
12 11
13static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name, 12static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
@@ -51,7 +50,7 @@ static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
51 memcpy(class, &colors, sizeof(struct border_colors)); 50 memcpy(class, &colors, sizeof(struct border_colors));
52 51
53 if (config->active) { 52 if (config->active) {
54 root_for_each_container(rebuild_textures_iterator, NULL); 53 root_for_each_container(container_update_iterator, NULL);
55 54
56 for (int i = 0; i < root->outputs->length; ++i) { 55 for (int i = 0; i < root->outputs->length; ++i) {
57 struct sway_output *output = root->outputs->items[i]; 56 struct sway_output *output = root->outputs->items[i];
diff --git a/sway/commands/mark.c b/sway/commands/mark.c
index aa5f185c..30cf458c 100644
--- a/sway/commands/mark.c
+++ b/sway/commands/mark.c
@@ -59,7 +59,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) {
59 } 59 }
60 60
61 free(mark); 61 free(mark);
62 container_update_marks_textures(container); 62 container_update_marks(container);
63 if (container->view) { 63 if (container->view) {
64 view_execute_criteria(container->view); 64 view_execute_criteria(container->view);
65 } 65 }
diff --git a/sway/commands/reload.c b/sway/commands/reload.c
index 76f14bba..82967ca7 100644
--- a/sway/commands/reload.c
+++ b/sway/commands/reload.c
@@ -9,9 +9,8 @@
9#include "list.h" 9#include "list.h"
10#include "log.h" 10#include "log.h"
11 11
12static void rebuild_textures_iterator(struct sway_container *con, void *data) { 12static void title_bar_update_iterator(struct sway_container *con, void *data) {
13 container_update_marks_textures(con); 13 container_update_title_bar(con);
14 container_update_title_textures(con);
15} 14}
16 15
17static void do_reload(void *data) { 16static void do_reload(void *data) {
@@ -48,7 +47,7 @@ static void do_reload(void *data) {
48 } 47 }
49 list_free_items_and_destroy(bar_ids); 48 list_free_items_and_destroy(bar_ids);
50 49
51 root_for_each_container(rebuild_textures_iterator, NULL); 50 root_for_each_container(title_bar_update_iterator, NULL);
52 51
53 arrange_root(); 52 arrange_root();
54} 53}
diff --git a/sway/commands/show_marks.c b/sway/commands/show_marks.c
index 0d373b80..f738144f 100644
--- a/sway/commands/show_marks.c
+++ b/sway/commands/show_marks.c
@@ -10,8 +10,8 @@
10#include "stringop.h" 10#include "stringop.h"
11#include "util.h" 11#include "util.h"
12 12
13static void rebuild_marks_iterator(struct sway_container *con, void *data) { 13static void title_bar_update_iterator(struct sway_container *con, void *data) {
14 container_update_marks_textures(con); 14 container_update_marks(con);
15} 15}
16 16
17struct cmd_results *cmd_show_marks(int argc, char **argv) { 17struct cmd_results *cmd_show_marks(int argc, char **argv) {
@@ -23,7 +23,7 @@ struct cmd_results *cmd_show_marks(int argc, char **argv) {
23 config->show_marks = parse_boolean(argv[0], config->show_marks); 23 config->show_marks = parse_boolean(argv[0], config->show_marks);
24 24
25 if (config->show_marks) { 25 if (config->show_marks) {
26 root_for_each_container(rebuild_marks_iterator, NULL); 26 root_for_each_container(title_bar_update_iterator, NULL);
27 } 27 }
28 28
29 for (int i = 0; i < root->outputs->length; ++i) { 29 for (int i = 0; i < root->outputs->length; ++i) {
diff --git a/sway/commands/title_align.c b/sway/commands/title_align.c
index c30355de..7f5dd3ae 100644
--- a/sway/commands/title_align.c
+++ b/sway/commands/title_align.c
@@ -4,6 +4,10 @@
4#include "sway/tree/container.h" 4#include "sway/tree/container.h"
5#include "sway/tree/root.h" 5#include "sway/tree/root.h"
6 6
7static void arrange_title_bar_iterator(struct sway_container *con, void *data) {
8 container_arrange_title_bar(con);
9}
10
7struct cmd_results *cmd_title_align(int argc, char **argv) { 11struct cmd_results *cmd_title_align(int argc, char **argv) {
8 struct cmd_results *error = NULL; 12 struct cmd_results *error = NULL;
9 if ((error = checkarg(argc, "title_align", EXPECTED_AT_LEAST, 1))) { 13 if ((error = checkarg(argc, "title_align", EXPECTED_AT_LEAST, 1))) {
@@ -21,6 +25,8 @@ struct cmd_results *cmd_title_align(int argc, char **argv) {
21 "Expected 'title_align left|center|right'"); 25 "Expected 'title_align left|center|right'");
22 } 26 }
23 27
28 root_for_each_container(arrange_title_bar_iterator, NULL);
29
24 for (int i = 0; i < root->outputs->length; ++i) { 30 for (int i = 0; i < root->outputs->length; ++i) {
25 struct sway_output *output = root->outputs->items[i]; 31 struct sway_output *output = root->outputs->items[i];
26 output_damage_whole(output); 32 output_damage_whole(output);
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c
index 19274dfb..c3a6ac4b 100644
--- a/sway/commands/unmark.c
+++ b/sway/commands/unmark.c
@@ -8,9 +8,13 @@
8#include "log.h" 8#include "log.h"
9#include "stringop.h" 9#include "stringop.h"
10 10
11static void remove_all_marks_iterator(struct sway_container *con, void *data) { 11static void remove_mark(struct sway_container *con) {
12 container_clear_marks(con); 12 container_clear_marks(con);
13 container_update_marks_textures(con); 13 container_update_marks(con);
14}
15
16static void remove_all_marks_iterator(struct sway_container *con, void *data) {
17 remove_mark(con);
14} 18}
15 19
16// unmark Remove all marks from all views 20// unmark Remove all marks from all views
@@ -38,8 +42,7 @@ struct cmd_results *cmd_unmark(int argc, char **argv) {
38 } 42 }
39 } else if (con && !mark) { 43 } else if (con && !mark) {
40 // Clear all marks from the given container 44 // Clear all marks from the given container
41 container_clear_marks(con); 45 remove_mark(con);
42 container_update_marks_textures(con);
43 } else if (!con && mark) { 46 } else if (!con && mark) {
44 // Remove mark from whichever container has it 47 // Remove mark from whichever container has it
45 container_find_and_unmark(mark); 48 container_find_and_unmark(mark);
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 8fca6a12..4aae4d32 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -8,15 +8,13 @@
8#include <wlr/types/wlr_output_layout.h> 8#include <wlr/types/wlr_output_layout.h>
9#include <wlr/types/wlr_subcompositor.h> 9#include <wlr/types/wlr_subcompositor.h>
10#include "linux-dmabuf-unstable-v1-protocol.h" 10#include "linux-dmabuf-unstable-v1-protocol.h"
11#include "cairo_util.h"
12#include "pango.h"
13#include "sway/config.h" 11#include "sway/config.h"
14#include "sway/desktop.h"
15#include "sway/desktop/transaction.h" 12#include "sway/desktop/transaction.h"
16#include "sway/input/input-manager.h" 13#include "sway/input/input-manager.h"
17#include "sway/input/seat.h" 14#include "sway/input/seat.h"
18#include "sway/ipc-server.h" 15#include "sway/ipc-server.h"
19#include "sway/scene_descriptor.h" 16#include "sway/scene_descriptor.h"
17#include "sway/sway_text_node.h"
20#include "sway/output.h" 18#include "sway/output.h"
21#include "sway/server.h" 19#include "sway/server.h"
22#include "sway/surface.h" 20#include "sway/surface.h"
@@ -120,9 +118,328 @@ struct sway_container *container_create(struct sway_view *view) {
120 wl_signal_init(&c->events.destroy); 118 wl_signal_init(&c->events.destroy);
121 wl_signal_emit_mutable(&root->events.new_node, &c->node); 119 wl_signal_emit_mutable(&root->events.new_node, &c->node);
122 120
121 container_update(c);
122
123 return c; 123 return c;
124} 124}
125 125
126static bool container_is_focused(struct sway_container *con, void *data) {
127 return con->current.focused;
128}
129
130static bool container_has_focused_child(struct sway_container *con) {
131 return container_find_child(con, container_is_focused, NULL);
132}
133
134static bool container_is_current_parent_focused(struct sway_container *con) {
135 if (con->current.parent) {
136 struct sway_container *parent = con->current.parent;
137 return parent->current.focused || container_is_current_parent_focused(parent);
138 } else if (con->current.workspace) {
139 struct sway_workspace *ws = con->current.workspace;
140 return ws->current.focused;
141 }
142
143 return false;
144}
145
146static struct border_colors *container_get_current_colors(
147 struct sway_container *con) {
148 struct border_colors *colors;
149
150 bool urgent = con->view ?
151 view_is_urgent(con->view) : container_has_urgent_child(con);
152 struct sway_container *active_child;
153
154 if (con->current.parent) {
155 active_child = con->current.parent->current.focused_inactive_child;
156 } else if (con->current.workspace) {
157 active_child = con->current.workspace->current.focused_inactive_child;
158 } else {
159 active_child = NULL;
160 }
161
162 if (urgent) {
163 colors = &config->border_colors.urgent;
164 } else if (con->current.focused || container_is_current_parent_focused(con)) {
165 colors = &config->border_colors.focused;
166 } else if (config->has_focused_tab_title && container_has_focused_child(con)) {
167 colors = &config->border_colors.focused_tab_title;
168 } else if (con == active_child) {
169 colors = &config->border_colors.focused_inactive;
170 } else {
171 colors = &config->border_colors.unfocused;
172 }
173
174 return colors;
175}
176
177static bool container_is_current_floating(struct sway_container *container) {
178 if (!container->current.parent && container->current.workspace &&
179 list_find(container->current.workspace->floating, container) != -1) {
180 return true;
181 }
182 if (container->scratchpad) {
183 return true;
184 }
185 return false;
186}
187
188// scene rect wants premultiplied colors
189static void scene_rect_set_color(struct wlr_scene_rect *rect,
190 const float color[4], float opacity) {
191 const float premultiplied[] = {
192 color[0] * color[3] * opacity,
193 color[1] * color[3] * opacity,
194 color[2] * color[3] * opacity,
195 color[3] * opacity,
196 };
197
198 wlr_scene_rect_set_color(rect, premultiplied);
199}
200
201void container_update(struct sway_container *con) {
202 struct border_colors *colors = container_get_current_colors(con);
203 list_t *siblings = NULL;
204 enum sway_container_layout layout = L_NONE;
205 float alpha = con->alpha;
206
207 if (con->current.parent) {
208 siblings = con->current.parent->current.children;
209 layout = con->current.parent->current.layout;
210 } else if (con->current.workspace) {
211 siblings = con->current.workspace->current.tiling;
212 layout = con->current.workspace->current.layout;
213 }
214
215 float bottom[4], right[4];
216 memcpy(bottom, colors->child_border, sizeof(bottom));
217 memcpy(right, colors->child_border, sizeof(right));
218
219 if (!container_is_current_floating(con) && siblings && siblings->length == 1) {
220 if (layout == L_HORIZ) {
221 memcpy(right, colors->indicator, sizeof(right));
222 } else if (layout == L_VERT) {
223 memcpy(bottom, colors->indicator, sizeof(bottom));
224 }
225 }
226
227 struct wlr_scene_node *node;
228 wl_list_for_each(node, &con->title_bar.border->children, link) {
229 struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
230 scene_rect_set_color(rect, colors->border, alpha);
231 }
232
233 wl_list_for_each(node, &con->title_bar.background->children, link) {
234 struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
235 scene_rect_set_color(rect, colors->background, alpha);
236 }
237
238 if (con->view) {
239 scene_rect_set_color(con->border.top, colors->child_border, alpha);
240 scene_rect_set_color(con->border.bottom, bottom, alpha);
241 scene_rect_set_color(con->border.left, colors->child_border, alpha);
242 scene_rect_set_color(con->border.right, right, alpha);
243 }
244
245 if (con->title_bar.title_text) {
246 sway_text_node_set_color(con->title_bar.title_text, colors->text);
247 sway_text_node_set_background(con->title_bar.title_text, colors->background);
248 }
249
250 if (con->title_bar.marks_text) {
251 sway_text_node_set_color(con->title_bar.marks_text, colors->text);
252 sway_text_node_set_background(con->title_bar.marks_text, colors->background);
253 }
254}
255
256void container_update_itself_and_parents(struct sway_container *con) {
257 container_update(con);
258
259 if (con->current.parent) {
260 container_update_itself_and_parents(con->current.parent);
261 }
262}
263
264static void update_rect_list(struct wlr_scene_tree *tree, pixman_region32_t *region) {
265 int len;
266 const pixman_box32_t *rects = pixman_region32_rectangles(region, &len);
267
268 wlr_scene_node_set_enabled(&tree->node, len > 0);
269 if (len == 0) {
270 return;
271 }
272
273 int i = 0;
274 struct wlr_scene_node *node;
275 wl_list_for_each(node, &tree->children, link) {
276 struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
277 wlr_scene_node_set_enabled(&rect->node, i < len);
278
279 if (i < len) {
280 const pixman_box32_t *box = &rects[i++];
281 wlr_scene_node_set_position(&rect->node, box->x1, box->y1);
282 wlr_scene_rect_set_size(rect, box->x2 - box->x1, box->y2 - box->y1);
283 }
284 }
285}
286
287void container_arrange_title_bar(struct sway_container *con) {
288 enum alignment title_align = config->title_align;
289 int marks_buffer_width = 0;
290 int width = con->title_width;
291 int height = container_titlebar_height();
292
293 pixman_region32_t text_area;
294 pixman_region32_init(&text_area);
295
296 if (con->title_bar.marks_text) {
297 struct sway_text_node *node = con->title_bar.marks_text;
298 marks_buffer_width = node->width;
299
300 int h_padding;
301 if (title_align == ALIGN_RIGHT) {
302 h_padding = config->titlebar_h_padding;
303 } else {
304 h_padding = width - config->titlebar_h_padding - marks_buffer_width;
305 }
306
307 h_padding = MAX(h_padding, 0);
308
309 int alloc_width = MIN((int)node->width,
310 width - h_padding - config->titlebar_h_padding);
311 sway_text_node_set_max_width(node, alloc_width);
312 wlr_scene_node_set_position(node->node,
313 h_padding, (height - node->height) >> 1);
314
315 pixman_region32_union_rect(&text_area, &text_area,
316 node->node->x, node->node->y, alloc_width, node->height);
317 }
318
319 if (con->title_bar.title_text) {
320 struct sway_text_node *node = con->title_bar.title_text;
321
322 int h_padding;
323 if (title_align == ALIGN_RIGHT) {
324 h_padding = width - config->titlebar_h_padding - node->width;
325 } else if (title_align == ALIGN_CENTER) {
326 h_padding = ((int)width - marks_buffer_width - node->width) >> 1;
327 } else {
328 h_padding = config->titlebar_h_padding;
329 }
330
331 h_padding = MAX(h_padding, 0);
332
333 int alloc_width = MIN((int) node->width,
334 width - h_padding - config->titlebar_h_padding);
335 sway_text_node_set_max_width(node, alloc_width);
336 wlr_scene_node_set_position(node->node,
337 h_padding, (height - node->height) >> 1);
338
339 pixman_region32_union_rect(&text_area, &text_area,
340 node->node->x, node->node->y, alloc_width, node->height);
341 }
342
343 // silence pixman errors
344 if (width <= 0 || height <= 0) {
345 pixman_region32_fini(&text_area);
346 return;
347 }
348
349 pixman_region32_t background, border;
350
351 int thickness = config->titlebar_border_thickness;
352 pixman_region32_init_rect(&background,
353 thickness, thickness,
354 width - thickness * 2, height - thickness * 2);
355 pixman_region32_init_rect(&border, 0, 0, width, height);
356 pixman_region32_subtract(&border, &border, &background);
357
358 pixman_region32_subtract(&background, &background, &text_area);
359 pixman_region32_fini(&text_area);
360
361 update_rect_list(con->title_bar.background, &background);
362 pixman_region32_fini(&background);
363
364 update_rect_list(con->title_bar.border, &border);
365 pixman_region32_fini(&border);
366
367 container_update(con);
368}
369
370void container_update_marks(struct sway_container *con) {
371 char *buffer = NULL;
372
373 if (config->show_marks && con->marks->length) {
374 size_t len = 0;
375 for (int i = 0; i < con->marks->length; ++i) {
376 char *mark = con->marks->items[i];
377 if (mark[0] != '_') {
378 len += strlen(mark) + 2;
379 }
380 }
381 buffer = calloc(len + 1, 1);
382 char *part = malloc(len + 1);
383
384 if (!sway_assert(buffer && part, "Unable to allocate memory")) {
385 free(buffer);
386 return;
387 }
388
389 for (int i = 0; i < con->marks->length; ++i) {
390 char *mark = con->marks->items[i];
391 if (mark[0] != '_') {
392 snprintf(part, len + 1, "[%s]", mark);
393 strcat(buffer, part);
394 }
395 }
396 free(part);
397 }
398
399 if (!buffer) {
400 if (con->title_bar.marks_text) {
401 wlr_scene_node_destroy(con->title_bar.marks_text->node);
402 con->title_bar.marks_text = NULL;
403 }
404 } else if (!con->title_bar.marks_text) {
405 struct border_colors *colors = container_get_current_colors(con);
406
407 con->title_bar.marks_text = sway_text_node_create(con->title_bar.tree,
408 buffer, colors->text, false);
409 } else {
410 sway_text_node_set_text(con->title_bar.marks_text, buffer);
411 }
412
413 container_arrange_title_bar(con);
414 free(buffer);
415}
416
417void container_update_title_bar(struct sway_container *con) {
418 if (!con->formatted_title) {
419 return;
420 }
421
422 struct border_colors *colors = container_get_current_colors(con);
423
424 if (con->title_bar.title_text) {
425 wlr_scene_node_destroy(con->title_bar.title_text->node);
426 con->title_bar.title_text = NULL;
427 }
428
429 con->title_bar.title_text = sway_text_node_create(con->title_bar.tree,
430 con->formatted_title, colors->text, config->pango_markup);
431
432 // we always have to remake these text buffers completely for text font
433 // changes etc...
434 if (con->title_bar.marks_text) {
435 wlr_scene_node_destroy(con->title_bar.marks_text->node);
436 con->title_bar.marks_text = NULL;
437 }
438
439 container_update_marks(con);
440 container_arrange_title_bar(con);
441}
442
126void container_destroy(struct sway_container *con) { 443void container_destroy(struct sway_container *con) {
127 if (!sway_assert(con->node.destroying, 444 if (!sway_assert(con->node.destroying,
128 "Tried to free container which wasn't marked as destroying")) { 445 "Tried to free container which wasn't marked as destroying")) {
@@ -134,21 +451,11 @@ void container_destroy(struct sway_container *con) {
134 } 451 }
135 free(con->title); 452 free(con->title);
136 free(con->formatted_title); 453 free(con->formatted_title);
137 wlr_texture_destroy(con->title_focused);
138 wlr_texture_destroy(con->title_focused_inactive);
139 wlr_texture_destroy(con->title_unfocused);
140 wlr_texture_destroy(con->title_urgent);
141 wlr_texture_destroy(con->title_focused_tab_title);
142 list_free(con->pending.children); 454 list_free(con->pending.children);
143 list_free(con->current.children); 455 list_free(con->current.children);
144 list_free(con->outputs); 456 list_free(con->outputs);
145 457
146 list_free_items_and_destroy(con->marks); 458 list_free_items_and_destroy(con->marks);
147 wlr_texture_destroy(con->marks_focused);
148 wlr_texture_destroy(con->marks_focused_inactive);
149 wlr_texture_destroy(con->marks_unfocused);
150 wlr_texture_destroy(con->marks_urgent);
151 wlr_texture_destroy(con->marks_focused_tab_title);
152 459
153 if (con->view && con->view->container == con) { 460 if (con->view && con->view->container == con) {
154 con->view->container = NULL; 461 con->view->container = NULL;
@@ -308,108 +615,6 @@ struct sway_output *container_get_effective_output(struct sway_container *con) {
308 return con->outputs->items[con->outputs->length - 1]; 615 return con->outputs->items[con->outputs->length - 1];
309} 616}
310 617
311static void render_titlebar_text_texture(struct sway_output *output,
312 struct sway_container *con, struct wlr_texture **texture,
313 struct border_colors *class, bool pango_markup, char *text) {
314 double scale = output->wlr_output->scale;
315 int width = 0;
316 int height = config->font_height * scale;
317 int baseline;
318
319 // We must use a non-nil cairo_t for cairo_set_font_options to work.
320 // Therefore, we cannot use cairo_create(NULL).
321 cairo_surface_t *dummy_surface = cairo_image_surface_create(
322 CAIRO_FORMAT_ARGB32, 0, 0);
323 cairo_t *c = cairo_create(dummy_surface);
324 cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST);
325 cairo_font_options_t *fo = cairo_font_options_create();
326 if (output->wlr_output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) {
327 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY);
328 } else {
329 cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL);
330 cairo_font_options_set_subpixel_order(fo,
331 to_cairo_subpixel_order(output->wlr_output->subpixel));
332 }
333 cairo_set_font_options(c, fo);
334 get_text_size(c, config->font_description, &width, NULL, &baseline, scale,
335 config->pango_markup, "%s", text);
336 cairo_surface_destroy(dummy_surface);
337 cairo_destroy(c);
338
339 if (width == 0 || height == 0) {
340 return;
341 }
342
343 if (height > config->font_height * scale) {
344 height = config->font_height * scale;
345 }
346
347 cairo_surface_t *surface = cairo_image_surface_create(
348 CAIRO_FORMAT_ARGB32, width, height);
349 cairo_status_t status = cairo_surface_status(surface);
350 if (status != CAIRO_STATUS_SUCCESS) {
351 sway_log(SWAY_ERROR, "cairo_image_surface_create failed: %s",
352 cairo_status_to_string(status));
353 return;
354 }
355
356 cairo_t *cairo = cairo_create(surface);
357 cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
358 cairo_set_font_options(cairo, fo);
359 cairo_font_options_destroy(fo);
360 cairo_set_source_rgba(cairo, class->background[0], class->background[1],
361 class->background[2], class->background[3]);
362 cairo_paint(cairo);
363 PangoContext *pango = pango_cairo_create_context(cairo);
364 cairo_set_source_rgba(cairo, class->text[0], class->text[1],
365 class->text[2], class->text[3]);
366 cairo_move_to(cairo, 0, config->font_baseline * scale - baseline);
367
368 render_text(cairo, config->font_description, scale, pango_markup, "%s", text);
369
370 cairo_surface_flush(surface);
371 unsigned char *data = cairo_image_surface_get_data(surface);
372 int stride = cairo_image_surface_get_stride(surface);
373 struct wlr_renderer *renderer = output->wlr_output->renderer;
374 *texture = wlr_texture_from_pixels(
375 renderer, DRM_FORMAT_ARGB8888, stride, width, height, data);
376 cairo_surface_destroy(surface);
377 g_object_unref(pango);
378 cairo_destroy(cairo);
379}
380
381static void update_title_texture(struct sway_container *con,
382 struct wlr_texture **texture, struct border_colors *class) {
383 struct sway_output *output = container_get_effective_output(con);
384 if (!output) {
385 return;
386 }
387 if (*texture) {
388 wlr_texture_destroy(*texture);
389 *texture = NULL;
390 }
391 if (!con->formatted_title) {
392 return;
393 }
394
395 render_titlebar_text_texture(output, con, texture, class,
396 config->pango_markup, con->formatted_title);
397}
398
399void container_update_title_textures(struct sway_container *container) {
400 update_title_texture(container, &container->title_focused,
401 &config->border_colors.focused);
402 update_title_texture(container, &container->title_focused_inactive,
403 &config->border_colors.focused_inactive);
404 update_title_texture(container, &container->title_unfocused,
405 &config->border_colors.unfocused);
406 update_title_texture(container, &container->title_urgent,
407 &config->border_colors.urgent);
408 update_title_texture(container, &container->title_focused_tab_title,
409 &config->border_colors.focused_tab_title);
410 container_damage_whole(container);
411}
412
413/** 618/**
414 * Calculate and return the length of the tree representation. 619 * Calculate and return the length of the tree representation.
415 * An example tree representation is: V[Terminal, Firefox] 620 * An example tree representation is: V[Terminal, Firefox]
@@ -475,7 +680,13 @@ void container_update_representation(struct sway_container *con) {
475 } 680 }
476 container_build_representation(con->pending.layout, con->pending.children, 681 container_build_representation(con->pending.layout, con->pending.children,
477 con->formatted_title); 682 con->formatted_title);
478 container_update_title_textures(con); 683
684 if (con->title_bar.title_text) {
685 sway_text_node_set_text(con->title_bar.title_text, con->formatted_title);
686 container_arrange_title_bar(con);
687 } else {
688 container_update_title_bar(con);
689 }
479 } 690 }
480 if (con->pending.parent) { 691 if (con->pending.parent) {
481 container_update_representation(con->pending.parent); 692 container_update_representation(con->pending.parent);
@@ -761,17 +972,6 @@ bool container_is_floating(struct sway_container *container) {
761 return false; 972 return false;
762} 973}
763 974
764bool container_is_current_floating(struct sway_container *container) {
765 if (!container->current.parent && container->current.workspace &&
766 list_find(container->current.workspace->floating, container) != -1) {
767 return true;
768 }
769 if (container->scratchpad) {
770 return true;
771 }
772 return false;
773}
774
775void container_get_box(struct sway_container *container, struct wlr_box *box) { 975void container_get_box(struct sway_container *container, struct wlr_box *box) {
776 box->x = container->pending.x; 976 box->x = container->pending.x;
777 box->y = container->pending.y; 977 box->y = container->pending.y;
@@ -1092,7 +1292,6 @@ void container_discover_outputs(struct sway_container *con) {
1092 .width = con->current.width, 1292 .width = con->current.width,
1093 .height = con->current.height, 1293 .height = con->current.height,
1094 }; 1294 };
1095 struct sway_output *old_output = container_get_effective_output(con);
1096 1295
1097 for (int i = 0; i < root->outputs->length; ++i) { 1296 for (int i = 0; i < root->outputs->length; ++i) {
1098 struct sway_output *output = root->outputs->items[i]; 1297 struct sway_output *output = root->outputs->items[i];
@@ -1129,14 +1328,6 @@ void container_discover_outputs(struct sway_container *con) {
1129 list_del(con->outputs, index); 1328 list_del(con->outputs, index);
1130 } 1329 }
1131 } 1330 }
1132 struct sway_output *new_output = container_get_effective_output(con);
1133 double old_scale = old_output && old_output->enabled ?
1134 old_output->wlr_output->scale : -1;
1135 double new_scale = new_output ? new_output->wlr_output->scale : -1;
1136 if (old_scale != new_scale) {
1137 container_update_title_textures(con);
1138 container_update_marks_textures(con);
1139 }
1140} 1331}
1141 1332
1142enum sway_container_layout container_parent_layout(struct sway_container *con) { 1333enum sway_container_layout container_parent_layout(struct sway_container *con) {
@@ -1149,14 +1340,6 @@ enum sway_container_layout container_parent_layout(struct sway_container *con) {
1149 return L_NONE; 1340 return L_NONE;
1150} 1341}
1151 1342
1152enum sway_container_layout container_current_parent_layout(
1153 struct sway_container *con) {
1154 if (con->current.parent) {
1155 return con->current.parent->current.layout;
1156 }
1157 return con->current.workspace->current.layout;
1158}
1159
1160list_t *container_get_siblings(struct sway_container *container) { 1343list_t *container_get_siblings(struct sway_container *container) {
1161 if (container->pending.parent) { 1344 if (container->pending.parent) {
1162 return container->pending.parent->pending.children; 1345 return container->pending.parent->pending.children;
@@ -1174,13 +1357,6 @@ int container_sibling_index(struct sway_container *child) {
1174 return list_find(container_get_siblings(child), child); 1357 return list_find(container_get_siblings(child), child);
1175} 1358}
1176 1359
1177list_t *container_get_current_siblings(struct sway_container *container) {
1178 if (container->current.parent) {
1179 return container->current.parent->current.children;
1180 }
1181 return container->current.workspace->current.tiling;
1182}
1183
1184void container_handle_fullscreen_reparent(struct sway_container *con) { 1360void container_handle_fullscreen_reparent(struct sway_container *con) {
1185 if (con->pending.fullscreen_mode != FULLSCREEN_WORKSPACE || !con->pending.workspace || 1361 if (con->pending.fullscreen_mode != FULLSCREEN_WORKSPACE || !con->pending.workspace ||
1186 con->pending.workspace->fullscreen == con) { 1362 con->pending.workspace->fullscreen == con) {
@@ -1395,7 +1571,7 @@ bool container_find_and_unmark(char *mark) {
1395 if (strcmp(con_mark, mark) == 0) { 1571 if (strcmp(con_mark, mark) == 0) {
1396 free(con_mark); 1572 free(con_mark);
1397 list_del(con->marks, i); 1573 list_del(con->marks, i);
1398 container_update_marks_textures(con); 1574 container_update_marks(con);
1399 ipc_event_window(con, "mark"); 1575 ipc_event_window(con, "mark");
1400 return true; 1576 return true;
1401 } 1577 }
@@ -1426,70 +1602,15 @@ void container_add_mark(struct sway_container *con, char *mark) {
1426 ipc_event_window(con, "mark"); 1602 ipc_event_window(con, "mark");
1427} 1603}
1428 1604
1429static void update_marks_texture(struct sway_container *con,
1430 struct wlr_texture **texture, struct border_colors *class) {
1431 struct sway_output *output = container_get_effective_output(con);
1432 if (!output) {
1433 return;
1434 }
1435 if (*texture) {
1436 wlr_texture_destroy(*texture);
1437 *texture = NULL;
1438 }
1439 if (!con->marks->length) {
1440 return;
1441 }
1442
1443 size_t len = 0;
1444 for (int i = 0; i < con->marks->length; ++i) {
1445 char *mark = con->marks->items[i];
1446 if (mark[0] != '_') {
1447 len += strlen(mark) + 2;
1448 }
1449 }
1450 char *buffer = calloc(len + 1, 1);
1451 char *part = malloc(len + 1);
1452
1453 if (!sway_assert(buffer && part, "Unable to allocate memory")) {
1454 free(buffer);
1455 return;
1456 }
1457
1458 for (int i = 0; i < con->marks->length; ++i) {
1459 char *mark = con->marks->items[i];
1460 if (mark[0] != '_') {
1461 snprintf(part, len + 1, "[%s]", mark);
1462 strcat(buffer, part);
1463 }
1464 }
1465 free(part);
1466
1467 render_titlebar_text_texture(output, con, texture, class, false, buffer);
1468
1469 free(buffer);
1470}
1471
1472void container_update_marks_textures(struct sway_container *con) {
1473 if (!config->show_marks) {
1474 return;
1475 }
1476 update_marks_texture(con, &con->marks_focused,
1477 &config->border_colors.focused);
1478 update_marks_texture(con, &con->marks_focused_inactive,
1479 &config->border_colors.focused_inactive);
1480 update_marks_texture(con, &con->marks_unfocused,
1481 &config->border_colors.unfocused);
1482 update_marks_texture(con, &con->marks_urgent,
1483 &config->border_colors.urgent);
1484 update_marks_texture(con, &con->marks_focused_tab_title,
1485 &config->border_colors.focused_tab_title);
1486 container_damage_whole(con);
1487}
1488
1489void container_raise_floating(struct sway_container *con) { 1605void container_raise_floating(struct sway_container *con) {
1490 // Bring container to front by putting it at the end of the floating list. 1606 // Bring container to front by putting it at the end of the floating list.
1491 struct sway_container *floater = container_toplevel_ancestor(con); 1607 struct sway_container *floater = container_toplevel_ancestor(con);
1492 if (container_is_floating(floater) && floater->pending.workspace) { 1608 if (container_is_floating(floater) && floater->pending.workspace) {
1609 // it's okay to just raise the scene directly instead of waiting
1610 // for the transaction to go through. We won't be reconfiguring
1611 // surfaces
1612 wlr_scene_node_raise_to_top(&floater->scene_tree->node);
1613
1493 list_move_to_end(floater->pending.workspace->floating, floater); 1614 list_move_to_end(floater->pending.workspace->floating, floater);
1494 node_set_dirty(&floater->pending.workspace->node); 1615 node_set_dirty(&floater->pending.workspace->node);
1495 } 1616 }
diff --git a/sway/tree/view.c b/sway/tree/view.c
index d349e5fa..7af2fd3f 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -27,6 +27,7 @@
27#include "sway/scene_descriptor.h" 27#include "sway/scene_descriptor.h"
28#include "sway/server.h" 28#include "sway/server.h"
29#include "sway/surface.h" 29#include "sway/surface.h"
30#include "sway/sway_text_node.h"
30#include "sway/tree/arrange.h" 31#include "sway/tree/arrange.h"
31#include "sway/tree/container.h" 32#include "sway/tree/container.h"
32#include "sway/tree/view.h" 33#include "sway/tree/view.h"
@@ -1337,7 +1338,13 @@ void view_update_title(struct sway_view *view, bool force) {
1337 view->container->title = title ? strdup(title) : NULL; 1338 view->container->title = title ? strdup(title) : NULL;
1338 1339
1339 // Update title after the global font height is updated 1340 // Update title after the global font height is updated
1340 container_update_title_textures(view->container); 1341 if (view->container->title_bar.title_text && len) {
1342 sway_text_node_set_text(view->container->title_bar.title_text,
1343 view->container->formatted_title);
1344 container_arrange_title_bar(view->container);
1345 } else {
1346 container_update_title_bar(view->container);
1347 }
1341 1348
1342 ipc_event_window(view->container, "title"); 1349 ipc_event_window(view->container, "title");
1343 1350
@@ -1404,6 +1411,7 @@ void view_set_urgent(struct sway_view *view, bool enable) {
1404 return; 1411 return;
1405 } 1412 }
1406 clock_gettime(CLOCK_MONOTONIC, &view->urgent); 1413 clock_gettime(CLOCK_MONOTONIC, &view->urgent);
1414 container_update_itself_and_parents(view->container);
1407 } else { 1415 } else {
1408 view->urgent = (struct timespec){ 0 }; 1416 view->urgent = (struct timespec){ 0 };
1409 if (view->urgent_timer) { 1417 if (view->urgent_timer) {