diff options
author | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-09-24 20:54:57 +1000 |
---|---|---|
committer | Ryan Dwyer <ryandwyer1@gmail.com> | 2018-09-27 22:51:37 +1000 |
commit | 7b138e5ef0f679c9bb0078019d7c9c63fef36273 (patch) | |
tree | 2cdbeb394889065e0606a1fcbe38c1e99e25d260 | |
parent | Merge pull request #2717 from ianyfan/tablet-config (diff) | |
download | sway-7b138e5ef0f679c9bb0078019d7c9c63fef36273.tar.gz sway-7b138e5ef0f679c9bb0078019d7c9c63fef36273.tar.zst sway-7b138e5ef0f679c9bb0078019d7c9c63fef36273.zip |
Add CSD to border modes
This replaces view.using_csd with a new border mode: B_CSD. This also
removes sway_xdg_shell{_v6}_view.deco_mode and
view->has_client_side_decorations as we can now get these from the
border.
You can use `border toggle` to cycle through the modes including CSD, or
use `border csd` to set it directly. The client must support the
xdg-decoration protocol, and the only client I know of that does is the
example in wlroots.
If the client switches from SSD to CSD without us expecting it (via the
server-decoration protocol), we stash the previous border type into
view.saved_border so we can restore it if the client returns to SSD. I
haven't found a way to test this though.
-rw-r--r-- | include/sway/server.h | 5 | ||||
-rw-r--r-- | include/sway/tree/container.h | 2 | ||||
-rw-r--r-- | include/sway/tree/view.h | 21 | ||||
-rw-r--r-- | include/sway/xdg_decoration.h | 19 | ||||
-rw-r--r-- | sway/commands/border.c | 21 | ||||
-rw-r--r-- | sway/decoration.c | 22 | ||||
-rw-r--r-- | sway/desktop/render.c | 108 | ||||
-rw-r--r-- | sway/desktop/transaction.c | 1 | ||||
-rw-r--r-- | sway/desktop/xdg_shell.c | 22 | ||||
-rw-r--r-- | sway/desktop/xdg_shell_v6.c | 22 | ||||
-rw-r--r-- | sway/desktop/xwayland.c | 20 | ||||
-rw-r--r-- | sway/input/cursor.c | 3 | ||||
-rw-r--r-- | sway/ipc-json.c | 2 | ||||
-rw-r--r-- | sway/meson.build | 1 | ||||
-rw-r--r-- | sway/server.c | 9 | ||||
-rw-r--r-- | sway/tree/container.c | 2 | ||||
-rw-r--r-- | sway/tree/view.c | 37 | ||||
-rw-r--r-- | sway/xdg_decoration.c | 73 |
18 files changed, 250 insertions, 140 deletions
diff --git a/include/sway/server.h b/include/sway/server.h index 5dabb61f..3e1cbb33 100644 --- a/include/sway/server.h +++ b/include/sway/server.h | |||
@@ -54,6 +54,10 @@ struct sway_server { | |||
54 | struct wl_listener server_decoration; | 54 | struct wl_listener server_decoration; |
55 | struct wl_list decorations; // sway_server_decoration::link | 55 | struct wl_list decorations; // sway_server_decoration::link |
56 | 56 | ||
57 | struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager; | ||
58 | struct wl_listener xdg_decoration; | ||
59 | struct wl_list xdg_decorations; // sway_xdg_decoration::link | ||
60 | |||
57 | size_t txn_timeout_ms; | 61 | size_t txn_timeout_ms; |
58 | list_t *transactions; | 62 | list_t *transactions; |
59 | list_t *dirty_nodes; | 63 | list_t *dirty_nodes; |
@@ -78,5 +82,6 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data); | |||
78 | void handle_xwayland_surface(struct wl_listener *listener, void *data); | 82 | void handle_xwayland_surface(struct wl_listener *listener, void *data); |
79 | #endif | 83 | #endif |
80 | void handle_server_decoration(struct wl_listener *listener, void *data); | 84 | void handle_server_decoration(struct wl_listener *listener, void *data); |
85 | void handle_xdg_decoration(struct wl_listener *listener, void *data); | ||
81 | 86 | ||
82 | #endif | 87 | #endif |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 5e281a2f..6019602c 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -28,6 +28,7 @@ enum sway_container_border { | |||
28 | B_NONE, | 28 | B_NONE, |
29 | B_PIXEL, | 29 | B_PIXEL, |
30 | B_NORMAL, | 30 | B_NORMAL, |
31 | B_CSD, | ||
31 | }; | 32 | }; |
32 | 33 | ||
33 | struct sway_root; | 34 | struct sway_root; |
@@ -63,7 +64,6 @@ struct sway_container_state { | |||
63 | bool border_bottom; | 64 | bool border_bottom; |
64 | bool border_left; | 65 | bool border_left; |
65 | bool border_right; | 66 | bool border_right; |
66 | bool using_csd; | ||
67 | }; | 67 | }; |
68 | 68 | ||
69 | struct sway_container { | 69 | struct sway_container { |
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index d10251dd..49df7c88 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "sway/input/seat.h" | 11 | #include "sway/input/seat.h" |
12 | 12 | ||
13 | struct sway_container; | 13 | struct sway_container; |
14 | struct sway_xdg_decoration; | ||
14 | 15 | ||
15 | enum sway_view_type { | 16 | enum sway_view_type { |
16 | SWAY_VIEW_XDG_SHELL_V6, | 17 | SWAY_VIEW_XDG_SHELL_V6, |
@@ -44,7 +45,6 @@ struct sway_view_impl { | |||
44 | void (*set_tiled)(struct sway_view *view, bool tiled); | 45 | void (*set_tiled)(struct sway_view *view, bool tiled); |
45 | void (*set_fullscreen)(struct sway_view *view, bool fullscreen); | 46 | void (*set_fullscreen)(struct sway_view *view, bool fullscreen); |
46 | bool (*wants_floating)(struct sway_view *view); | 47 | bool (*wants_floating)(struct sway_view *view); |
47 | bool (*has_client_side_decorations)(struct sway_view *view); | ||
48 | void (*for_each_surface)(struct sway_view *view, | 48 | void (*for_each_surface)(struct sway_view *view, |
49 | wlr_surface_iterator_func_t iterator, void *user_data); | 49 | wlr_surface_iterator_func_t iterator, void *user_data); |
50 | void (*for_each_popup)(struct sway_view *view, | 50 | void (*for_each_popup)(struct sway_view *view, |
@@ -60,6 +60,7 @@ struct sway_view { | |||
60 | 60 | ||
61 | struct sway_container *container; // NULL if unmapped and transactions finished | 61 | struct sway_container *container; // NULL if unmapped and transactions finished |
62 | struct wlr_surface *surface; // NULL for unmapped views | 62 | struct wlr_surface *surface; // NULL for unmapped views |
63 | struct sway_xdg_decoration *xdg_decoration; | ||
63 | 64 | ||
64 | pid_t pid; | 65 | pid_t pid; |
65 | 66 | ||
@@ -76,12 +77,12 @@ struct sway_view { | |||
76 | 77 | ||
77 | char *title_format; | 78 | char *title_format; |
78 | enum sway_container_border border; | 79 | enum sway_container_border border; |
80 | enum sway_container_border saved_border; | ||
79 | int border_thickness; | 81 | int border_thickness; |
80 | bool border_top; | 82 | bool border_top; |
81 | bool border_bottom; | 83 | bool border_bottom; |
82 | bool border_left; | 84 | bool border_left; |
83 | bool border_right; | 85 | bool border_right; |
84 | bool using_csd; | ||
85 | 86 | ||
86 | struct timespec urgent; | 87 | struct timespec urgent; |
87 | bool allow_request_urgent; | 88 | bool allow_request_urgent; |
@@ -127,8 +128,6 @@ struct sway_view { | |||
127 | struct sway_xdg_shell_v6_view { | 128 | struct sway_xdg_shell_v6_view { |
128 | struct sway_view view; | 129 | struct sway_view view; |
129 | 130 | ||
130 | enum wlr_server_decoration_manager_mode deco_mode; | ||
131 | |||
132 | struct wl_listener commit; | 131 | struct wl_listener commit; |
133 | struct wl_listener request_move; | 132 | struct wl_listener request_move; |
134 | struct wl_listener request_resize; | 133 | struct wl_listener request_resize; |
@@ -145,8 +144,6 @@ struct sway_xdg_shell_v6_view { | |||
145 | struct sway_xdg_shell_view { | 144 | struct sway_xdg_shell_view { |
146 | struct sway_view view; | 145 | struct sway_view view; |
147 | 146 | ||
148 | enum wlr_server_decoration_manager_mode deco_mode; | ||
149 | |||
150 | struct wl_listener commit; | 147 | struct wl_listener commit; |
151 | struct wl_listener request_move; | 148 | struct wl_listener request_move; |
152 | struct wl_listener request_resize; | 149 | struct wl_listener request_resize; |
@@ -175,6 +172,7 @@ struct sway_xwayland_view { | |||
175 | struct wl_listener set_role; | 172 | struct wl_listener set_role; |
176 | struct wl_listener set_window_type; | 173 | struct wl_listener set_window_type; |
177 | struct wl_listener set_hints; | 174 | struct wl_listener set_hints; |
175 | struct wl_listener set_decorations; | ||
178 | struct wl_listener map; | 176 | struct wl_listener map; |
179 | struct wl_listener unmap; | 177 | struct wl_listener unmap; |
180 | struct wl_listener destroy; | 178 | struct wl_listener destroy; |
@@ -268,6 +266,17 @@ void view_set_activated(struct sway_view *view, bool activated); | |||
268 | */ | 266 | */ |
269 | void view_request_activate(struct sway_view *view); | 267 | void view_request_activate(struct sway_view *view); |
270 | 268 | ||
269 | /** | ||
270 | * If possible, instructs the client to change their decoration mode. | ||
271 | */ | ||
272 | void view_set_csd_from_server(struct sway_view *view, bool enabled); | ||
273 | |||
274 | /** | ||
275 | * Updates the view's border setting when the client unexpectedly changes their | ||
276 | * decoration mode. | ||
277 | */ | ||
278 | void view_set_csd_from_client(struct sway_view *view, bool enabled); | ||
279 | |||
271 | void view_set_tiled(struct sway_view *view, bool tiled); | 280 | void view_set_tiled(struct sway_view *view, bool tiled); |
272 | 281 | ||
273 | void view_close(struct sway_view *view); | 282 | void view_close(struct sway_view *view); |
diff --git a/include/sway/xdg_decoration.h b/include/sway/xdg_decoration.h new file mode 100644 index 00000000..46fb8d34 --- /dev/null +++ b/include/sway/xdg_decoration.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef _SWAY_XDG_DECORATION_H | ||
2 | #define _SWAY_XDG_DECORATION_H | ||
3 | |||
4 | #include <wlr/types/wlr_xdg_decoration_v1.h> | ||
5 | |||
6 | struct sway_xdg_decoration { | ||
7 | struct wlr_xdg_toplevel_decoration_v1 *wlr_xdg_decoration; | ||
8 | struct wl_list link; | ||
9 | |||
10 | struct sway_view *view; | ||
11 | |||
12 | struct wl_listener destroy; | ||
13 | struct wl_listener surface_commit; | ||
14 | }; | ||
15 | |||
16 | struct sway_xdg_decoration *xdg_decoration_from_surface( | ||
17 | struct wlr_surface *surface); | ||
18 | |||
19 | #endif | ||
diff --git a/sway/commands/border.c b/sway/commands/border.c index 95498b2f..673fea08 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c | |||
@@ -7,6 +7,17 @@ | |||
7 | #include "sway/tree/container.h" | 7 | #include "sway/tree/container.h" |
8 | #include "sway/tree/view.h" | 8 | #include "sway/tree/view.h" |
9 | 9 | ||
10 | static void set_border(struct sway_view *view, | ||
11 | enum sway_container_border new_border) { | ||
12 | if (view->border == B_CSD && new_border != B_CSD) { | ||
13 | view_set_csd_from_server(view, false); | ||
14 | } else if (view->border != B_CSD && new_border == B_CSD) { | ||
15 | view_set_csd_from_server(view, true); | ||
16 | } | ||
17 | view->saved_border = view->border; | ||
18 | view->border = new_border; | ||
19 | } | ||
20 | |||
10 | struct cmd_results *cmd_border(int argc, char **argv) { | 21 | struct cmd_results *cmd_border(int argc, char **argv) { |
11 | struct cmd_results *error = NULL; | 22 | struct cmd_results *error = NULL; |
12 | if ((error = checkarg(argc, "border", EXPECTED_AT_LEAST, 1))) { | 23 | if ((error = checkarg(argc, "border", EXPECTED_AT_LEAST, 1))) { |
@@ -21,13 +32,15 @@ struct cmd_results *cmd_border(int argc, char **argv) { | |||
21 | struct sway_view *view = container->view; | 32 | struct sway_view *view = container->view; |
22 | 33 | ||
23 | if (strcmp(argv[0], "none") == 0) { | 34 | if (strcmp(argv[0], "none") == 0) { |
24 | view->border = B_NONE; | 35 | set_border(view, B_NONE); |
25 | } else if (strcmp(argv[0], "normal") == 0) { | 36 | } else if (strcmp(argv[0], "normal") == 0) { |
26 | view->border = B_NORMAL; | 37 | set_border(view, B_NORMAL); |
27 | } else if (strcmp(argv[0], "pixel") == 0) { | 38 | } else if (strcmp(argv[0], "pixel") == 0) { |
28 | view->border = B_PIXEL; | 39 | set_border(view, B_PIXEL); |
40 | } else if (strcmp(argv[0], "csd") == 0) { | ||
41 | set_border(view, B_CSD); | ||
29 | } else if (strcmp(argv[0], "toggle") == 0) { | 42 | } else if (strcmp(argv[0], "toggle") == 0) { |
30 | view->border = (view->border + 1) % 3; | 43 | set_border(view, (view->border + 1) % 4); |
31 | } else { | 44 | } else { |
32 | return cmd_results_new(CMD_INVALID, "border", | 45 | return cmd_results_new(CMD_INVALID, "border", |
33 | "Expected 'border <none|normal|pixel|toggle>' " | 46 | "Expected 'border <none|normal|pixel|toggle>' " |
diff --git a/sway/decoration.c b/sway/decoration.c index 0e3e67ac..fea6ed4c 100644 --- a/sway/decoration.c +++ b/sway/decoration.c | |||
@@ -1,6 +1,8 @@ | |||
1 | #include <stdlib.h> | 1 | #include <stdlib.h> |
2 | #include "sway/decoration.h" | 2 | #include "sway/decoration.h" |
3 | #include "sway/desktop/transaction.h" | ||
3 | #include "sway/server.h" | 4 | #include "sway/server.h" |
5 | #include "sway/tree/arrange.h" | ||
4 | #include "sway/tree/view.h" | 6 | #include "sway/tree/view.h" |
5 | #include "log.h" | 7 | #include "log.h" |
6 | 8 | ||
@@ -24,20 +26,12 @@ static void server_decoration_handle_mode(struct wl_listener *listener, | |||
24 | return; | 26 | return; |
25 | } | 27 | } |
26 | 28 | ||
27 | switch (view->type) { | 29 | bool csd = deco->wlr_server_decoration->mode == |
28 | case SWAY_VIEW_XDG_SHELL_V6:; | 30 | WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; |
29 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = | 31 | view_set_csd_from_client(view, csd); |
30 | (struct sway_xdg_shell_v6_view *)view; | 32 | |
31 | xdg_shell_v6_view->deco_mode = deco->wlr_server_decoration->mode; | 33 | arrange_container(view->container); |
32 | break; | 34 | transaction_commit_dirty(); |
33 | case SWAY_VIEW_XDG_SHELL:; | ||
34 | struct sway_xdg_shell_view *xdg_shell_view = | ||
35 | (struct sway_xdg_shell_view *)view; | ||
36 | xdg_shell_view->deco_mode = deco->wlr_server_decoration->mode; | ||
37 | break; | ||
38 | default: | ||
39 | break; | ||
40 | } | ||
41 | } | 35 | } |
42 | 36 | ||
43 | void handle_server_decoration(struct wl_listener *listener, void *data) { | 37 | void handle_server_decoration(struct wl_listener *listener, void *data) { |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index af4e2905..c8b08a58 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -272,7 +272,7 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
272 | render_view_toplevels(view, output, damage, view->container->alpha); | 272 | render_view_toplevels(view, output, damage, view->container->alpha); |
273 | } | 273 | } |
274 | 274 | ||
275 | if (view->container->current.using_csd) { | 275 | if (con->current.border == B_NONE || con->current.border == B_CSD) { |
276 | return; | 276 | return; |
277 | } | 277 | } |
278 | 278 | ||
@@ -281,51 +281,49 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
281 | float color[4]; | 281 | float color[4]; |
282 | struct sway_container_state *state = &con->current; | 282 | struct sway_container_state *state = &con->current; |
283 | 283 | ||
284 | if (state->border != B_NONE) { | 284 | if (state->border_left) { |
285 | if (state->border_left) { | 285 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
286 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 286 | premultiply_alpha(color, con->alpha); |
287 | premultiply_alpha(color, con->alpha); | 287 | box.x = state->con_x; |
288 | box.x = state->con_x; | 288 | box.y = state->view_y; |
289 | box.y = state->view_y; | 289 | box.width = state->border_thickness; |
290 | box.width = state->border_thickness; | 290 | box.height = state->view_height; |
291 | box.height = state->view_height; | 291 | scale_box(&box, output_scale); |
292 | scale_box(&box, output_scale); | 292 | render_rect(output->wlr_output, damage, &box, color); |
293 | render_rect(output->wlr_output, damage, &box, color); | 293 | } |
294 | } | ||
295 | 294 | ||
296 | list_t *siblings = container_get_current_siblings(con); | 295 | list_t *siblings = container_get_current_siblings(con); |
297 | enum sway_container_layout layout = | 296 | enum sway_container_layout layout = |
298 | container_current_parent_layout(con); | 297 | container_current_parent_layout(con); |
299 | 298 | ||
300 | if (state->border_right) { | 299 | if (state->border_right) { |
301 | if (siblings->length == 1 && layout == L_HORIZ) { | 300 | if (siblings->length == 1 && layout == L_HORIZ) { |
302 | memcpy(&color, colors->indicator, sizeof(float) * 4); | 301 | memcpy(&color, colors->indicator, sizeof(float) * 4); |
303 | } else { | 302 | } else { |
304 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 303 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
305 | } | ||
306 | premultiply_alpha(color, con->alpha); | ||
307 | box.x = state->view_x + state->view_width; | ||
308 | box.y = state->view_y; | ||
309 | box.width = state->border_thickness; | ||
310 | box.height = state->view_height; | ||
311 | scale_box(&box, output_scale); | ||
312 | render_rect(output->wlr_output, damage, &box, color); | ||
313 | } | 304 | } |
305 | premultiply_alpha(color, con->alpha); | ||
306 | box.x = state->view_x + state->view_width; | ||
307 | box.y = state->view_y; | ||
308 | box.width = state->border_thickness; | ||
309 | box.height = state->view_height; | ||
310 | scale_box(&box, output_scale); | ||
311 | render_rect(output->wlr_output, damage, &box, color); | ||
312 | } | ||
314 | 313 | ||
315 | if (state->border_bottom) { | 314 | if (state->border_bottom) { |
316 | if (siblings->length == 1 && layout == L_VERT) { | 315 | if (siblings->length == 1 && layout == L_VERT) { |
317 | memcpy(&color, colors->indicator, sizeof(float) * 4); | 316 | memcpy(&color, colors->indicator, sizeof(float) * 4); |
318 | } else { | 317 | } else { |
319 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 318 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
320 | } | ||
321 | premultiply_alpha(color, con->alpha); | ||
322 | box.x = state->con_x; | ||
323 | box.y = state->view_y + state->view_height; | ||
324 | box.width = state->con_width; | ||
325 | box.height = state->border_thickness; | ||
326 | scale_box(&box, output_scale); | ||
327 | render_rect(output->wlr_output, damage, &box, color); | ||
328 | } | 319 | } |
320 | premultiply_alpha(color, con->alpha); | ||
321 | box.x = state->con_x; | ||
322 | box.y = state->view_y + state->view_height; | ||
323 | box.width = state->con_width; | ||
324 | box.height = state->border_thickness; | ||
325 | scale_box(&box, output_scale); | ||
326 | render_rect(output->wlr_output, damage, &box, color); | ||
329 | } | 327 | } |
330 | } | 328 | } |
331 | 329 | ||
@@ -645,14 +643,12 @@ static void render_containers_linear(struct sway_output *output, | |||
645 | marks_texture = view->marks_unfocused; | 643 | marks_texture = view->marks_unfocused; |
646 | } | 644 | } |
647 | 645 | ||
648 | if (!view->container->current.using_csd) { | 646 | if (state->border == B_NORMAL) { |
649 | if (state->border == B_NORMAL) { | 647 | render_titlebar(output, damage, child, state->con_x, |
650 | render_titlebar(output, damage, child, state->con_x, | 648 | state->con_y, state->con_width, colors, |
651 | state->con_y, state->con_width, colors, | 649 | title_texture, marks_texture); |
652 | title_texture, marks_texture); | 650 | } else if (state->border == B_PIXEL) { |
653 | } else { | 651 | render_top_border(output, damage, child, colors); |
654 | render_top_border(output, damage, child, colors); | ||
655 | } | ||
656 | } | 652 | } |
657 | render_view(output, damage, child, colors); | 653 | render_view(output, damage, child, colors); |
658 | } else { | 654 | } else { |
@@ -859,14 +855,12 @@ static void render_floating_container(struct sway_output *soutput, | |||
859 | marks_texture = view->marks_unfocused; | 855 | marks_texture = view->marks_unfocused; |
860 | } | 856 | } |
861 | 857 | ||
862 | if (!view->container->current.using_csd) { | 858 | if (con->current.border == B_NORMAL) { |
863 | if (con->current.border == B_NORMAL) { | 859 | render_titlebar(soutput, damage, con, con->current.con_x, |
864 | render_titlebar(soutput, damage, con, con->current.con_x, | 860 | con->current.con_y, con->current.con_width, colors, |
865 | con->current.con_y, con->current.con_width, colors, | 861 | title_texture, marks_texture); |
866 | title_texture, marks_texture); | 862 | } else if (con->current.border == B_PIXEL) { |
867 | } else if (con->current.border != B_NONE) { | 863 | render_top_border(soutput, damage, con, colors); |
868 | render_top_border(soutput, damage, con, colors); | ||
869 | } | ||
870 | } | 864 | } |
871 | render_view(soutput, damage, con, colors); | 865 | render_view(soutput, damage, con, colors); |
872 | } else { | 866 | } else { |
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 797f6b4c..4624d824 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -167,7 +167,6 @@ static void copy_container_state(struct sway_container *container, | |||
167 | state->border_left = view->border_left; | 167 | state->border_left = view->border_left; |
168 | state->border_right = view->border_right; | 168 | state->border_right = view->border_right; |
169 | state->border_bottom = view->border_bottom; | 169 | state->border_bottom = view->border_bottom; |
170 | state->using_csd = view->using_csd; | ||
171 | } else { | 170 | } else { |
172 | state->children = create_list(); | 171 | state->children = create_list(); |
173 | list_cat(state->children, container->children); | 172 | list_cat(state->children, container->children); |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 6d1ccdd7..d563edae 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -175,15 +175,6 @@ static bool wants_floating(struct sway_view *view) { | |||
175 | || toplevel->parent; | 175 | || toplevel->parent; |
176 | } | 176 | } |
177 | 177 | ||
178 | static bool has_client_side_decorations(struct sway_view *view) { | ||
179 | struct sway_xdg_shell_view *xdg_shell_view = | ||
180 | xdg_shell_view_from_view(view); | ||
181 | if (xdg_shell_view == NULL) { | ||
182 | return true; | ||
183 | } | ||
184 | return xdg_shell_view->deco_mode != WLR_SERVER_DECORATION_MANAGER_MODE_SERVER; | ||
185 | } | ||
186 | |||
187 | static void for_each_surface(struct sway_view *view, | 178 | static void for_each_surface(struct sway_view *view, |
188 | wlr_surface_iterator_func_t iterator, void *user_data) { | 179 | wlr_surface_iterator_func_t iterator, void *user_data) { |
189 | if (xdg_shell_view_from_view(view) == NULL) { | 180 | if (xdg_shell_view_from_view(view) == NULL) { |
@@ -240,7 +231,6 @@ static const struct sway_view_impl view_impl = { | |||
240 | .set_tiled = set_tiled, | 231 | .set_tiled = set_tiled, |
241 | .set_fullscreen = set_fullscreen, | 232 | .set_fullscreen = set_fullscreen, |
242 | .wants_floating = wants_floating, | 233 | .wants_floating = wants_floating, |
243 | .has_client_side_decorations = has_client_side_decorations, | ||
244 | .for_each_surface = for_each_surface, | 234 | .for_each_surface = for_each_surface, |
245 | .for_each_popup = for_each_popup, | 235 | .for_each_popup = for_each_popup, |
246 | .close = _close, | 236 | .close = _close, |
@@ -385,15 +375,13 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
385 | view->natural_height = view->wlr_xdg_surface->surface->current.height; | 375 | view->natural_height = view->wlr_xdg_surface->surface->current.height; |
386 | } | 376 | } |
387 | 377 | ||
378 | view_map(view, view->wlr_xdg_surface->surface); | ||
379 | |||
388 | struct sway_server_decoration *deco = | 380 | struct sway_server_decoration *deco = |
389 | decoration_from_surface(xdg_surface->surface); | 381 | decoration_from_surface(xdg_surface->surface); |
390 | if (deco != NULL) { | 382 | bool csd = !deco || deco->wlr_server_decoration->mode == |
391 | xdg_shell_view->deco_mode = deco->wlr_server_decoration->mode; | 383 | WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; |
392 | } else { | 384 | view_set_csd_from_client(view, csd); |
393 | xdg_shell_view->deco_mode = WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; | ||
394 | } | ||
395 | |||
396 | view_map(view, view->wlr_xdg_surface->surface); | ||
397 | 385 | ||
398 | if (xdg_surface->toplevel->client_pending.fullscreen) { | 386 | if (xdg_surface->toplevel->client_pending.fullscreen) { |
399 | container_set_fullscreen(view->container, true); | 387 | container_set_fullscreen(view->container, true); |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 95ca396c..8c8085f7 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -171,15 +171,6 @@ static bool wants_floating(struct sway_view *view) { | |||
171 | || toplevel->parent; | 171 | || toplevel->parent; |
172 | } | 172 | } |
173 | 173 | ||
174 | static bool has_client_side_decorations(struct sway_view *view) { | ||
175 | struct sway_xdg_shell_v6_view *xdg_shell_v6_view = | ||
176 | xdg_shell_v6_view_from_view(view); | ||
177 | if (xdg_shell_v6_view == NULL) { | ||
178 | return true; | ||
179 | } | ||
180 | return xdg_shell_v6_view->deco_mode != WLR_SERVER_DECORATION_MANAGER_MODE_SERVER; | ||
181 | } | ||
182 | |||
183 | static void for_each_surface(struct sway_view *view, | 174 | static void for_each_surface(struct sway_view *view, |
184 | wlr_surface_iterator_func_t iterator, void *user_data) { | 175 | wlr_surface_iterator_func_t iterator, void *user_data) { |
185 | if (xdg_shell_v6_view_from_view(view) == NULL) { | 176 | if (xdg_shell_v6_view_from_view(view) == NULL) { |
@@ -237,7 +228,6 @@ static const struct sway_view_impl view_impl = { | |||
237 | .set_tiled = set_tiled, | 228 | .set_tiled = set_tiled, |
238 | .set_fullscreen = set_fullscreen, | 229 | .set_fullscreen = set_fullscreen, |
239 | .wants_floating = wants_floating, | 230 | .wants_floating = wants_floating, |
240 | .has_client_side_decorations = has_client_side_decorations, | ||
241 | .for_each_surface = for_each_surface, | 231 | .for_each_surface = for_each_surface, |
242 | .for_each_popup = for_each_popup, | 232 | .for_each_popup = for_each_popup, |
243 | .close = _close, | 233 | .close = _close, |
@@ -382,15 +372,13 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
382 | view->natural_height = view->wlr_xdg_surface_v6->surface->current.height; | 372 | view->natural_height = view->wlr_xdg_surface_v6->surface->current.height; |
383 | } | 373 | } |
384 | 374 | ||
375 | view_map(view, view->wlr_xdg_surface_v6->surface); | ||
376 | |||
385 | struct sway_server_decoration *deco = | 377 | struct sway_server_decoration *deco = |
386 | decoration_from_surface(xdg_surface->surface); | 378 | decoration_from_surface(xdg_surface->surface); |
387 | if (deco != NULL) { | 379 | bool csd = !deco || deco->wlr_server_decoration->mode == |
388 | xdg_shell_v6_view->deco_mode = deco->wlr_server_decoration->mode; | 380 | WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; |
389 | } else { | 381 | view_set_csd_from_client(view, csd); |
390 | xdg_shell_v6_view->deco_mode = WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; | ||
391 | } | ||
392 | |||
393 | view_map(view, view->wlr_xdg_surface_v6->surface); | ||
394 | 382 | ||
395 | if (xdg_surface->toplevel->client_pending.fullscreen) { | 383 | if (xdg_surface->toplevel->client_pending.fullscreen) { |
396 | container_set_fullscreen(view->container, true); | 384 | container_set_fullscreen(view->container, true); |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index a12ac854..f1205518 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -243,12 +243,14 @@ static bool wants_floating(struct sway_view *view) { | |||
243 | return false; | 243 | return false; |
244 | } | 244 | } |
245 | 245 | ||
246 | static bool has_client_side_decorations(struct sway_view *view) { | 246 | static void handle_set_decorations(struct wl_listener *listener, void *data) { |
247 | if (xwayland_view_from_view(view) == NULL) { | 247 | struct sway_xwayland_view *xwayland_view = |
248 | return false; | 248 | wl_container_of(listener, xwayland_view, set_decorations); |
249 | } | 249 | struct sway_view *view = &xwayland_view->view; |
250 | struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; | 250 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
251 | return surface->decorations != WLR_XWAYLAND_SURFACE_DECORATIONS_ALL; | 251 | |
252 | bool csd = xsurface->decorations != WLR_XWAYLAND_SURFACE_DECORATIONS_ALL; | ||
253 | view_set_csd_from_client(view, csd); | ||
252 | } | 254 | } |
253 | 255 | ||
254 | static void _close(struct sway_view *view) { | 256 | static void _close(struct sway_view *view) { |
@@ -274,7 +276,6 @@ static const struct sway_view_impl view_impl = { | |||
274 | .set_tiled = set_tiled, | 276 | .set_tiled = set_tiled, |
275 | .set_fullscreen = set_fullscreen, | 277 | .set_fullscreen = set_fullscreen, |
276 | .wants_floating = wants_floating, | 278 | .wants_floating = wants_floating, |
277 | .has_client_side_decorations = has_client_side_decorations, | ||
278 | .close = _close, | 279 | .close = _close, |
279 | .destroy = destroy, | 280 | .destroy = destroy, |
280 | }; | 281 | }; |
@@ -343,6 +344,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { | |||
343 | wl_list_remove(&xwayland_view->set_role.link); | 344 | wl_list_remove(&xwayland_view->set_role.link); |
344 | wl_list_remove(&xwayland_view->set_window_type.link); | 345 | wl_list_remove(&xwayland_view->set_window_type.link); |
345 | wl_list_remove(&xwayland_view->set_hints.link); | 346 | wl_list_remove(&xwayland_view->set_hints.link); |
347 | wl_list_remove(&xwayland_view->set_decorations.link); | ||
346 | wl_list_remove(&xwayland_view->map.link); | 348 | wl_list_remove(&xwayland_view->map.link); |
347 | wl_list_remove(&xwayland_view->unmap.link); | 349 | wl_list_remove(&xwayland_view->unmap.link); |
348 | view_begin_destroy(&xwayland_view->view); | 350 | view_begin_destroy(&xwayland_view->view); |
@@ -613,6 +615,10 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { | |||
613 | wl_signal_add(&xsurface->events.set_hints, &xwayland_view->set_hints); | 615 | wl_signal_add(&xsurface->events.set_hints, &xwayland_view->set_hints); |
614 | xwayland_view->set_hints.notify = handle_set_hints; | 616 | xwayland_view->set_hints.notify = handle_set_hints; |
615 | 617 | ||
618 | wl_signal_add(&xsurface->events.set_decorations, | ||
619 | &xwayland_view->set_decorations); | ||
620 | xwayland_view->set_decorations.notify = handle_set_decorations; | ||
621 | |||
616 | wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); | 622 | wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap); |
617 | xwayland_view->unmap.notify = handle_unmap; | 623 | xwayland_view->unmap.notify = handle_unmap; |
618 | 624 | ||
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index aa0e07f5..eab102fd 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -175,7 +175,8 @@ static enum wlr_edges find_edge(struct sway_container *cont, | |||
175 | return WLR_EDGE_NONE; | 175 | return WLR_EDGE_NONE; |
176 | } | 176 | } |
177 | struct sway_view *view = cont->view; | 177 | struct sway_view *view = cont->view; |
178 | if (view->border == B_NONE || !view->border_thickness || view->using_csd) { | 178 | if (view->border == B_NONE || !view->border_thickness || |
179 | view->border == B_CSD) { | ||
179 | return WLR_EDGE_NONE; | 180 | return WLR_EDGE_NONE; |
180 | } | 181 | } |
181 | 182 | ||
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index f054ac9f..df24b812 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -216,6 +216,8 @@ static const char *describe_container_border(enum sway_container_border border) | |||
216 | return "pixel"; | 216 | return "pixel"; |
217 | case B_NORMAL: | 217 | case B_NORMAL: |
218 | return "normal"; | 218 | return "normal"; |
219 | case B_CSD: | ||
220 | return "csd"; | ||
219 | } | 221 | } |
220 | return "unknown"; | 222 | return "unknown"; |
221 | } | 223 | } |
diff --git a/sway/meson.build b/sway/meson.build index d67a4c64..2a3c5b5e 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -10,6 +10,7 @@ sway_sources = files( | |||
10 | 'security.c', | 10 | 'security.c', |
11 | 'server.c', | 11 | 'server.c', |
12 | 'swaynag.c', | 12 | 'swaynag.c', |
13 | 'xdg_decoration.c', | ||
13 | 14 | ||
14 | 'desktop/desktop.c', | 15 | 'desktop/desktop.c', |
15 | 'desktop/idle_inhibit_v1.c', | 16 | 'desktop/idle_inhibit_v1.c', |
diff --git a/sway/server.c b/sway/server.c index bed5aed1..63bfa7e1 100644 --- a/sway/server.c +++ b/sway/server.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <wlr/types/wlr_screencopy_v1.h> | 16 | #include <wlr/types/wlr_screencopy_v1.h> |
17 | #include <wlr/types/wlr_server_decoration.h> | 17 | #include <wlr/types/wlr_server_decoration.h> |
18 | #include <wlr/types/wlr_xcursor_manager.h> | 18 | #include <wlr/types/wlr_xcursor_manager.h> |
19 | #include <wlr/types/wlr_xdg_decoration_v1.h> | ||
19 | #include <wlr/types/wlr_xdg_output_v1.h> | 20 | #include <wlr/types/wlr_xdg_output_v1.h> |
20 | #include <wlr/util/log.h> | 21 | #include <wlr/util/log.h> |
21 | #include "list.h" | 22 | #include "list.h" |
@@ -115,6 +116,14 @@ bool server_init(struct sway_server *server) { | |||
115 | server->server_decoration.notify = handle_server_decoration; | 116 | server->server_decoration.notify = handle_server_decoration; |
116 | wl_list_init(&server->decorations); | 117 | wl_list_init(&server->decorations); |
117 | 118 | ||
119 | server->xdg_decoration_manager = | ||
120 | wlr_xdg_decoration_manager_v1_create(server->wl_display); | ||
121 | wl_signal_add( | ||
122 | &server->xdg_decoration_manager->events.new_toplevel_decoration, | ||
123 | &server->xdg_decoration); | ||
124 | server->xdg_decoration.notify = handle_xdg_decoration; | ||
125 | wl_list_init(&server->xdg_decorations); | ||
126 | |||
118 | wlr_export_dmabuf_manager_v1_create(server->wl_display); | 127 | wlr_export_dmabuf_manager_v1_create(server->wl_display); |
119 | wlr_screencopy_manager_v1_create(server->wl_display); | 128 | wlr_screencopy_manager_v1_create(server->wl_display); |
120 | 129 | ||
diff --git a/sway/tree/container.c b/sway/tree/container.c index baaa82fd..d75e34a5 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -715,7 +715,7 @@ void container_set_geometry_from_floating_view(struct sway_container *con) { | |||
715 | size_t border_width = 0; | 715 | size_t border_width = 0; |
716 | size_t top = 0; | 716 | size_t top = 0; |
717 | 717 | ||
718 | if (!view->using_csd) { | 718 | if (view->border != B_CSD) { |
719 | border_width = view->border_thickness * (view->border != B_NONE); | 719 | border_width = view->border_thickness * (view->border != B_NONE); |
720 | top = view->border == B_NORMAL ? | 720 | top = view->border == B_NORMAL ? |
721 | container_titlebar_height() : border_width; | 721 | container_titlebar_height() : border_width; |
diff --git a/sway/tree/view.c b/sway/tree/view.c index e370443c..c370de2d 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -5,6 +5,8 @@ | |||
5 | #include <wlr/render/wlr_renderer.h> | 5 | #include <wlr/render/wlr_renderer.h> |
6 | #include <wlr/types/wlr_buffer.h> | 6 | #include <wlr/types/wlr_buffer.h> |
7 | #include <wlr/types/wlr_output_layout.h> | 7 | #include <wlr/types/wlr_output_layout.h> |
8 | #include <wlr/types/wlr_server_decoration.h> | ||
9 | #include <wlr/types/wlr_xdg_decoration_v1.h> | ||
8 | #include "config.h" | 10 | #include "config.h" |
9 | #ifdef HAVE_XWAYLAND | 11 | #ifdef HAVE_XWAYLAND |
10 | #include <wlr/xwayland.h> | 12 | #include <wlr/xwayland.h> |
@@ -23,6 +25,7 @@ | |||
23 | #include "sway/tree/view.h" | 25 | #include "sway/tree/view.h" |
24 | #include "sway/tree/workspace.h" | 26 | #include "sway/tree/workspace.h" |
25 | #include "sway/config.h" | 27 | #include "sway/config.h" |
28 | #include "sway/xdg_decoration.h" | ||
26 | #include "pango.h" | 29 | #include "pango.h" |
27 | #include "stringop.h" | 30 | #include "stringop.h" |
28 | 31 | ||
@@ -231,12 +234,8 @@ void view_autoconfigure(struct sway_view *view) { | |||
231 | view->border_top = false; | 234 | view->border_top = false; |
232 | } | 235 | } |
233 | 236 | ||
234 | enum sway_container_border border = view->border; | 237 | switch (view->border) { |
235 | if (view->using_csd) { | 238 | case B_CSD: |
236 | border = B_NONE; | ||
237 | } | ||
238 | |||
239 | switch (border) { | ||
240 | case B_NONE: | 239 | case B_NONE: |
241 | x = con->x; | 240 | x = con->x; |
242 | y = con->y + y_offset; | 241 | y = con->y + y_offset; |
@@ -309,16 +308,26 @@ void view_request_activate(struct sway_view *view) { | |||
309 | } | 308 | } |
310 | } | 309 | } |
311 | 310 | ||
312 | void view_set_tiled(struct sway_view *view, bool tiled) { | 311 | void view_set_csd_from_server(struct sway_view *view, bool enabled) { |
313 | if (!tiled) { | 312 | if (view->xdg_decoration) { |
314 | view->using_csd = true; | 313 | uint32_t mode = enabled ? |
315 | if (view->impl->has_client_side_decorations) { | 314 | WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE : |
316 | view->using_csd = view->impl->has_client_side_decorations(view); | 315 | WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; |
317 | } | 316 | wlr_xdg_toplevel_decoration_v1_set_mode( |
318 | } else { | 317 | view->xdg_decoration->wlr_xdg_decoration, mode); |
319 | view->using_csd = false; | ||
320 | } | 318 | } |
319 | } | ||
321 | 320 | ||
321 | void view_set_csd_from_client(struct sway_view *view, bool enabled) { | ||
322 | if (enabled && view->border != B_CSD) { | ||
323 | view->saved_border = view->border; | ||
324 | view->border = B_CSD; | ||
325 | } else if (!enabled && view->border == B_CSD) { | ||
326 | view->border = view->saved_border; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | void view_set_tiled(struct sway_view *view, bool tiled) { | ||
322 | if (view->impl->set_tiled) { | 331 | if (view->impl->set_tiled) { |
323 | view->impl->set_tiled(view, tiled); | 332 | view->impl->set_tiled(view, tiled); |
324 | } | 333 | } |
diff --git a/sway/xdg_decoration.c b/sway/xdg_decoration.c new file mode 100644 index 00000000..2e7e4bd0 --- /dev/null +++ b/sway/xdg_decoration.c | |||
@@ -0,0 +1,73 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include "sway/desktop/transaction.h" | ||
3 | #include "sway/server.h" | ||
4 | #include "sway/tree/arrange.h" | ||
5 | #include "sway/tree/view.h" | ||
6 | #include "sway/xdg_decoration.h" | ||
7 | #include "log.h" | ||
8 | |||
9 | static void xdg_decoration_handle_destroy(struct wl_listener *listener, | ||
10 | void *data) { | ||
11 | struct sway_xdg_decoration *deco = | ||
12 | wl_container_of(listener, deco, destroy); | ||
13 | deco->view->xdg_decoration = NULL; | ||
14 | wl_list_remove(&deco->destroy.link); | ||
15 | wl_list_remove(&deco->surface_commit.link); | ||
16 | wl_list_remove(&deco->link); | ||
17 | free(deco); | ||
18 | } | ||
19 | |||
20 | static void xdg_decoration_handle_surface_commit(struct wl_listener *listener, | ||
21 | void *data) { | ||
22 | struct sway_xdg_decoration *decoration = | ||
23 | wl_container_of(listener, decoration, surface_commit); | ||
24 | |||
25 | bool csd = decoration->wlr_xdg_decoration->current_mode == | ||
26 | WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; | ||
27 | struct sway_view *view = decoration->view; | ||
28 | |||
29 | view_set_csd_from_client(view, csd); | ||
30 | |||
31 | arrange_container(view->container); | ||
32 | transaction_commit_dirty(); | ||
33 | } | ||
34 | |||
35 | void handle_xdg_decoration(struct wl_listener *listener, void *data) { | ||
36 | struct wlr_xdg_toplevel_decoration_v1 *wlr_deco = data; | ||
37 | struct sway_xdg_shell_view *xdg_shell_view = wlr_deco->surface->data; | ||
38 | struct wlr_xdg_surface *wlr_xdg_surface = | ||
39 | xdg_shell_view->view.wlr_xdg_surface; | ||
40 | |||
41 | struct sway_xdg_decoration *deco = calloc(1, sizeof(*deco)); | ||
42 | if (deco == NULL) { | ||
43 | return; | ||
44 | } | ||
45 | |||
46 | deco->view = &xdg_shell_view->view; | ||
47 | deco->view->xdg_decoration = deco; | ||
48 | deco->wlr_xdg_decoration = wlr_deco; | ||
49 | |||
50 | wl_signal_add(&wlr_deco->events.destroy, &deco->destroy); | ||
51 | deco->destroy.notify = xdg_decoration_handle_destroy; | ||
52 | |||
53 | // Note: We don't listen to the request_mode signal here, effectively | ||
54 | // ignoring any modes the client asks to set. The client can still force a | ||
55 | // mode upon us, in which case we get upset but live with it. | ||
56 | |||
57 | deco->surface_commit.notify = xdg_decoration_handle_surface_commit; | ||
58 | wl_signal_add(&wlr_xdg_surface->surface->events.commit, | ||
59 | &deco->surface_commit); | ||
60 | |||
61 | wl_list_insert(&server.xdg_decorations, &deco->link); | ||
62 | } | ||
63 | |||
64 | struct sway_xdg_decoration *xdg_decoration_from_surface( | ||
65 | struct wlr_surface *surface) { | ||
66 | struct sway_xdg_decoration *deco; | ||
67 | wl_list_for_each(deco, &server.xdg_decorations, link) { | ||
68 | if (deco->wlr_xdg_decoration->surface->surface == surface) { | ||
69 | return deco; | ||
70 | } | ||
71 | } | ||
72 | return NULL; | ||
73 | } | ||