From f873bcc4e1b2d39edb9ca91ea60db24e6b6e42f2 Mon Sep 17 00:00:00 2001 From: Jason Nader Date: Mon, 18 Oct 2021 18:41:11 +0900 Subject: [PATCH 01/59] swaymsg: use INT_MAX max JSON depth when parsing IPC response Same reasoning as fe11caeac946cecda491d592044a6b9519ef2035. Without this, swaymsg would fail with a cryptic error message when the JSON was nested too deep. --- swaymsg/main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/swaymsg/main.c b/swaymsg/main.c index 574d3b75..ce5d7d71 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200809L +#include #include #include #include @@ -480,7 +481,9 @@ int main(int argc, char **argv) { char *resp = ipc_single_command(socketfd, type, command, &len); // pretty print the json - json_object *obj = json_tokener_parse(resp); + json_tokener *tok = json_tokener_new_ex(INT_MAX); + json_object *obj = json_tokener_parse_ex(tok, resp, -1); + json_tokener_free(tok); if (obj == NULL) { if (!quiet) { fprintf(stderr, "ERROR: Could not parse json response from ipc. " @@ -517,7 +520,9 @@ int main(int argc, char **argv) { break; } - json_object *obj = json_tokener_parse(reply->payload); + json_tokener *tok = json_tokener_new_ex(INT_MAX); + json_object *obj = json_tokener_parse_ex(tok, reply->payload, -1); + json_tokener_free(tok); if (obj == NULL) { if (!quiet) { fprintf(stderr, "ERROR: Could not parse json response from" From 55cd8abd76cf6a31ca7edf67473c048f90f99140 Mon Sep 17 00:00:00 2001 From: Jason Nader Date: Mon, 18 Oct 2021 18:44:41 +0900 Subject: [PATCH 02/59] swaymsg: be explicit about the json parser error --- swaymsg/main.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/swaymsg/main.c b/swaymsg/main.c index ce5d7d71..c3468a16 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -483,12 +483,12 @@ int main(int argc, char **argv) { // pretty print the json json_tokener *tok = json_tokener_new_ex(INT_MAX); json_object *obj = json_tokener_parse_ex(tok, resp, -1); + enum json_tokener_error err = json_tokener_get_error(tok); json_tokener_free(tok); - if (obj == NULL) { + if (obj == NULL || err != json_tokener_success) { if (!quiet) { - fprintf(stderr, "ERROR: Could not parse json response from ipc. " - "This is a bug in sway."); - printf("%s\n", resp); + sway_log(SWAY_ERROR, "failed to parse payload as json: %s", + json_tokener_error_desc(err)); } ret = 1; } else { @@ -522,11 +522,12 @@ int main(int argc, char **argv) { json_tokener *tok = json_tokener_new_ex(INT_MAX); json_object *obj = json_tokener_parse_ex(tok, reply->payload, -1); + enum json_tokener_error err = json_tokener_get_error(tok); json_tokener_free(tok); - if (obj == NULL) { + if (obj == NULL || err != json_tokener_success) { if (!quiet) { - fprintf(stderr, "ERROR: Could not parse json response from" - " ipc. This is a bug in sway."); + sway_log(SWAY_ERROR, "failed to parse payload as json: %s", + json_tokener_error_desc(err)); ret = 1; } break; From db70f6496c7be38edff5d5594d1fb5a7895a23bc Mon Sep 17 00:00:00 2001 From: Jason Nader Date: Mon, 18 Oct 2021 18:45:40 +0900 Subject: [PATCH 03/59] swaymsg: fix misplaced return value --- swaymsg/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swaymsg/main.c b/swaymsg/main.c index c3468a16..5f7854f5 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -528,8 +528,8 @@ int main(int argc, char **argv) { if (!quiet) { sway_log(SWAY_ERROR, "failed to parse payload as json: %s", json_tokener_error_desc(err)); - ret = 1; } + ret = 1; break; } else if (quiet) { json_object_put(obj); From b48cb6b0ec1320ad25fd2c0a1b5118dbe2536060 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 17 Oct 2021 21:18:24 +0200 Subject: [PATCH 04/59] Remove --my-next-gpu-wont-be-nvidia Nvidia has historically been a bad actor in the open-source graphics ecosystem because they required a special EGLStreams code-path instead of exposing the de-facto standard GBM API. However, with their upcoming release they now support GBM as well. This is a push in the right direction for Nvidia, so there's no reason we should be more hostile to them than to any other proprietary driver. Let's remove the --my-next-gpu-wont-be-nvidia flag, and advise users to use --unsupported-gpu now. Note, proprietary Nvidia drivers are still unsupported by the Sway project (just like all other proprietary drivers). --- sway/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sway/main.c b/sway/main.c index e960c4e2..264fa847 100644 --- a/sway/main.c +++ b/sway/main.c @@ -63,7 +63,7 @@ void detect_proprietary(int allow_unsupported_gpu) { sway_log(SWAY_ERROR, "Proprietary Nvidia drivers are NOT supported. " "Use Nouveau. To launch sway anyway, launch with " - "--my-next-gpu-wont-be-nvidia and DO NOT report issues."); + "--unsupported-gpu and DO NOT report issues."); exit(EXIT_FAILURE); } break; @@ -220,7 +220,6 @@ int main(int argc, char **argv) { {"verbose", no_argument, NULL, 'V'}, {"get-socketpath", no_argument, NULL, 'p'}, {"unsupported-gpu", no_argument, NULL, 'u'}, - {"my-next-gpu-wont-be-nvidia", no_argument, NULL, 'u'}, {0, 0, 0, 0} }; From 215787e8b28d4e52d97bdcadd4b64305c7a62ac5 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Tue, 19 Oct 2021 07:50:05 +0200 Subject: [PATCH 05/59] xwayland: Clear wlr_xwayland_surface in handle_destroy If the destroyed xwayland view is in transaction, it won't be destroyed immediately. wlr_xwayland_surface then becomes dangling pointer. Closes #6605 Closes #5884 --- sway/desktop/xwayland.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 1af8d248..40288f97 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -436,6 +436,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&xwayland_view->commit.link); } + xwayland_view->view.wlr_xwayland_surface = NULL; + wl_list_remove(&xwayland_view->destroy.link); wl_list_remove(&xwayland_view->request_configure.link); wl_list_remove(&xwayland_view->request_fullscreen.link); From 197d0ab82f64ea9a96786e55e375c930389aa85b Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sun, 10 Oct 2021 01:57:48 +0300 Subject: [PATCH 06/59] commands/focus: focus view inside container seat_get_focus_inactive_floating and seat_get_focus_inactive_tiling do not always return a view, so get the previously focused view from the container with seat_get_focus_inactive_view. This is the i3 behavior. --- sway/commands/focus.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 6771ca2f..ceb43d45 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -267,6 +267,11 @@ static struct cmd_results *focus_mode(struct sway_workspace *ws, new_focus = seat_get_focus_inactive_tiling(seat, ws); } if (new_focus) { + struct sway_container *new_focus_view = + seat_get_focus_inactive_view(seat, &new_focus->node); + if (new_focus_view) { + new_focus = new_focus_view; + } seat_set_focus_container(seat, new_focus); // If we're on the floating layer and the floating container area From 21d2fdf74c93a4d1df5dd2dc0d6bf24c611dd752 Mon Sep 17 00:00:00 2001 From: siikamiika Date: Sun, 10 Oct 2021 17:27:43 +0300 Subject: [PATCH 07/59] view: add new container as a sibling of tiled view If the focused container is floating by itself, create a new container in tiling mode as a sibling of the inactive focused container instead of creating it as a sibling of everything that is in tiling mode in that workspace. This is the i3 behavior. --- sway/tree/view.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/sway/tree/view.c b/sway/tree/view.c index b2f70d70..bd53a5c8 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -729,10 +729,29 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, } struct sway_seat *seat = input_manager_current_seat(); - struct sway_node *node = ws ? seat_get_focus_inactive(seat, &ws->node) - : seat_get_focus_inactive(seat, &root->node); - struct sway_container *target_sibling = node->type == N_CONTAINER ? - node->sway_container : NULL; + struct sway_node *node = + seat_get_focus_inactive(seat, ws ? &ws->node : &root->node); + struct sway_container *target_sibling = NULL; + if (node && node->type == N_CONTAINER) { + if (container_is_floating(node->sway_container)) { + // If we're about to launch the view into the floating container, then + // launch it as a tiled view instead. + if (ws) { + target_sibling = seat_get_focus_inactive_tiling(seat, ws); + if (target_sibling) { + struct sway_container *con = + seat_get_focus_inactive_view(seat, &target_sibling->node); + if (con) { + target_sibling = con; + } + } + } else { + ws = seat_get_last_known_workspace(seat); + } + } else { + target_sibling = node->sway_container; + } + } view->foreign_toplevel = wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager); @@ -749,13 +768,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, wl_signal_add(&view->foreign_toplevel->events.destroy, &view->foreign_destroy); - // If we're about to launch the view into the floating container, then - // launch it as a tiled view in the root of the workspace instead. - if (target_sibling && container_is_floating(target_sibling)) { - target_sibling = NULL; - ws = seat_get_last_known_workspace(seat); - } - struct sway_container *container = view->container; if (target_sibling) { container_add_sibling(target_sibling, container, 1); From 944d7031c5a1ffebb105fb1fed3f957903abe8da Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Thu, 21 Oct 2021 18:20:26 +0200 Subject: [PATCH 08/59] fix: handle NULL from json_tokener_new_ex if there is not enough memory to fit json_tokener and (depth * json_tokener_srec) in RAM, don't segfault. --- swaymsg/main.c | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/swaymsg/main.c b/swaymsg/main.c index 5f7854f5..3698294a 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -482,28 +482,33 @@ int main(int argc, char **argv) { // pretty print the json json_tokener *tok = json_tokener_new_ex(INT_MAX); - json_object *obj = json_tokener_parse_ex(tok, resp, -1); - enum json_tokener_error err = json_tokener_get_error(tok); - json_tokener_free(tok); - if (obj == NULL || err != json_tokener_success) { - if (!quiet) { - sway_log(SWAY_ERROR, "failed to parse payload as json: %s", - json_tokener_error_desc(err)); - } + if (tok == NULL) { + sway_log(SWAY_ERROR, "failed allocating json_tokener"); ret = 1; } else { - if (!success(obj, true)) { - ret = 2; - } - if (!quiet && (type != IPC_SUBSCRIBE || ret != 0)) { - if (raw) { - printf("%s\n", json_object_to_json_string_ext(obj, - JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); - } else { - pretty_print(type, obj); + json_object *obj = json_tokener_parse_ex(tok, resp, -1); + enum json_tokener_error err = json_tokener_get_error(tok); + json_tokener_free(tok); + if (obj == NULL || err != json_tokener_success) { + if (!quiet) { + sway_log(SWAY_ERROR, "failed to parse payload as json: %s", + json_tokener_error_desc(err)); } + ret = 1; + } else { + if (!success(obj, true)) { + ret = 2; + } + if (!quiet && (type != IPC_SUBSCRIBE || ret != 0)) { + if (raw) { + printf("%s\n", json_object_to_json_string_ext(obj, + JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); + } else { + pretty_print(type, obj); + } + } + json_object_put(obj); } - json_object_put(obj); } free(command); free(resp); @@ -521,6 +526,11 @@ int main(int argc, char **argv) { } json_tokener *tok = json_tokener_new_ex(INT_MAX); + if (tok == NULL) { + sway_log(SWAY_ERROR, "failed allocating json_tokener"); + ret = 1; + break; + } json_object *obj = json_tokener_parse_ex(tok, reply->payload, -1); enum json_tokener_error err = json_tokener_get_error(tok); json_tokener_free(tok); From 96baef8ae9955dd7ffd85c6b769a14df1f95bc97 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Thu, 21 Oct 2021 18:22:50 +0200 Subject: [PATCH 09/59] fix: use sane value for json_tokener max_depth INT_MAX causes a NULL pointer if there is not enough memory available to fit (INT_MAX * sizeof(struct json_tokener_srec)). --- swaymsg/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/swaymsg/main.c b/swaymsg/main.c index 3698294a..dcf42cb6 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -1,4 +1,8 @@ #define _POSIX_C_SOURCE 200809L + +// arbitrary number, it's probably sufficient, higher number = more memory usage +#define JSON_MAX_DEPTH 512 + #include #include #include @@ -481,7 +485,7 @@ int main(int argc, char **argv) { char *resp = ipc_single_command(socketfd, type, command, &len); // pretty print the json - json_tokener *tok = json_tokener_new_ex(INT_MAX); + json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH); if (tok == NULL) { sway_log(SWAY_ERROR, "failed allocating json_tokener"); ret = 1; @@ -525,7 +529,7 @@ int main(int argc, char **argv) { break; } - json_tokener *tok = json_tokener_new_ex(INT_MAX); + json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH); if (tok == NULL) { sway_log(SWAY_ERROR, "failed allocating json_tokener"); ret = 1; From b223f702500d7cda6336e948062d680f07f34f66 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Thu, 21 Oct 2021 22:47:35 +0200 Subject: [PATCH 10/59] refactor: use sway_abort instead --- swaymsg/main.c | 54 ++++++++++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/swaymsg/main.c b/swaymsg/main.c index dcf42cb6..e469319a 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -487,32 +487,33 @@ int main(int argc, char **argv) { // pretty print the json json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH); if (tok == NULL) { - sway_log(SWAY_ERROR, "failed allocating json_tokener"); + if (quiet) { + exit(EXIT_FAILURE); + } + sway_abort("failed allocating json_tokener"); + } + json_object *obj = json_tokener_parse_ex(tok, resp, -1); + enum json_tokener_error err = json_tokener_get_error(tok); + json_tokener_free(tok); + if (obj == NULL || err != json_tokener_success) { + if (!quiet) { + sway_log(SWAY_ERROR, "failed to parse payload as json: %s", + json_tokener_error_desc(err)); + } ret = 1; } else { - json_object *obj = json_tokener_parse_ex(tok, resp, -1); - enum json_tokener_error err = json_tokener_get_error(tok); - json_tokener_free(tok); - if (obj == NULL || err != json_tokener_success) { - if (!quiet) { - sway_log(SWAY_ERROR, "failed to parse payload as json: %s", - json_tokener_error_desc(err)); - } - ret = 1; - } else { - if (!success(obj, true)) { - ret = 2; - } - if (!quiet && (type != IPC_SUBSCRIBE || ret != 0)) { - if (raw) { - printf("%s\n", json_object_to_json_string_ext(obj, - JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); - } else { - pretty_print(type, obj); - } - } - json_object_put(obj); + if (!success(obj, true)) { + ret = 2; } + if (!quiet && (type != IPC_SUBSCRIBE || ret != 0)) { + if (raw) { + printf("%s\n", json_object_to_json_string_ext(obj, + JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); + } else { + pretty_print(type, obj); + } + } + json_object_put(obj); } free(command); free(resp); @@ -531,9 +532,10 @@ int main(int argc, char **argv) { json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH); if (tok == NULL) { - sway_log(SWAY_ERROR, "failed allocating json_tokener"); - ret = 1; - break; + if (quiet) { + exit(EXIT_FAILURE); + } + sway_abort("failed allocating json_tokener"); } json_object *obj = json_tokener_parse_ex(tok, reply->payload, -1); enum json_tokener_error err = json_tokener_get_error(tok); From 9303bed4d4523d158b33c44f534a53b21d7688d6 Mon Sep 17 00:00:00 2001 From: Jason Nader Date: Mon, 25 Oct 2021 13:28:32 +0900 Subject: [PATCH 11/59] refactor: use JSON_MAX_DEPTH everywhere --- include/ipc-client.h | 3 +++ swaybar/ipc.c | 2 +- swaymsg/main.c | 3 --- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/ipc-client.h b/include/ipc-client.h index d3895023..9c5712d7 100644 --- a/include/ipc-client.h +++ b/include/ipc-client.h @@ -1,6 +1,9 @@ #ifndef _SWAY_IPC_CLIENT_H #define _SWAY_IPC_CLIENT_H +// arbitrary number, it's probably sufficient, higher number = more memory usage +#define JSON_MAX_DEPTH 512 + #include #include #include diff --git a/swaybar/ipc.c b/swaybar/ipc.c index a64aa1ab..2cb235bf 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -550,7 +550,7 @@ bool handle_ipc_readable(struct swaybar *bar) { // The default depth of 32 is too small to represent some nested layouts, but // we can't pass INT_MAX here because json-c (as of this writing) prefaults // all the memory for its stack. - json_tokener *tok = json_tokener_new_ex(256); + json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH); if (!tok) { sway_log_errno(SWAY_ERROR, "failed to create tokener"); free_ipc_response(resp); diff --git a/swaymsg/main.c b/swaymsg/main.c index e469319a..0d9dc5a0 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -1,8 +1,5 @@ #define _POSIX_C_SOURCE 200809L -// arbitrary number, it's probably sufficient, higher number = more memory usage -#define JSON_MAX_DEPTH 512 - #include #include #include From aaf68cf423d718a748b56481fddb37e9186b83ed Mon Sep 17 00:00:00 2001 From: Rasmus Moorats Date: Thu, 23 Sep 2021 17:52:35 +0300 Subject: [PATCH 12/59] fix cursor input for layer-shell surfaces previously, fullscreen global containers would grab cursor input even if a shell-layer surface was on top of it related issue: https://github.com/swaywm/sway/issues/6501 --- sway/input/cursor.c | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 1e3e16d6..d8b1abeb 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -83,7 +83,28 @@ static struct wlr_surface *layer_surface_popup_at(struct sway_output *output, struct sway_node *node_at_coords( struct sway_seat *seat, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - // check for unmanaged views first + // find the output the cursor is on + struct wlr_output *wlr_output = wlr_output_layout_output_at( + root->output_layout, lx, ly); + if (wlr_output == NULL) { + return NULL; + } + struct sway_output *output = wlr_output->data; + if (!output || !output->enabled) { + // output is being destroyed or is being enabled + return NULL; + } + double ox = lx, oy = ly; + wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy); + + // layer surfaces on the overlay layer are rendered on top + if ((*surface = layer_surface_at(output, + &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], + ox, oy, sx, sy))) { + return NULL; + } + + // check for unmanaged views #if HAVE_XWAYLAND struct wl_list *unmanaged = &root->xwayland_unmanaged; struct sway_xwayland_unmanaged *unmanaged_surface; @@ -101,19 +122,6 @@ struct sway_node *node_at_coords( } } #endif - // find the output the cursor is on - struct wlr_output *wlr_output = wlr_output_layout_output_at( - root->output_layout, lx, ly); - if (wlr_output == NULL) { - return NULL; - } - struct sway_output *output = wlr_output->data; - if (!output || !output->enabled) { - // output is being destroyed or is being enabled - return NULL; - } - double ox = lx, oy = ly; - wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy); if (root->fullscreen_global) { // Try fullscreen container @@ -131,11 +139,6 @@ struct sway_node *node_at_coords( return NULL; } - if ((*surface = layer_surface_at(output, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - ox, oy, sx, sy))) { - return NULL; - } if (ws->fullscreen) { // Try transient containers for (int i = 0; i < ws->floating->length; ++i) { From 9969de9e00a1ca89ded85d418a72c4ebbce91331 Mon Sep 17 00:00:00 2001 From: bR3iN Date: Thu, 28 Oct 2021 15:31:23 +0200 Subject: [PATCH 13/59] Add smart_gaps inverse_outer command Add a subcommand for `smart_gaps` that enables outer gaps only on workspaces with exactly one visible child. Also add documentation for `smart_gaps toggle`. --- include/sway/config.h | 8 +++++++- sway/commands/smart_gaps.c | 7 ++++++- sway/config.c | 2 +- sway/sway.5.scd | 5 +++-- sway/tree/workspace.c | 42 ++++++++++++++++++++++++-------------- 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 46dd4ffe..660245c1 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -283,6 +283,12 @@ struct side_gaps { int left; }; +enum smart_gaps_mode { + SMART_GAPS_OFF, + SMART_GAPS_ON, + SMART_GAPS_INVERSE_OUTER, +}; + /** * Stores configuration for a workspace, regardless of whether the workspace * exists. @@ -512,7 +518,7 @@ struct sway_config { bool tiling_drag; int tiling_drag_threshold; - bool smart_gaps; + enum smart_gaps_mode smart_gaps; int gaps_inner; struct side_gaps gaps_outer; diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c index b27f9ccd..a6d165dc 100644 --- a/sway/commands/smart_gaps.c +++ b/sway/commands/smart_gaps.c @@ -15,7 +15,12 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) { return error; } - config->smart_gaps = parse_boolean(argv[0], config->smart_gaps); + if (strcmp(argv[0], "inverse_outer") == 0) { + config->smart_gaps = SMART_GAPS_INVERSE_OUTER; + } else { + config->smart_gaps = parse_boolean(argv[0], config->smart_gaps) + ? SMART_GAPS_ON : SMART_GAPS_OFF; + } arrange_root(); diff --git a/sway/config.c b/sway/config.c index e3daacda..35837212 100644 --- a/sway/config.c +++ b/sway/config.c @@ -266,7 +266,7 @@ static void config_defaults(struct sway_config *config) { config->tiling_drag = true; config->tiling_drag_threshold = 9; - config->smart_gaps = false; + config->smart_gaps = SMART_GAPS_OFF; config->gaps_inner = 0; config->gaps_outer.top = 0; config->gaps_outer.right = 0; diff --git a/sway/sway.5.scd b/sway/sway.5.scd index e8d3d606..ec34a56c 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -692,9 +692,10 @@ The default colors are: borders will only be enabled if the workspace has more than one visible child and gaps equal to zero. -*smart_gaps* on|off +*smart_gaps* on|off|toggle|inverse_outer If smart_gaps are _on_ gaps will only be enabled if a workspace has more - than one child. + than one child. If smart_gaps are _inverse_outer_ outer gaps will only + be enabled if a workspace has exactly one child. *mark* --add|--replace [--toggle] Marks are arbitrary labels that can be used to identify certain windows and diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 8dd7789d..e3ff1513 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -844,24 +844,36 @@ struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, return con; } +bool workspace_has_single_visible_container(struct sway_workspace *ws) { + struct sway_seat *seat = input_manager_get_default_seat(); + struct sway_container *focus = + seat_get_focus_inactive_tiling(seat, ws); + if (focus && !focus->view) { + focus = seat_get_focus_inactive_view(seat, &focus->node); + } + return (focus && focus->view && view_ancestor_is_only_visible(focus->view)); +} + void workspace_add_gaps(struct sway_workspace *ws) { - if (config->smart_gaps) { - struct sway_seat *seat = input_manager_get_default_seat(); - struct sway_container *focus = - seat_get_focus_inactive_tiling(seat, ws); - if (focus && !focus->view) { - focus = seat_get_focus_inactive_view(seat, &focus->node); - } - if (focus && focus->view && view_ancestor_is_only_visible(focus->view)) { - ws->current_gaps.top = 0; - ws->current_gaps.right = 0; - ws->current_gaps.bottom = 0; - ws->current_gaps.left = 0; - return; - } + if (config->smart_gaps == SMART_GAPS_ON + && workspace_has_single_visible_container(ws)) { + ws->current_gaps.top = 0; + ws->current_gaps.right = 0; + ws->current_gaps.bottom = 0; + ws->current_gaps.left = 0; + return; + } + + if (config->smart_gaps == SMART_GAPS_INVERSE_OUTER + && !workspace_has_single_visible_container(ws)) { + ws->current_gaps.top = 0; + ws->current_gaps.right = 0; + ws->current_gaps.bottom = 0; + ws->current_gaps.left = 0; + } else { + ws->current_gaps = ws->gaps_outer; } - ws->current_gaps = ws->gaps_outer; // Add inner gaps and make sure we don't turn out negative ws->current_gaps.top = fmax(0, ws->current_gaps.top + ws->gaps_inner); ws->current_gaps.right = fmax(0, ws->current_gaps.right + ws->gaps_inner); From 38020d157ddb58e756c654e9a2ff203c1562b25b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 21 Oct 2021 21:52:17 +0200 Subject: [PATCH 14/59] Bump RLIMIT_NOFILE Wayland compositors handle many file descriptors: client connections, DMA-BUFs, sync_files, wl_data_device pipes, and so on. Bump the limit to the max. Closes: https://github.com/swaywm/sway/issues/6285 --- include/sway/server.h | 2 ++ sway/commands/exec_always.c | 2 ++ sway/config/bar.c | 2 ++ sway/config/output.c | 2 ++ sway/main.c | 31 +++++++++++++++++++++++++++++++ sway/swaynag.c | 2 ++ 6 files changed, 41 insertions(+) diff --git a/include/sway/server.h b/include/sway/server.h index 88dda097..f99bbda6 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -137,6 +137,8 @@ void server_fini(struct sway_server *server); bool server_start(struct sway_server *server); void server_run(struct sway_server *server); +void restore_nofile_limit(void); + void handle_compositor_new_surface(struct wl_listener *listener, void *data); void handle_new_output(struct wl_listener *listener, void *data); diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index fce337d5..b35065c1 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -7,6 +7,7 @@ #include #include "sway/commands.h" #include "sway/config.h" +#include "sway/server.h" #include "sway/tree/container.h" #include "sway/tree/root.h" #include "sway/tree/workspace.h" @@ -53,6 +54,7 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) { // Fork process if ((pid = fork()) == 0) { // Fork child process again + restore_nofile_limit(); setsid(); sigset_t set; sigemptyset(&set); diff --git a/sway/config/bar.c b/sway/config/bar.c index e09add44..d1b342e6 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -219,6 +219,8 @@ static void invoke_swaybar(struct bar_config *bar) { sigprocmask(SIG_SETMASK, &set, NULL); signal(SIGPIPE, SIG_DFL); + restore_nofile_limit(); + pid = fork(); if (pid < 0) { sway_log_errno(SWAY_ERROR, "fork failed"); diff --git a/sway/config/output.c b/sway/config/output.c index 8e937b28..6d39c2f5 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -750,6 +750,8 @@ static bool _spawn_swaybg(char **command) { sway_log_errno(SWAY_ERROR, "fork failed"); return false; } else if (pid == 0) { + restore_nofile_limit(); + pid = fork(); if (pid < 0) { sway_log_errno(SWAY_ERROR, "fork failed"); diff --git a/sway/main.c b/sway/main.c index 264fa847..2c760524 100644 --- a/sway/main.c +++ b/sway/main.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ static bool terminate_request = false; static int exit_value = 0; +static struct rlimit original_nofile_rlimit = {0}; struct sway_server server = {0}; struct sway_debug debug = {0}; @@ -169,6 +171,33 @@ static bool drop_permissions(void) { return true; } +static void increase_nofile_limit(void) { + if (getrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) { + sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: " + "getrlimit(NOFILE) failed"); + return; + } + + struct rlimit new_rlimit = original_nofile_rlimit; + new_rlimit.rlim_cur = new_rlimit.rlim_max; + if (setrlimit(RLIMIT_NOFILE, &new_rlimit) != 0) { + sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: " + "setrlimit(NOFILE) failed"); + sway_log(SWAY_INFO, "Running with %d max open files", + (int)original_nofile_rlimit.rlim_cur); + } +} + +void restore_nofile_limit(void) { + if (original_nofile_rlimit.rlim_cur == 0) { + return; + } + if (setrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) { + sway_log_errno(SWAY_ERROR, "Failed to restore max open files limit: " + "setrlimit(NOFILE) failed"); + } +} + void enable_debug_flag(const char *flag) { if (strcmp(flag, "damage=highlight") == 0) { debug.damage = DAMAGE_HIGHLIGHT; @@ -349,6 +378,8 @@ int main(int argc, char **argv) { exit(EXIT_FAILURE); } + increase_nofile_limit(); + // handle SIGTERM signals signal(SIGTERM, sig_handler); signal(SIGINT, sig_handler); diff --git a/sway/swaynag.c b/sway/swaynag.c index ba582989..4a0a6d30 100644 --- a/sway/swaynag.c +++ b/sway/swaynag.c @@ -64,6 +64,8 @@ bool swaynag_spawn(const char *swaynag_command, sway_log(SWAY_ERROR, "Failed to create fork for swaynag"); goto failed; } else if (pid == 0) { + restore_nofile_limit(); + pid = fork(); if (pid < 0) { sway_log_errno(SWAY_ERROR, "fork failed"); From fc25e4944efdc5bc7e33a81180908927dba93ee6 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Mon, 1 Nov 2021 23:23:13 -0400 Subject: [PATCH 15/59] Update URL to wlroots project (GitHub->GitLab) --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 2 +- README.de.md | 2 +- README.dk.md | 2 +- README.es.md | 2 +- README.fr.md | 2 +- README.gr.md | 2 +- README.hu.md | 2 +- README.ir.md | 2 +- README.ja.md | 2 +- README.ko.md | 2 +- README.md | 2 +- README.nl.md | 2 +- README.pl.md | 2 +- README.pt.md | 2 +- README.ro.md | 2 +- README.ru.md | 2 +- README.tr.md | 2 +- README.uk.md | 2 +- README.zh-CN.md | 2 +- README.zh-TW.md | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index 7f0bef02..abf636ab 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -21,7 +21,7 @@ packages: - xwayland sources: - https://github.com/swaywm/sway - - https://github.com/swaywm/wlroots + - https://gitlab.freedesktop.org/wlroots/wlroots.git tasks: - wlroots: | cd wlroots diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index a8f1dfed..ac4cdb4d 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -18,7 +18,7 @@ packages: - seatd sources: - https://github.com/swaywm/sway - - https://github.com/swaywm/wlroots + - https://gitlab.freedesktop.org/wlroots/wlroots.git tasks: - wlroots: | cd wlroots diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 1a3c8512..97e7eccc 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -26,7 +26,7 @@ packages: - x11/xcb-util-wm sources: - https://github.com/swaywm/sway -- https://github.com/swaywm/wlroots +- https://gitlab.freedesktop.org/wlroots/wlroots.git tasks: - setup: | cd sway diff --git a/README.de.md b/README.de.md index 6e1e8ca9..01b5e9ad 100644 --- a/README.de.md +++ b/README.de.md @@ -15,7 +15,7 @@ Falls du sway für deine eigene Distribution als Paket bereitstellen möchtest, sway benötigt die folgenden Pakete: * meson\* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols\* * pcre diff --git a/README.dk.md b/README.dk.md index 94c0b9eb..f712e96b 100644 --- a/README.dk.md +++ b/README.dk.md @@ -70,5 +70,5 @@ support til dem (gdm er kendt for at fungere temmelig godt). [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [GitHub releases]: https://github.com/swaywm/sway/releases [Opsætning til udvikling]: https://github.com/swaywm/sway/wiki/Development-Setup -[wlroots]: https://github.com/swaywm/wlroots +[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots [scdoc]: https://git.sr.ht/~sircmpwn/scdoc diff --git a/README.es.md b/README.es.md index 951a2eba..7af7d90b 100644 --- a/README.es.md +++ b/README.es.md @@ -25,7 +25,7 @@ escriba un email a sir@cmpwn.com Instale las dependencias: * meson \* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols \* * pcre diff --git a/README.fr.md b/README.fr.md index d1f4f934..359a30f9 100644 --- a/README.fr.md +++ b/README.fr.md @@ -79,5 +79,5 @@ bien fonctionner). [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [versions GitHub]: https://github.com/swaywm/sway/releases [Configuration de développement]: https://github.com/swaywm/sway/wiki/Development-Setup -[wlroots]: https://github.com/swaywm/wlroots +[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots [scdoc]: https://git.sr.ht/~sircmpwn/scdoc diff --git a/README.gr.md b/README.gr.md index 5bb04932..4c30e29d 100644 --- a/README.gr.md +++ b/README.gr.md @@ -69,5 +69,5 @@ _\*Compile-time dep_ [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [GitHub releases]: https://github.com/swaywm/sway/releases [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup -[wlroots]: https://github.com/swaywm/wlroots +[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots [scdoc]: https://git.sr.ht/~sircmpwn/scdoc \ No newline at end of file diff --git a/README.hu.md b/README.hu.md index 75999071..4e006f25 100644 --- a/README.hu.md +++ b/README.hu.md @@ -73,5 +73,5 @@ gdm-ről ismeretes, hogy egész jól működik.) [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [GitHub releases]: https://github.com/swaywm/sway/releases [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup -[wlroots]: https://github.com/swaywm/wlroots +[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots [scdoc]: https://git.sr.ht/~sircmpwn/scdoc diff --git a/README.ir.md b/README.ir.md index 890a0fd2..bd0849b6 100644 --- a/README.ir.md +++ b/README.ir.md @@ -28,7 +28,7 @@ sway در بسته‌های رسمی توزیع‌های مختلف وجود د بسته‌های مورد نیاز: * meson \* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols \* * pcre diff --git a/README.ja.md b/README.ja.md index 7af54fb2..786e169c 100644 --- a/README.ja.md +++ b/README.ja.md @@ -27,7 +27,7 @@ Swayは沢山のディストリビューションで提供されています。" 次の依存パッケージをインストールしてください: * meson \* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols \* * pcre diff --git a/README.ko.md b/README.ko.md index 76ce2f4d..1086da0c 100644 --- a/README.ko.md +++ b/README.ko.md @@ -24,7 +24,7 @@ IRC 채널을 방문하거나 sir@cmpwn.com으로 이메일을 보내 상담 받 다음 의존 패키지들을 설치해 주세요: * meson \* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols \* * pcre diff --git a/README.md b/README.md index 3367f846..8c252e9e 100644 --- a/README.md +++ b/README.md @@ -87,5 +87,5 @@ sway (gdm is known to work fairly well). [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [GitHub releases]: https://github.com/swaywm/sway/releases [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup -[wlroots]: https://github.com/swaywm/wlroots +[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots [scdoc]: https://git.sr.ht/~sircmpwn/scdoc diff --git a/README.nl.md b/README.nl.md index 3351db39..c0a93063 100644 --- a/README.nl.md +++ b/README.nl.md @@ -25,7 +25,7 @@ kanaal of stuur een e-mail naar sir@cmpwn.com voor advies. Afhankelijkheden installeren: * meson \* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols \* * pcre diff --git a/README.pl.md b/README.pl.md index da987b7c..6d376b68 100644 --- a/README.pl.md +++ b/README.pl.md @@ -25,7 +25,7 @@ adres sir@cmpwn.com w celu uzyskania wskazówek. Zainstaluj zależności: * meson \* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols \* * pcre diff --git a/README.pt.md b/README.pt.md index 7d449ef3..92a4b54d 100644 --- a/README.pt.md +++ b/README.pt.md @@ -27,7 +27,7 @@ Verifique [essa página da wiki](https://github.com/swaywm/sway/wiki/Development Instale as dependências: * meson \* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols \* * pcre diff --git a/README.ro.md b/README.ro.md index 79524b79..f7785b8f 100644 --- a/README.ro.md +++ b/README.ro.md @@ -22,7 +22,7 @@ Dacă sunteți interesați in a crea pachete pentru distribuția voastră, infor Dependențe pentru instalare: * meson \* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols \* * pcre diff --git a/README.ru.md b/README.ru.md index 70396905..d563859c 100644 --- a/README.ru.md +++ b/README.ru.md @@ -70,5 +70,5 @@ sway (gdm работает довольно неплохо). [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [GitHub releases]: https://github.com/swaywm/sway/releases [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup -[wlroots]: https://github.com/swaywm/wlroots +[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots [scdoc]: https://git.sr.ht/~sircmpwn/scdoc diff --git a/README.tr.md b/README.tr.md index c0f72d72..5c98a538 100644 --- a/README.tr.md +++ b/README.tr.md @@ -64,5 +64,5 @@ TTY'den `sway` çalıştırın. Bazı görüntü yöneticileriyle(display manag [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [GitHub releases]: https://github.com/swaywm/sway/releases [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup -[wlroots]: https://github.com/swaywm/wlroots +[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots [scdoc]: https://git.sr.ht/~sircmpwn/scdoc diff --git a/README.uk.md b/README.uk.md index 3d7402de..ff9ebec3 100644 --- a/README.uk.md +++ b/README.uk.md @@ -36,7 +36,7 @@ Sway доступний у багатьох дистрибутивах Linux (а Встановіть залежності: * meson \* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols \* * pcre diff --git a/README.zh-CN.md b/README.zh-CN.md index ecb46789..561d6c14 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -25,7 +25,7 @@ Sway 在很多发行版中可用. 尝试在你的发行版中安装 "sway" 包. 安装依赖: * meson \* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols \* * pcre diff --git a/README.zh-TW.md b/README.zh-TW.md index 4fd656da..bc30b903 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -25,7 +25,7 @@ Sway 在許多發行版都有提供。請自己嘗試於你的發行版安裝 相依套件: * meson \* -* [wlroots](https://github.com/swaywm/wlroots) +* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots) * wayland * wayland-protocols \* * pcre From bb7bb3676deead149c66fbf74b55d3bb4f9d69b5 Mon Sep 17 00:00:00 2001 From: Eric Engestrom Date: Sat, 13 Nov 2021 15:25:58 +0000 Subject: [PATCH 16/59] sway: allow IPCs on proprietary drivers Proprietary drivers require --unsupported-gpu to be allowed, and IPCs require no option to be passed. The only way to satisfy both is to run IPCs before checking for proprietary drivers. --- sway/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sway/main.c b/sway/main.c index 2c760524..6c71048b 100644 --- a/sway/main.c +++ b/sway/main.c @@ -342,7 +342,6 @@ int main(int argc, char **argv) { log_kernel(); log_distro(); log_env(); - detect_proprietary(allow_unsupported_gpu); if (optind < argc) { // Behave as IPC client if (optind != 1) { @@ -369,6 +368,8 @@ int main(int argc, char **argv) { return 0; } + detect_proprietary(allow_unsupported_gpu); + if (!server_privileged_prepare(&server)) { return 1; } From cbecc5cbaed6b30c995d2c245def458e383b4e38 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 13 Nov 2021 09:08:14 +0300 Subject: [PATCH 17/59] container: fix surface_is_popup() --- sway/tree/container.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index 6a01eab3..943d3d53 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -382,19 +382,17 @@ struct sway_container *tiling_container_at(struct sway_node *parent, } static bool surface_is_popup(struct wlr_surface *surface) { - if (wlr_surface_is_xdg_surface(surface)) { - struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_from_wlr_surface(surface); - while (xdg_surface && xdg_surface->role != WLR_XDG_SURFACE_ROLE_NONE) { - if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - return true; - } - xdg_surface = xdg_surface->toplevel->parent; + while (!wlr_surface_is_xdg_surface(surface)) { + if (!wlr_surface_is_subsurface(surface)) { + return false; } - return false; + struct wlr_subsurface *subsurface = + wlr_subsurface_from_wlr_surface(surface); + surface = subsurface->parent; } - - return false; + struct wlr_xdg_surface *xdg_surface = + wlr_xdg_surface_from_wlr_surface(surface); + return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP; } struct sway_container *container_at(struct sway_workspace *workspace, From 5865af75cf8029cc703cda36b68daafcb658c97b Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 15 Nov 2021 13:32:52 -0500 Subject: [PATCH 18/59] sway: create wlr_renderer and wlr_allocator wlroots now required the compositor to create its own wlr_renderer and wlr_allocator to initialize the wlr_output --- include/sway/server.h | 3 +++ sway/desktop/output.c | 6 ++++++ sway/desktop/render.c | 16 ++++------------ sway/server.c | 22 +++++++++++++++++----- sway/tree/container.c | 3 +-- 5 files changed, 31 insertions(+), 19 deletions(-) diff --git a/include/sway/server.h b/include/sway/server.h index f99bbda6..109097d7 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,8 @@ struct sway_server { struct wlr_backend *noop_backend; // secondary headless backend used for creating virtual outputs on-the-fly struct wlr_backend *headless_backend; + struct wlr_renderer *renderer; + struct wlr_allocator *allocator; struct wlr_compositor *compositor; struct wl_listener compositor_new_surface; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index edec71ad..cd9fd3a6 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -850,6 +850,12 @@ void handle_new_output(struct wl_listener *listener, void *data) { return; } + if (!wlr_output_init_render(wlr_output, server->allocator, + server->renderer)) { + sway_log(SWAY_ERROR, "Failed to init output render"); + return; + } + struct sway_output *output = output_create(wlr_output); if (!output) { return; diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 17fc8f6f..6c8c77ed 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -52,7 +52,7 @@ static int scale_length(int length, int offset, float scale) { static void scissor_output(struct wlr_output *wlr_output, pixman_box32_t *rect) { - struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); + struct wlr_renderer *renderer = wlr_output->renderer; assert(renderer); struct wlr_box box = { @@ -100,8 +100,7 @@ static void render_texture(struct wlr_output *wlr_output, pixman_region32_t *output_damage, struct wlr_texture *texture, const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const float matrix[static 9], float alpha) { - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); + struct wlr_renderer *renderer = wlr_output->renderer; struct sway_output *output = wlr_output->data; pixman_region32_t damage; @@ -218,8 +217,7 @@ void render_rect(struct sway_output *output, pixman_region32_t *output_damage, const struct wlr_box *_box, float color[static 4]) { struct wlr_output *wlr_output = output->wlr_output; - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); + struct wlr_renderer *renderer = wlr_output->renderer; struct wlr_box box; memcpy(&box, _box, sizeof(struct wlr_box)); @@ -1013,13 +1011,7 @@ static void render_seatops(struct sway_output *output, void output_render(struct sway_output *output, struct timespec *when, pixman_region32_t *damage) { struct wlr_output *wlr_output = output->wlr_output; - - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); - if (!sway_assert(renderer != NULL, - "expected the output backend to have a renderer")) { - return; - } + struct wlr_renderer *renderer = output->server->renderer; struct sway_workspace *workspace = output->current.active_workspace; if (workspace == NULL) { diff --git a/sway/server.c b/sway/server.c index b187fcd5..0d179c88 100644 --- a/sway/server.c +++ b/sway/server.c @@ -73,12 +73,23 @@ static void handle_drm_lease_request(struct wl_listener *listener, void *data) { bool server_init(struct sway_server *server) { sway_log(SWAY_DEBUG, "Initializing Wayland server"); - struct wlr_renderer *renderer = wlr_backend_get_renderer(server->backend); - assert(renderer); + server->renderer = wlr_renderer_autocreate(server->backend); + if (!server->renderer) { + sway_log(SWAY_ERROR, "Failed to create renderer"); + return false; + } - wlr_renderer_init_wl_display(renderer, server->wl_display); + wlr_renderer_init_wl_display(server->renderer, server->wl_display); - server->compositor = wlr_compositor_create(server->wl_display, renderer); + server->allocator = wlr_allocator_autocreate(server->backend, + server->renderer); + if (!server->allocator) { + sway_log(SWAY_ERROR, "Failed to create allocator"); + return false; + } + + server->compositor = wlr_compositor_create(server->wl_display, + server->renderer); server->compositor_new_surface.notify = handle_compositor_new_surface; wl_signal_add(&server->compositor->events.new_surface, &server->compositor_new_surface); @@ -212,7 +223,8 @@ bool server_init(struct sway_server *server) { root->noop_output = output_create(wlr_output); server->headless_backend = - wlr_headless_backend_create_with_renderer(server->wl_display, renderer); + wlr_headless_backend_create_with_renderer(server->wl_display, + server->renderer); if (!server->headless_backend) { sway_log(SWAY_INFO, "Failed to create secondary headless backend, " "starting without it"); diff --git a/sway/tree/container.c b/sway/tree/container.c index 943d3d53..eb88b47e 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -547,8 +547,7 @@ static void render_titlebar_text_texture(struct sway_output *output, cairo_surface_flush(surface); unsigned char *data = cairo_image_surface_get_data(surface); int stride = cairo_image_surface_get_stride(surface); - struct wlr_renderer *renderer = wlr_backend_get_renderer( - output->wlr_output->backend); + struct wlr_renderer *renderer = output->wlr_output->renderer; *texture = wlr_texture_from_pixels( renderer, DRM_FORMAT_ARGB8888, stride, width, height, data); cairo_surface_destroy(surface); From a23cdbbea145e0890627743d316c0ab6fe6c9c1f Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Thu, 2 Sep 2021 21:45:23 -0400 Subject: [PATCH 19/59] Add 'output render_bit_depth [8|10]' command This makes it possible to hint to the renderer and backends how many bits per channel the buffers that the compositor draws windows onto should have. Renderers and backends may deviate from this if they do not support the formats with higher bit depth. --- include/sway/commands.h | 1 + include/sway/config.h | 7 +++++ sway/commands/output.c | 1 + sway/commands/output/render_bit_depth.c | 29 +++++++++++++++++++ sway/config/output.c | 38 +++++++++++++++++++++++++ sway/meson.build | 1 + sway/sway-output.5.scd | 15 ++++++++++ 7 files changed, 92 insertions(+) create mode 100644 sway/commands/output/render_bit_depth.c diff --git a/include/sway/commands.h b/include/sway/commands.h index 4be40870..c6f5c2e0 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -284,6 +284,7 @@ sway_cmd output_cmd_max_render_time; sway_cmd output_cmd_mode; sway_cmd output_cmd_modeline; sway_cmd output_cmd_position; +sway_cmd output_cmd_render_bit_depth; sway_cmd output_cmd_scale; sway_cmd output_cmd_scale_filter; sway_cmd output_cmd_subpixel; diff --git a/include/sway/config.h b/include/sway/config.h index 660245c1..aa71209d 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -247,6 +247,12 @@ enum scale_filter_mode { SCALE_FILTER_SMART, }; +enum render_bit_depth { + RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8 + RENDER_BIT_DEPTH_8, + RENDER_BIT_DEPTH_10, +}; + /** * Size and position configuration for a particular output. * @@ -266,6 +272,7 @@ struct output_config { enum wl_output_subpixel subpixel; int max_render_time; // In milliseconds int adaptive_sync; + enum render_bit_depth render_bit_depth; char *background; char *background_option; diff --git a/sway/commands/output.c b/sway/commands/output.c index d8ef2885..42230bd7 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -18,6 +18,7 @@ static const struct cmd_handler output_handlers[] = { { "modeline", output_cmd_modeline }, { "pos", output_cmd_position }, { "position", output_cmd_position }, + { "render_bit_depth", output_cmd_render_bit_depth }, { "res", output_cmd_mode }, { "resolution", output_cmd_mode }, { "scale", output_cmd_scale }, diff --git a/sway/commands/output/render_bit_depth.c b/sway/commands/output/render_bit_depth.c new file mode 100644 index 00000000..c419321e --- /dev/null +++ b/sway/commands/output/render_bit_depth.c @@ -0,0 +1,29 @@ +#include +#include +#include "sway/commands.h" +#include "sway/config.h" + +struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) { + if (!config->handler_context.output_config) { + return cmd_results_new(CMD_FAILURE, "Missing output config"); + } + if (!argc) { + return cmd_results_new(CMD_INVALID, "Missing bit depth argument."); + } + + if (strcmp(*argv, "8") == 0) { + config->handler_context.output_config->render_bit_depth = + RENDER_BIT_DEPTH_8; + } else if (strcmp(*argv, "10") == 0) { + config->handler_context.output_config->render_bit_depth = + RENDER_BIT_DEPTH_10; + } else { + return cmd_results_new(CMD_INVALID, + "Invalid bit depth. Must be a value in (8|10)."); + } + + config->handler_context.leftovers.argc = argc - 1; + config->handler_context.leftovers.argv = argv + 1; + return NULL; +} + diff --git a/sway/config/output.c b/sway/config/output.c index 6d39c2f5..63c81382 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -1,5 +1,6 @@ #define _POSIX_C_SOURCE 200809L #include +#include #include #include #include @@ -67,6 +68,7 @@ struct output_config *new_output_config(const char *name) { oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; oc->max_render_time = -1; oc->adaptive_sync = -1; + oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT; return oc; } @@ -113,6 +115,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) { if (src->adaptive_sync != -1) { dst->adaptive_sync = src->adaptive_sync; } + if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { + dst->render_bit_depth = src->render_bit_depth; + } if (src->background) { free(dst->background); dst->background = strdup(src->background); @@ -351,6 +356,23 @@ static int compute_default_scale(struct wlr_output *output) { return 2; } +/* Lists of formats to try, in order, when a specific render bit depth has + * been asked for. The second to last format in each list should always + * be XRGB8888, as a reliable backup in case the others are not available; + * the last should be DRM_FORMAT_INVALID, to indicate the end of the list. */ +static const uint32_t *bit_depth_preferences[] = { + [RENDER_BIT_DEPTH_8] = (const uint32_t []){ + DRM_FORMAT_XRGB8888, + DRM_FORMAT_INVALID, + }, + [RENDER_BIT_DEPTH_10] = (const uint32_t []){ + DRM_FORMAT_XRGB2101010, + DRM_FORMAT_XBGR2101010, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_INVALID, + }, +}; + static void queue_output_config(struct output_config *oc, struct sway_output *output) { if (output == root->noop_output) { @@ -437,6 +459,22 @@ static void queue_output_config(struct output_config *oc, oc->adaptive_sync); wlr_output_enable_adaptive_sync(wlr_output, oc->adaptive_sync == 1); } + + if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { + const uint32_t *fmts = bit_depth_preferences[oc->render_bit_depth]; + assert(fmts); + + for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) { + wlr_output_set_render_format(wlr_output, fmts[i]); + if (wlr_output_test(wlr_output)) { + break; + } + + sway_log(SWAY_DEBUG, "Preferred output format 0x%08x " + "failed to work, falling back to next in " + "list, 0x%08x", fmts[i], fmts[i + 1]); + } + } } bool apply_output_config(struct output_config *oc, struct sway_output *output) { diff --git a/sway/meson.build b/sway/meson.build index 1402db15..8eab31a2 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -188,6 +188,7 @@ sway_sources = files( 'commands/output/max_render_time.c', 'commands/output/mode.c', 'commands/output/position.c', + 'commands/output/render_bit_depth.c', 'commands/output/scale.c', 'commands/output/scale_filter.c', 'commands/output/subpixel.c', diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd index 55d8f719..4159a851 100644 --- a/sway/sway-output.5.scd +++ b/sway/sway-output.5.scd @@ -157,6 +157,21 @@ must be separated by one space. For example: adaptive sync can improve latency, but can cause flickering on some hardware. +*output* render_bit_depth 8|10 + Controls the color channel bit depth at which frames are rendered; the + default is currently 8 bits per channel. + + Setting higher values will not have an effect if hardware and software lack + support for such bit depths. Successfully increasing the render bit depth + will not necessarily increase the bit depth of the frames sent to a display. + An increased render bit depth may provide smoother rendering of gradients, + and screenshots which can more precisely store the colors of programs + which display high bit depth colors. + + Warnings: this can break screenshot/screencast programs which have not been + updated to work with different bit depths. This command is experimental, + and may be removed or changed in the future. + # SEE ALSO *sway*(5) *sway-input*(5) From 94dc486f0e2eb1693b64dcc84309794f17d0f79b Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Mon, 22 Nov 2021 20:52:19 -0800 Subject: [PATCH 20/59] ipc: make `bar mode|hidden_state` behave as documented sway-bar(5) says: > For compatibility with i3, bar mode [] syntax is > supported along with the sway only bar mode syntax. while the actual behavior is that `bar_cmd_mode` ignores already selected `config->current_bar` and applies the change to all the configured bars. --- sway/commands/bar/hidden_state.c | 2 +- sway/commands/bar/mode.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c index 1f08a5d2..8b661e3a 100644 --- a/sway/commands/bar/hidden_state.c +++ b/sway/commands/bar/hidden_state.c @@ -54,7 +54,7 @@ struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { } const char *state = argv[0]; - if (config->reading) { + if (config->current_bar) { error = bar_set_hidden_state(config->current_bar, state); } else { const char *id = argc == 2 ? argv[1] : NULL; diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c index 8b3fb275..7c2f423b 100644 --- a/sway/commands/bar/mode.c +++ b/sway/commands/bar/mode.c @@ -58,7 +58,7 @@ struct cmd_results *bar_cmd_mode(int argc, char **argv) { } const char *mode = argv[0]; - if (config->reading) { + if (config->current_bar) { error = bar_set_mode(config->current_bar, mode); } else { const char *id = argc == 2 ? argv[1] : NULL; From f627cd77d6a889e97eb1e6b889322e70482d441c Mon Sep 17 00:00:00 2001 From: Ludvig Michaelsson Date: Sun, 21 Nov 2021 10:55:20 +0100 Subject: [PATCH 21/59] swaybar: signal status command's process group Make the status command a process group leader and change the kill(2) calls to target the new process group. Signals sent by swaybar will then be received by both the status command and its children, if any. While here, check the result of fork(2). Without this, children spawned by the status command may not receive the signals sent by swaybar. As a result, these children may be orphaned on reload. The issue could be shown by setting the bar to bar { status_command i3status | tee /tmp/i3status.out } which would leave orphaned processes for each reload of sway $ ps o pid,ppid,cmd | grep i3status | grep -v grep 43633 43624 sh -c i3status | tee /tmp/i3status.out 43634 43633 i3status 43635 43633 tee /tmp/i3status.out $ swaymsg reload $ ps o pid,ppid,cmd | grep i3status | grep -v grep 43634 1 i3status 43635 1 tee /tmp/i3status.out 43801 43788 sh -c i3status | tee /tmp/i3status.out 43802 43801 i3status 43803 43801 tee /tmp/i3status.out This fixes #5584. --- swaybar/bar.c | 2 +- swaybar/status_line.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/swaybar/bar.c b/swaybar/bar.c index 15eab782..18b87e6d 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -172,7 +172,7 @@ bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) { if (bar->status) { sway_log(SWAY_DEBUG, "Sending %s signal to status command", visible ? "cont" : "stop"); - kill(bar->status->pid, visible ? + kill(-bar->status->pid, visible ? bar->status->cont_signal : bar->status->stop_signal); } } diff --git a/swaybar/status_line.c b/swaybar/status_line.c index ecd91032..a97f3525 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -157,7 +157,12 @@ struct status_line *status_line_init(char *cmd) { assert(!getenv("WAYLAND_SOCKET") && "display must be initialized before " " starting `status-command`; WAYLAND_SOCKET should not be set"); status->pid = fork(); - if (status->pid == 0) { + if (status->pid < 0) { + sway_log_errno(SWAY_ERROR, "fork failed"); + exit(1); + } else if (status->pid == 0) { + setpgid(0, 0); + dup2(pipe_read_fd[1], STDOUT_FILENO); close(pipe_read_fd[0]); close(pipe_read_fd[1]); @@ -185,8 +190,8 @@ struct status_line *status_line_init(char *cmd) { void status_line_free(struct status_line *status) { status_line_close_fds(status); - kill(status->pid, status->cont_signal); - kill(status->pid, SIGTERM); + kill(-status->pid, status->cont_signal); + kill(-status->pid, SIGTERM); waitpid(status->pid, NULL, 0); if (status->protocol == PROTOCOL_I3BAR) { struct i3bar_block *block, *tmp; From 729e18bff5ff5a648a309d645cae100608defd4c Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 25 Nov 2021 16:20:54 +0100 Subject: [PATCH 22/59] Replace wlr_headless_backend_create_with_renderer call Update for the wlroots breaking change in [1]. [1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3367 --- sway/server.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sway/server.c b/sway/server.c index 0d179c88..246f9c4f 100644 --- a/sway/server.c +++ b/sway/server.c @@ -222,12 +222,11 @@ bool server_init(struct sway_server *server) { struct wlr_output *wlr_output = wlr_noop_add_output(server->noop_backend); root->noop_output = output_create(wlr_output); - server->headless_backend = - wlr_headless_backend_create_with_renderer(server->wl_display, - server->renderer); + server->headless_backend = wlr_headless_backend_create(server->wl_display); if (!server->headless_backend) { - sway_log(SWAY_INFO, "Failed to create secondary headless backend, " - "starting without it"); + sway_log(SWAY_ERROR, "Failed to create secondary headless backend"); + wlr_backend_destroy(server->backend); + return false; } else { wlr_multi_backend_add(server->backend, server->headless_backend); } From 0cd8efe0bb669e71e9cdc30d96ae466cb583e605 Mon Sep 17 00:00:00 2001 From: Simon Zeni Date: Mon, 4 Oct 2021 10:04:46 -0400 Subject: [PATCH 23/59] sway: replace noop_output by fallback_output wlroots removed the support for the noop backend. Instead we rely on the headless backend to provide the fallback output. --- include/sway/server.h | 1 - include/sway/tree/root.h | 2 +- sway/commands/output.c | 6 +++--- sway/config/output.c | 6 +++--- sway/desktop/layer_shell.c | 2 +- sway/desktop/output.c | 6 +++++- sway/ipc-server.c | 2 +- sway/server.c | 11 +++++------ sway/tree/output.c | 6 +++--- sway/tree/root.c | 8 ++++---- sway/tree/workspace.c | 4 ++-- 11 files changed, 28 insertions(+), 26 deletions(-) diff --git a/include/sway/server.h b/include/sway/server.h index 109097d7..7ac2af26 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -33,7 +33,6 @@ struct sway_server { const char *socket; struct wlr_backend *backend; - struct wlr_backend *noop_backend; // secondary headless backend used for creating virtual outputs on-the-fly struct wlr_backend *headless_backend; struct wlr_renderer *renderer; diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h index e8f4d573..5d4a2f2d 100644 --- a/include/sway/tree/root.h +++ b/include/sway/tree/root.h @@ -31,7 +31,7 @@ struct sway_root { list_t *scratchpad; // struct sway_container // For when there's no connected outputs - struct sway_output *noop_output; + struct sway_output *fallback_output; struct sway_container *fullscreen_global; diff --git a/sway/commands/output.c b/sway/commands/output.c index 42230bd7..125df5a7 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -34,9 +34,9 @@ struct cmd_results *cmd_output(int argc, char **argv) { return error; } - // The NOOP-1 output is a dummy output used when there's no outputs + // The HEADLESS-1 output is a dummy output used when there's no outputs // connected. It should never be configured. - if (strcasecmp(argv[0], root->noop_output->wlr_output->name) == 0) { + if (strcasecmp(argv[0], root->fallback_output->wlr_output->name) == 0) { return cmd_results_new(CMD_FAILURE, "Refusing to configure the no op output"); } @@ -53,7 +53,7 @@ struct cmd_results *cmd_output(int argc, char **argv) { if (!sway_output) { return cmd_results_new(CMD_FAILURE, "Unknown output"); } - if (sway_output == root->noop_output) { + if (sway_output == root->fallback_output) { return cmd_results_new(CMD_FAILURE, "Refusing to configure the no op output"); } diff --git a/sway/config/output.c b/sway/config/output.c index 63c81382..fa509252 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -375,7 +375,7 @@ static const uint32_t *bit_depth_preferences[] = { static void queue_output_config(struct output_config *oc, struct sway_output *output) { - if (output == root->noop_output) { + if (output == root->fallback_output) { return; } @@ -478,7 +478,7 @@ static void queue_output_config(struct output_config *oc, } bool apply_output_config(struct output_config *oc, struct sway_output *output) { - if (output == root->noop_output) { + if (output == root->fallback_output) { return false; } @@ -573,7 +573,7 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { } bool test_output_config(struct output_config *oc, struct sway_output *output) { - if (output == root->noop_output) { + if (output == root->fallback_output) { return false; } diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 7f5a337b..db78b59f 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -624,7 +624,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { output = ws->output; } } - if (!output || output == root->noop_output) { + if (!output || output == root->fallback_output) { if (!root->outputs->length) { sway_log(SWAY_ERROR, "no output to auto-assign layer surface '%s' to", diff --git a/sway/desktop/output.c b/sway/desktop/output.c index cd9fd3a6..ed6bc064 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -733,7 +733,7 @@ static void update_output_manager_config(struct sway_server *server) { struct sway_output *output; wl_list_for_each(output, &root->all_outputs, link) { - if (output == root->noop_output) { + if (output == root->fallback_output) { continue; } struct wlr_output_configuration_head_v1 *config_head = @@ -838,6 +838,10 @@ static void handle_present(struct wl_listener *listener, void *data) { void handle_new_output(struct wl_listener *listener, void *data) { struct sway_server *server = wl_container_of(listener, server, new_output); struct wlr_output *wlr_output = data; + if (wlr_output == root->fallback_output->wlr_output) { + return; + } + sway_log(SWAY_DEBUG, "New output %p: %s (non-desktop: %d)", wlr_output, wlr_output->name, wlr_output->non_desktop); diff --git a/sway/ipc-server.c b/sway/ipc-server.c index aad9a7b5..1bf5a05f 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -687,7 +687,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt } struct sway_output *output; wl_list_for_each(output, &root->all_outputs, link) { - if (!output->enabled && output != root->noop_output) { + if (!output->enabled && output != root->fallback_output) { json_object_array_add(outputs, ipc_json_describe_disabled_output(output)); } diff --git a/sway/server.c b/sway/server.c index 246f9c4f..ff269c79 100644 --- a/sway/server.c +++ b/sway/server.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -217,11 +216,6 @@ bool server_init(struct sway_server *server) { return false; } - server->noop_backend = wlr_noop_backend_create(server->wl_display); - - struct wlr_output *wlr_output = wlr_noop_add_output(server->noop_backend); - root->noop_output = output_create(wlr_output); - server->headless_backend = wlr_headless_backend_create(server->wl_display); if (!server->headless_backend) { sway_log(SWAY_ERROR, "Failed to create secondary headless backend"); @@ -231,6 +225,10 @@ bool server_init(struct sway_server *server) { wlr_multi_backend_add(server->backend, server->headless_backend); } + struct wlr_output *wlr_output = + wlr_headless_add_output(server->headless_backend, 800, 600); + root->fallback_output = output_create(wlr_output); + // This may have been set already via -Dtxn-timeout if (!server->txn_timeout_ms) { server->txn_timeout_ms = 200; @@ -287,6 +285,7 @@ bool server_start(struct sway_server *server) { wlr_backend_destroy(server->backend); return false; } + return true; } diff --git a/sway/tree/output.c b/sway/tree/output.c index c095dce0..242e6fac 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -56,8 +56,8 @@ static void restore_workspaces(struct sway_output *output) { } // Saved workspaces - while (root->noop_output->workspaces->length) { - struct sway_workspace *ws = root->noop_output->workspaces->items[0]; + while (root->fallback_output->workspaces->length) { + struct sway_workspace *ws = root->fallback_output->workspaces->items[0]; workspace_detach(ws); output_add_workspace(output, ws); @@ -192,7 +192,7 @@ static void output_evacuate(struct sway_output *output) { new_output = fallback_output; } if (!new_output) { - new_output = root->noop_output; + new_output = root->fallback_output; } struct sway_workspace *new_output_ws = diff --git a/sway/tree/root.c b/sway/tree/root.c index dd4d8e33..73f3993c 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -374,8 +374,8 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data), } // Saved workspaces - for (int i = 0; i < root->noop_output->workspaces->length; ++i) { - struct sway_workspace *ws = root->noop_output->workspaces->items[i]; + for (int i = 0; i < root->fallback_output->workspaces->length; ++i) { + struct sway_workspace *ws = root->fallback_output->workspaces->items[i]; workspace_for_each_container(ws, f, data); } } @@ -427,8 +427,8 @@ struct sway_container *root_find_container( } // Saved workspaces - for (int i = 0; i < root->noop_output->workspaces->length; ++i) { - struct sway_workspace *ws = root->noop_output->workspaces->items[i]; + for (int i = 0; i < root->fallback_output->workspaces->length; ++i) { + struct sway_workspace *ws = root->fallback_output->workspaces->items[i]; if ((result = workspace_find_container(ws, test, data))) { return result; } diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index e3ff1513..c84320bd 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -50,8 +50,8 @@ struct sway_output *workspace_get_initial_output(const char *name) { } else if (focus && focus->type == N_CONTAINER) { return focus->sway_container->pending.workspace->output; } - // Fallback to the first output or noop output for headless - return root->outputs->length ? root->outputs->items[0] : root->noop_output; + // Fallback to the first output or the headless output + return root->outputs->length ? root->outputs->items[0] : root->fallback_output; } struct sway_workspace *workspace_create(struct sway_output *output, From 02b412a3d4e930237a1d16554af6e1e7d1855c89 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 24 Oct 2021 21:34:36 +0200 Subject: [PATCH 24/59] build: use list for sdbus dep This allows to simplify our logic. Meson will pick the first found library. --- meson.build | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/meson.build b/meson.build index 436b84d1..72bce0ee 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project( 'c', version: '1.6', license: 'MIT', - meson_version: '>=0.59.0', + meson_version: '>=0.60.0', default_options: [ 'c_std=c11', 'warning_level=2', @@ -92,30 +92,15 @@ if get_option('sd-bus-provider') == 'auto' if not get_option('tray').disabled() assert(get_option('auto_features').auto(), 'sd-bus-provider must not be set to auto since auto_features != auto') endif - sdbus = dependency('libsystemd', - required: false, + sdbus = dependency(['libsystemd', 'libelogind', 'basu'], + required: get_option('tray'), version: '>=239', - not_found_message: 'libsystemd not found, trying libelogind', ) - if not sdbus.found() - sdbus = dependency('libelogind', - required: false, - version: '>=239', - not_found_message: 'libelogind not found, trying basu', - ) - endif - if not sdbus.found() - sdbus = dependency('basu', required: false) - endif else sdbus = dependency(get_option('sd-bus-provider'), required: get_option('tray')) endif -tray_deps_found = sdbus.found() -if get_option('tray').enabled() and not tray_deps_found - error('Building with -Dtray=enabled, but sd-bus has not been not found') -endif -have_tray = (not get_option('tray').disabled()) and tray_deps_found +have_tray = sdbus.found() conf_data = configuration_data() From b518b1295cc0eb4237f695ee31bb8e0bba773a20 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 5 Dec 2021 19:21:09 +0100 Subject: [PATCH 25/59] Delete .clang-format This file isn't accurate, and clang-format can't describe our code style. References: https://github.com/swaywm/sway/pull/6249#issuecomment-986214042 --- .clang-format | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .clang-format diff --git a/.clang-format b/.clang-format deleted file mode 100644 index 24ea869d..00000000 --- a/.clang-format +++ /dev/null @@ -1,18 +0,0 @@ -BasedOnStyle: LLVM -IndentWidth: 4 -TabWidth: 4 -UseTab: Always -BreakBeforeBraces: Attach -AllowShortIfStatementsOnASingleLine: false -IndentCaseLabels: false -SortIncludes: false -ColumnLimit: 80 -AlignAfterOpenBracket: DontAlign -BinPackParameters: true -BinPackArguments: true -ContinuationIndentWidth: 8 -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortLoopsOnASingleLine: true -ReflowComments: false -AllowAllArgumentsOnNextLine: false -AlignOperands: DontAlign From 03a29ed36df22f39198168c95d940a59578daa49 Mon Sep 17 00:00:00 2001 From: Kirill Primak Date: Sat, 4 Dec 2021 20:39:13 +0300 Subject: [PATCH 26/59] output: remove surface buffer damage check A surface can have effective damage even without any buffer damage committed. --- sway/desktop/output.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index ed6bc064..e0d76349 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -633,21 +633,19 @@ static void damage_surface_iterator(struct sway_output *output, struct wlr_box box = *_box; scale_box(&box, output->wlr_output->scale); - if (pixman_region32_not_empty(&surface->buffer_damage)) { - pixman_region32_t damage; - pixman_region32_init(&damage); - wlr_surface_get_effective_damage(surface, &damage); - wlr_region_scale(&damage, &damage, output->wlr_output->scale); - if (ceil(output->wlr_output->scale) > surface->current.scale) { - // When scaling up a surface, it'll become blurry so we need to - // expand the damage region - wlr_region_expand(&damage, &damage, - ceil(output->wlr_output->scale) - surface->current.scale); - } - pixman_region32_translate(&damage, box.x, box.y); - wlr_output_damage_add(output->damage, &damage); - pixman_region32_fini(&damage); + pixman_region32_t damage; + pixman_region32_init(&damage); + wlr_surface_get_effective_damage(surface, &damage); + wlr_region_scale(&damage, &damage, output->wlr_output->scale); + if (ceil(output->wlr_output->scale) > surface->current.scale) { + // When scaling up a surface, it'll become blurry so we need to + // expand the damage region + wlr_region_expand(&damage, &damage, + ceil(output->wlr_output->scale) - surface->current.scale); } + pixman_region32_translate(&damage, box.x, box.y); + wlr_output_damage_add(output->damage, &damage); + pixman_region32_fini(&damage); if (whole) { wlr_output_damage_add_box(output->damage, &box); From 1eaa61f503f38673db2c18d22515406c66d13424 Mon Sep 17 00:00:00 2001 From: "M.Zeinali" Date: Tue, 7 Dec 2021 17:56:57 +0330 Subject: [PATCH 27/59] readme: use right-to-left marks in ir translation --- README.ir.md | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/README.ir.md b/README.ir.md index bd0849b6..4542b93b 100644 --- a/README.ir.md +++ b/README.ir.md @@ -1,9 +1,7 @@ -
- # sway -sway یک کامپوزیتور الهام گرفته از [i3](https://i3wm.org/) بر روی [Wayland](http://wayland.freedesktop.org/) است. [سوال‌های متداول](https://github.com/swaywm/sway/wiki) را بخوانید. در [کانال -IRC](http://web.libera.chat/gamja/?channels=sway&uio=d4) عضو شوید (#sway sur +‏sway یک کامپوزیتور الهام گرفته از [i3](https://i3wm.org/) بر روی [Wayland](http://wayland.freedesktop.org/) است. [سوال‌های متداول](https://github.com/swaywm/sway/wiki) را بخوانید. در [کانال +IRC](http://web.libera.chat/gamja/?channels=sway&uio=d4) عضو شوید (‎#sway‏ در irc.libera.chat). برای حمایت از تیم توسعه sway به [صفحه @@ -17,7 +15,7 @@ Patreon با نام کاربری SirCmpwn](https://patreon.com/sircmpwn) مرا ### از بسته‌های رسمی -sway در بسته‌های رسمی توزیع‌های مختلف وجود دارد. بسته «sway» را نصب کنید. در صورتی که بسته رسمی وجود نداشت، برای آگاهی بیشتر درباره نصب روی توزیعتان به این [صفحه راهنما](https://github.com/swaywm/sway/wiki/Unsupported-packages) مراجعه کنید. +‏sway در بسته‌های رسمی توزیع‌های مختلف وجود دارد. بسته «sway» را نصب کنید. در صورتی که بسته رسمی وجود نداشت، برای آگاهی بیشتر درباره نصب روی توزیعتان به این [صفحه راهنما](https://github.com/swaywm/sway/wiki/Unsupported-packages) مراجعه کنید. اگر به ایجاد بسته sway برای توزیعتان علاقه‌مند هستید، از کانال IRC استفاده کنید یا به sir@cmpwn.com ایمیل بزنید. @@ -42,21 +40,16 @@ sway در بسته‌های رسمی توزیع‌های مختلف وجود د _\*نیازمندی‌های زمان کامپایل برنامه_ این فرمان‌ها را اجرا کنید: -
meson build ninja -C build sudo ninja -C build install -
- روی سیستم‌های بدون logind، باید فرمان زیر را برای suid کردن باینری sway اجرا کنید: -
sudo chmod a+s /usr/local/bin/sway -
-sway پس از startup مجوزهای دسترسی root را رها می‌کند. +‏sway پس از startup مجوزهای دسترسی root را رها می‌کند. ### شخصی سازی و تنظیمات @@ -64,7 +57,4 @@ sway پس از startup مجوزهای دسترسی root را رها می‌کن ## اجرا -در محیط TTY کافیست `sway` را اجرا کنید. ممکن است ابزارهای مدیریت نمایشگری نیز برای این کار وجود داشته باشند اما از طرف sway پشتیبانی نمی‌شوند (gdm عملکرد خوبی در این زمینه دارد). - -
- +در محیط TTY کافیست `sway` را اجرا کنید. ممکن است ابزارهای مدیریت نمایشگری نیز برای این کار وجود داشته باشند اما از طرف sway پشتیبانی نمی‌شوند (gdm عملکرد خوبی در این زمینه دارد). From 3f58f12617ca4d6a311d060081e40bf01a73c239 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 9 Dec 2021 15:55:58 +0100 Subject: [PATCH 28/59] Fixup headless output names We use the headless backend to create a special fallback output used when no other output is connected. However this messes up the "real" headless output names users have come to expect (e.g. currently the first headless output will be named "HEADLESS-2" instead of "HEADLESS-1"). Fix this by setting the output name with [1]. [1]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3395 --- sway/desktop/output.c | 10 ++++++++++ sway/server.c | 1 + 2 files changed, 11 insertions(+) diff --git a/sway/desktop/output.c b/sway/desktop/output.c index e0d76349..3ae97e66 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -833,13 +834,22 @@ static void handle_present(struct wl_listener *listener, void *data) { output->refresh_nsec = output_event->refresh; } +static unsigned int last_headless_num = 0; + void handle_new_output(struct wl_listener *listener, void *data) { struct sway_server *server = wl_container_of(listener, server, new_output); struct wlr_output *wlr_output = data; + if (wlr_output == root->fallback_output->wlr_output) { return; } + if (wlr_output_is_headless(wlr_output)) { + char name[64]; + snprintf(name, sizeof(name), "HEADLESS-%u", ++last_headless_num); + wlr_output_set_name(wlr_output, name); + } + sway_log(SWAY_DEBUG, "New output %p: %s (non-desktop: %d)", wlr_output, wlr_output->name, wlr_output->non_desktop); diff --git a/sway/server.c b/sway/server.c index ff269c79..582a04ab 100644 --- a/sway/server.c +++ b/sway/server.c @@ -227,6 +227,7 @@ bool server_init(struct sway_server *server) { struct wlr_output *wlr_output = wlr_headless_add_output(server->headless_backend, 800, 600); + wlr_output_set_name(wlr_output, "FALLBACK"); root->fallback_output = output_create(wlr_output); // This may have been set already via -Dtxn-timeout From f7725011efd3bc2762a0d1002ea5071470962213 Mon Sep 17 00:00:00 2001 From: Vsevolod Date: Fri, 10 Dec 2021 17:09:29 +0200 Subject: [PATCH 29/59] Add focused_tab_title --- include/sway/commands.h | 1 + include/sway/config.h | 3 +++ include/sway/tree/container.h | 2 ++ sway/commands.c | 1 + sway/commands/client.c | 16 ++++++++++++++++ sway/config.c | 2 ++ sway/desktop/render.c | 18 +++++++++++++++++- sway/sway.5.scd | 12 ++++++++++++ sway/tree/container.c | 6 ++++++ 9 files changed, 60 insertions(+), 1 deletion(-) diff --git a/include/sway/commands.h b/include/sway/commands.h index c6f5c2e0..2746ef28 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -112,6 +112,7 @@ sway_cmd cmd_border; sway_cmd cmd_client_noop; sway_cmd cmd_client_focused; sway_cmd cmd_client_focused_inactive; +sway_cmd cmd_client_focused_tab_title; sway_cmd cmd_client_unfocused; sway_cmd cmd_client_urgent; sway_cmd cmd_client_placeholder; diff --git a/include/sway/config.h b/include/sway/config.h index aa71209d..fda0e83f 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -548,12 +548,15 @@ struct sway_config { struct { struct border_colors focused; struct border_colors focused_inactive; + struct border_colors focused_tab_title; struct border_colors unfocused; struct border_colors urgent; struct border_colors placeholder; float background[4]; } border_colors; + bool has_focused_tab_title; + // floating view int32_t floating_maximum_width; int32_t floating_maximum_height; diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 97fa98c1..05761150 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -117,12 +117,14 @@ struct sway_container { struct wlr_texture *title_focused; struct wlr_texture *title_focused_inactive; + struct wlr_texture *title_focused_tab_title; struct wlr_texture *title_unfocused; struct wlr_texture *title_urgent; list_t *marks; // char * struct wlr_texture *marks_focused; struct wlr_texture *marks_focused_inactive; + struct wlr_texture *marks_focused_tab_title; struct wlr_texture *marks_unfocused; struct wlr_texture *marks_urgent; diff --git a/sway/commands.c b/sway/commands.c index 205406ad..5a1fd32e 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -51,6 +51,7 @@ static const struct cmd_handler handlers[] = { { "client.background", cmd_client_noop }, { "client.focused", cmd_client_focused }, { "client.focused_inactive", cmd_client_focused_inactive }, + { "client.focused_tab_title", cmd_client_focused_tab_title }, { "client.placeholder", cmd_client_noop }, { "client.unfocused", cmd_client_unfocused }, { "client.urgent", cmd_client_urgent }, diff --git a/sway/commands/client.c b/sway/commands/client.c index dd0694df..77263145 100644 --- a/sway/commands/client.c +++ b/sway/commands/client.c @@ -18,6 +18,12 @@ static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name, return error; } + if (argc > 3 && strcmp(cmd_name, "client.focused_tab_title") == 0) { + sway_log(SWAY_ERROR, + "Warning: indicator and child_border colors have no effect for %s", + cmd_name); + } + struct border_colors colors = {0}; const char *ind_hex = argc > 3 ? argv[3] : default_indicator; const char *child_hex = argc > 4 ? argv[4] : argv[1]; // def to background @@ -80,3 +86,13 @@ struct cmd_results *cmd_client_noop(int argc, char **argv) { sway_log(SWAY_INFO, "Warning: %s is ignored by sway", argv[-1]); return cmd_results_new(CMD_SUCCESS, NULL); } + +struct cmd_results *cmd_client_focused_tab_title(int argc, char **argv) { + struct cmd_results *result = handle_command(argc, argv, + "client.focused_tab_title", + &config->border_colors.focused_tab_title, "#2e9ef4ff"); + if (result && result->status == CMD_SUCCESS) { + config->has_focused_tab_title = true; + } + return result; +} diff --git a/sway/config.c b/sway/config.c index 35837212..e4745a5c 100644 --- a/sway/config.c +++ b/sway/config.c @@ -290,6 +290,8 @@ static void config_defaults(struct sway_config *config) { config->hide_edge_borders_smart = ESMART_OFF; config->hide_lone_tab = false; + config->has_focused_tab_title = false; + // border colors color_to_rgba(config->border_colors.focused.border, 0x4C7899FF); color_to_rgba(config->border_colors.focused.background, 0x285577FF); diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 6c8c77ed..c088c936 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -762,6 +762,14 @@ static void render_containers_linear(struct sway_output *output, } } +static bool container_is_focused(struct sway_container *con, void *data) { + return con->current.focused; +} + +static bool container_has_focused_child(struct sway_container *con) { + return container_find_child(con, container_is_focused, NULL); +} + /** * Render a container's children using the L_TABBED layout. */ @@ -793,6 +801,10 @@ static void render_containers_tabbed(struct sway_output *output, colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = child->marks_focused; + } else if (config->has_focused_tab_title && container_has_focused_child(child)) { + colors = &config->border_colors.focused_tab_title; + title_texture = child->title_focused_tab_title; + marks_texture = child->marks_focused_tab_title; } else if (child == parent->active_child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; @@ -858,7 +870,11 @@ static void render_containers_stacked(struct sway_output *output, colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = child->marks_focused; - } else if (child == parent->active_child) { + } else if (config->has_focused_tab_title && container_has_focused_child(child)) { + colors = &config->border_colors.focused_tab_title; + title_texture = child->title_focused_tab_title; + marks_texture = child->marks_focused_tab_title; + } else if (child == parent->active_child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = child->marks_focused_inactive; diff --git a/sway/sway.5.scd b/sway/sway.5.scd index ec34a56c..641d0925 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -499,6 +499,12 @@ runtime. *client.focused_inactive* The most recently focused view within a container which is not focused. + *client.focused_tab_title* + A view that has focused descendant container. + Tab or stack container title that is the parent of the focused container + but is not directly focused. Defaults to focused_inactive if not + specified and does not use the indicator and child_border colors. + *client.placeholder* Ignored (present for i3 compatibility). @@ -554,6 +560,12 @@ The default colors are: : #ffffff : #484e50 : #5f676a +| *focused_tab_title* +: #333333 +: #5f676a +: #ffffff +: n/a +: n/a | *unfocused* : #333333 : #222222 diff --git a/sway/tree/container.c b/sway/tree/container.c index eb88b47e..0284c9a5 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -64,6 +64,7 @@ void container_destroy(struct sway_container *con) { wlr_texture_destroy(con->title_focused_inactive); wlr_texture_destroy(con->title_unfocused); wlr_texture_destroy(con->title_urgent); + wlr_texture_destroy(con->title_focused_tab_title); list_free(con->pending.children); list_free(con->current.children); list_free(con->outputs); @@ -73,6 +74,7 @@ void container_destroy(struct sway_container *con) { wlr_texture_destroy(con->marks_focused_inactive); wlr_texture_destroy(con->marks_unfocused); wlr_texture_destroy(con->marks_urgent); + wlr_texture_destroy(con->marks_focused_tab_title); if (con->view) { if (con->view->container == con) { @@ -582,6 +584,8 @@ void container_update_title_textures(struct sway_container *container) { &config->border_colors.unfocused); update_title_texture(container, &container->title_urgent, &config->border_colors.urgent); + update_title_texture(container, &container->title_focused_tab_title, + &config->border_colors.focused_tab_title); container_damage_whole(container); } @@ -1635,6 +1639,8 @@ void container_update_marks_textures(struct sway_container *con) { &config->border_colors.unfocused); update_marks_texture(con, &con->marks_urgent, &config->border_colors.urgent); + update_marks_texture(con, &con->marks_focused_tab_title, + &config->border_colors.focused_tab_title); container_damage_whole(con); } From 8a3026337fd892ac7680ef4a33f5a99b4a896723 Mon Sep 17 00:00:00 2001 From: Alexander Orzechowski Date: Mon, 13 Dec 2021 03:02:00 -0500 Subject: [PATCH 30/59] view: Fix null dereference There seems to be a null pointer access that can happen. I was able to reproduce this by running the cemu emulator[1] with the new collabora wine wayland driver[2] and opening and closing some sub menus. Adding a trival null check seems to do the trick to stop sway from crashing and returning to tty and everything else works normally. [1]: http://cemu.info/ [2]: https://www.winehq.org/pipermail/wine-devel/2021-December/203035.html Stack trace from lldb: * thread #1, name = 'sway', stop reason = signal SIGSEGV: invalid address (fault address: 0xf8) frame #0: 0x00005555555c3fc3 sway`view_child_init(child=0x0000555555f67940, impl=0x00005555555ee030, view=0x00005555565bc590, surface=0x00005555565b6940) at view.c:1117:25 1114 wl_signal_add(&view->events.unmap, &child->view_unmap); 1115 child->view_unmap.notify = view_child_handle_view_unmap; 1116 -> 1117 struct sway_workspace *workspace = child->view->container->pending.workspace; 1118 if (workspace) { 1119 wlr_surface_send_enter(child->surface, workspace->output->wlr_output); 1120 } (lldb) up error: sway {0x000342ab}: DIE has DW_AT_ranges(DW_FORM_sec_offset 0x67) attribute, but range extraction failed (invalid range list offset 0x67), please file a bug and attach the file at the start of this error message frame #1: 0x00005555555c39f8 sway`view_child_subsurface_create(child=0x00005555564a10d0, wlr_subsurface=0x0000555556586910) at view.c:985:2 982 } 983 subsurface->child.parent = child; 984 wl_list_insert(&child->children, &subsurface->child.link); -> 985 view_child_init(&subsurface->child, &subsurface_impl, child->view, 986 wlr_subsurface->surface); 987 988 wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); (lldb) up frame #2: 0x00005555555c3c2a sway`view_child_handle_surface_new_subsurface(listener=0x00005555564a1130, data=0x0000555556586910) at view.c:1031:2 1028 struct sway_view_child *child = 1029 wl_container_of(listener, child, surface_new_subsurface); 1030 struct wlr_subsurface *subsurface = data; -> 1031 view_child_subsurface_create(child, subsurface); 1032 } 1033 1034 static void view_child_handle_surface_destroy(struct wl_listener *listener, (lldb) up frame #3: 0x00007ffff78f4bfe libwlroots.so.10`wlr_signal_emit_safe(signal=0x00005555565b2470, data=0x0000555556586910) at signal.c:29:3 26 wl_list_remove(&cursor.link); 27 wl_list_insert(pos, &cursor.link); 28 -> 29 l->notify(l, data); 30 } 31 32 wl_list_remove(&cursor.link); (lldb) up frame #4: 0x00007ffff78e5a41 libwlroots.so.10`subsurface_parent_commit(subsurface=0x0000555556586910) at wlr_surface.c:517:3 514 515 if (!subsurface->added) { 516 subsurface->added = true; -> 517 wlr_signal_emit_safe(&subsurface->parent->events.new_subsurface, 518 subsurface); 519 } 520 } (lldb) up frame #5: 0x00007ffff78e56fa libwlroots.so.10`surface_commit_state(surface=0x00005555565b21b0, next=0x00005555565b2338) at wlr_surface.c:439:3 436 wl_list_insert(&surface->current.subsurfaces_above, 437 &subsurface->current.link); 438 -> 439 subsurface_parent_commit(subsurface); 440 } 441 wl_list_for_each_reverse(subsurface, &surface->pending.subsurfaces_below, 442 pending.link) { (lldb) up frame #6: 0x00007ffff78e5b88 libwlroots.so.10`surface_handle_commit(client=0x0000555556564c80, resource=0x0000555556599a20) at wlr_surface.c:555:3 552 if (surface->pending.cached_state_locks > 0 || !wl_list_empty(&surface->cached)) { 553 surface_cache_pending(surface); 554 } else { -> 555 surface_commit_state(surface, &surface->pending); 556 } 557 } 558 (lldb) up frame #7: 0x00007ffff7000d4a libffi.so.8`___lldb_unnamed_symbol118 + 82 libffi.so.8`___lldb_unnamed_symbol118: -> 0x7ffff7000d4a <+82>: leaq 0x18(%rbp), %rsp 0x7ffff7000d4e <+86>: movq (%rbp), %rcx 0x7ffff7000d52 <+90>: movq 0x8(%rbp), %rdi 0x7ffff7000d56 <+94>: movq 0x10(%rbp), %rbp (lldb) up frame #8: 0x00007ffff7000267 libffi.so.8`___lldb_unnamed_symbol115 + 439 libffi.so.8`___lldb_unnamed_symbol115: -> 0x7ffff7000267 <+439>: movq -0x38(%rbp), %rax 0x7ffff700026b <+443>: subq %fs:0x28, %rax 0x7ffff7000274 <+452>: jne 0x7ffff70004e7 ; <+1079> 0x7ffff700027a <+458>: leaq -0x28(%rbp), %rsp (lldb) up frame #9: 0x00007ffff795a173 libwayland-server.so.0`___lldb_unnamed_symbol271 + 371 libwayland-server.so.0`___lldb_unnamed_symbol271: -> 0x7ffff795a173 <+371>: movq 0x8(%r12), %rax 0x7ffff795a178 <+376>: movq 0x8(%rax), %rdi 0x7ffff795a17c <+380>: movl (%r12), %eax 0x7ffff795a180 <+384>: testl %eax, %eax (lldb) up frame #10: 0x00007ffff795555c libwayland-server.so.0`___lldb_unnamed_symbol210 + 588 libwayland-server.so.0`___lldb_unnamed_symbol210: -> 0x7ffff795555c <+588>: jmp 0x7ffff7955435 ; <+293> 0x7ffff7955561 <+593>: nopl (%rax) 0x7ffff7955568 <+600>: callq *0xd76a(%rip) 0x7ffff795556e <+606>: cmpl $0xb, (%rax) (lldb) up frame #11: 0x00007ffff795804a libwayland-server.so.0`wl_event_loop_dispatch + 202 libwayland-server.so.0`wl_event_loop_dispatch: -> 0x7ffff795804a <+202>: addq $0xc, %r15 0x7ffff795804e <+206>: cmpq %r15, %rbp 0x7ffff7958051 <+209>: jne 0x7ffff7958038 ; <+184> 0x7ffff7958053 <+211>: movq 0x8(%rsp), %rcx1 (lldb) up frame #12: 0x00007ffff7955bc7 libwayland-server.so.0`wl_display_run + 39 libwayland-server.so.0`wl_display_run: -> 0x7ffff7955bc7 <+39>: movl 0x8(%rbx), %eax 0x7ffff7955bca <+42>: testl %eax, %eax 0x7ffff7955bcc <+44>: jne 0x7ffff7955bb0 ; <+16> 0x7ffff7955bce <+46>: popq %rbx (lldb) up frame #13: 0x00005555555756eb sway`server_run(server=0x00005555555f0640) at server.c:296:2 293 void server_run(struct sway_server *server) { 294 sway_log(SWAY_INFO, "Running compositor on wayland display '%s'", 295 server->socket); -> 296 wl_display_run(server->wl_display); 297 } (lldb) up frame #14: 0x0000555555574947 sway`main(argc=1, argv=0x00007fffffffe8d8) at main.c:428:2 425 swaynag_show(&config->swaynag_config_errors); 426 } 427 -> 428 server_run(&server); 429 430 shutdown: 431 sway_log(SWAY_INFO, "Shutting down sway"); (lldb) up frame #15: 0x00007ffff761db25 libc.so.6`__libc_start_main + 213 libc.so.6`__libc_start_main: -> 0x7ffff761db25 <+213>: movl %eax, %edi 0x7ffff761db27 <+215>: callq 0x7ffff7635630 ; exit 0x7ffff761db2c <+220>: movq (%rsp), %rax 0x7ffff761db30 <+224>: leaq 0x163929(%rip), %rdi (lldb) up frame #16: 0x00005555555656be sway`_start + 46 sway`_start: -> 0x5555555656be <+46>: hlt 0x5555555656bf: nop sway`deregister_tm_clones: 0x5555555656c0 <+0>: leaq 0x8aeb9(%rip), %rdi ; optind@GLIBC_2.2.5 0x5555555656c7 <+7>: leaq 0x8aeb2(%rip), %rax ; optind@GLIBC_2.2.5 Signed-off-by: Alexander Orzechowski --- sway/tree/view.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sway/tree/view.c b/sway/tree/view.c index bd53a5c8..1318f5fb 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -1114,9 +1114,12 @@ void view_child_init(struct sway_view_child *child, wl_signal_add(&view->events.unmap, &child->view_unmap); child->view_unmap.notify = view_child_handle_view_unmap; - struct sway_workspace *workspace = child->view->container->pending.workspace; - if (workspace) { - wlr_surface_send_enter(child->surface, workspace->output->wlr_output); + struct sway_container *container = child->view->container; + if (container != NULL) { + struct sway_workspace *workspace = container->pending.workspace; + if (workspace) { + wlr_surface_send_enter(child->surface, workspace->output->wlr_output); + } } view_child_init_subsurfaces(child, surface); From 4732325f591455f1e4bdcb35652505a8a636663a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 7 Jun 2021 18:58:20 +0200 Subject: [PATCH 31/59] Add support for linux-dmabuf surface hints References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/1376 --- include/sway/server.h | 2 ++ protocols/meson.build | 1 + sway/server.c | 10 +++++- sway/tree/container.c | 83 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 1 deletion(-) diff --git a/include/sway/server.h b/include/sway/server.h index 7ac2af26..0bd860b2 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -41,6 +41,8 @@ struct sway_server { struct wlr_compositor *compositor; struct wl_listener compositor_new_surface; + struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1; + struct wlr_data_device_manager *data_device_manager; struct sway_input_manager *input; diff --git a/protocols/meson.build b/protocols/meson.build index 8e9e65be..df24a4e5 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -15,6 +15,7 @@ protocols = [ [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], [wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'], [wl_protocol_dir, 'unstable/tablet/tablet-unstable-v2.xml'], + [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'], ['idle.xml'], ['wlr-input-inhibitor-unstable-v1.xml'], diff --git a/sway/server.c b/sway/server.c index 582a04ab..f50a0987 100644 --- a/sway/server.c +++ b/sway/server.c @@ -13,10 +13,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -78,7 +80,13 @@ bool server_init(struct sway_server *server) { return false; } - wlr_renderer_init_wl_display(server->renderer, server->wl_display); + wlr_renderer_init_wl_shm(server->renderer, server->wl_display); + + if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL) { + wlr_drm_create(server->wl_display, server->renderer); + server->linux_dmabuf_v1 = + wlr_linux_dmabuf_v1_create(server->wl_display, server->renderer); + } server->allocator = wlr_allocator_autocreate(server->backend, server->renderer); diff --git a/sway/tree/container.c b/sway/tree/container.c index 0284c9a5..132b6819 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -5,8 +5,12 @@ #include #include #include +#include #include +#include #include +#include +#include "linux-dmabuf-unstable-v1-protocol.h" #include "cairo_util.h" #include "pango.h" #include "sway/config.h" @@ -1051,6 +1055,16 @@ void container_end_mouse_operation(struct sway_container *container) { } } +static bool devid_from_fd(int fd, dev_t *devid) { + struct stat stat; + if (fstat(fd, &stat) != 0) { + sway_log_errno(SWAY_ERROR, "fstat failed"); + return false; + } + *devid = stat.st_rdev; + return true; +} + static void set_fullscreen(struct sway_container *con, bool enable) { if (!con->view) { return; @@ -1062,6 +1076,75 @@ static void set_fullscreen(struct sway_container *con, bool enable) { con->view->foreign_toplevel, enable); } } + + if (!server.linux_dmabuf_v1 || !con->view->surface) { + return; + } + if (!enable) { + wlr_linux_dmabuf_v1_set_surface_feedback(server.linux_dmabuf_v1, + con->view->surface, NULL); + return; + } + + if (!con->pending.workspace || !con->pending.workspace->output) { + return; + } + + struct sway_output *output = con->pending.workspace->output; + struct wlr_output *wlr_output = output->wlr_output; + + // TODO: add wlroots helpers for all of this stuff + + const struct wlr_drm_format_set *renderer_formats = + wlr_renderer_get_dmabuf_texture_formats(server.renderer); + assert(renderer_formats); + + int renderer_drm_fd = wlr_renderer_get_drm_fd(server.renderer); + int backend_drm_fd = wlr_backend_get_drm_fd(wlr_output->backend); + if (renderer_drm_fd < 0 || backend_drm_fd < 0) { + return; + } + + dev_t render_dev, scanout_dev; + if (!devid_from_fd(renderer_drm_fd, &render_dev) || + !devid_from_fd(backend_drm_fd, &scanout_dev)) { + return; + } + + const struct wlr_drm_format_set *output_formats = + wlr_output_get_primary_formats(output->wlr_output, + WLR_BUFFER_CAP_DMABUF); + if (!output_formats) { + return; + } + + struct wlr_drm_format_set scanout_formats = {0}; + if (!wlr_drm_format_set_intersect(&scanout_formats, + output_formats, renderer_formats)) { + return; + } + + struct wlr_linux_dmabuf_feedback_v1_tranche tranches[] = { + { + .target_device = scanout_dev, + .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, + .formats = &scanout_formats, + }, + { + .target_device = render_dev, + .formats = renderer_formats, + }, + }; + + const struct wlr_linux_dmabuf_feedback_v1 feedback = { + .main_device = render_dev, + .tranches = tranches, + .tranches_len = sizeof(tranches) / sizeof(tranches[0]), + }; + wlr_linux_dmabuf_v1_set_surface_feedback(server.linux_dmabuf_v1, + con->view->surface, &feedback); + + wlr_drm_format_set_finish(&scanout_formats); } static void container_fullscreen_workspace(struct sway_container *con) { From 57a7b3998ea62616223000eb6369c999b4cd1a94 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Mon, 13 Dec 2021 18:33:32 +0100 Subject: [PATCH 32/59] swaynag: remove xdg-output logic We can just get the output name from wl_output directly, now that wl_output version 4 exists. --- include/swaynag/swaynag.h | 3 -- meson.build | 2 +- swaybar/bar.c | 1 - swaynag/swaynag.c | 63 +++++++++++++-------------------------- 4 files changed, 22 insertions(+), 47 deletions(-) diff --git a/include/swaynag/swaynag.h b/include/swaynag/swaynag.h index 9e39e716..baa6ee8b 100644 --- a/include/swaynag/swaynag.h +++ b/include/swaynag/swaynag.h @@ -5,7 +5,6 @@ #include "list.h" #include "pool-buffer.h" #include "swaynag/types.h" -#include "xdg-output-unstable-v1-client-protocol.h" #define SWAYNAG_MAX_HEIGHT 500 @@ -75,13 +74,11 @@ struct swaynag_details { struct swaynag { bool run_display; - int querying_outputs; struct wl_display *display; struct wl_compositor *compositor; struct wl_seat *seat; struct wl_shm *shm; - struct zxdg_output_manager_v1 *xdg_output_manager; struct wl_list outputs; // swaynag_output::link struct wl_list seats; // swaynag_seat::link struct swaynag_output *output; diff --git a/meson.build b/meson.build index 72bce0ee..be1af04a 100644 --- a/meson.build +++ b/meson.build @@ -37,7 +37,7 @@ endif jsonc = dependency('json-c', version: '>=0.13') pcre = dependency('libpcre') -wayland_server = dependency('wayland-server') +wayland_server = dependency('wayland-server', version: '>=1.20.0') wayland_client = dependency('wayland-client') wayland_cursor = dependency('wayland-cursor') wayland_egl = dependency('wayland-egl') diff --git a/swaybar/bar.c b/swaybar/bar.c index 18b87e6d..6ffdc9b4 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -54,7 +54,6 @@ static void swaybar_output_free(struct swaybar_output *output) { if (output->input_region != NULL) { wl_region_destroy(output->input_region); } - zxdg_output_v1_destroy(output->xdg_output); wl_output_destroy(output->output); destroy_buffer(&output->buffers[0]); destroy_buffer(&output->buffers[1]); diff --git a/swaynag/swaynag.c b/swaynag/swaynag.c index 6d4a7a58..9b57d578 100644 --- a/swaynag/swaynag.c +++ b/swaynag/swaynag.c @@ -307,33 +307,25 @@ static void output_scale(void *data, struct wl_output *output, } } +static void output_name(void *data, struct wl_output *output, + const char *name) { + struct swaynag_output *swaynag_output = data; + swaynag_output->name = strdup(name); + + const char *outname = swaynag_output->swaynag->type->output; + if (!swaynag_output->swaynag->output && outname && + strcmp(outname, name) == 0) { + sway_log(SWAY_DEBUG, "Using output %s", name); + swaynag_output->swaynag->output = swaynag_output; + } +} + static const struct wl_output_listener output_listener = { .geometry = nop, .mode = nop, .done = nop, .scale = output_scale, -}; - -static void xdg_output_handle_name(void *data, - struct zxdg_output_v1 *xdg_output, const char *name) { - struct swaynag_output *swaynag_output = data; - char *outname = swaynag_output->swaynag->type->output; - sway_log(SWAY_DEBUG, "Checking against output %s for %s", name, outname); - if (!swaynag_output->swaynag->output && outname && name - && strcmp(outname, name) == 0) { - sway_log(SWAY_DEBUG, "Using output %s", name); - swaynag_output->swaynag->output = swaynag_output; - } - swaynag_output->name = strdup(name); - zxdg_output_v1_destroy(xdg_output); - swaynag_output->swaynag->querying_outputs--; -} - -static const struct zxdg_output_v1_listener xdg_output_listener = { - .logical_position = nop, - .logical_size = nop, - .done = nop, - .name = xdg_output_handle_name, + .name = output_name, .description = nop, }; @@ -361,33 +353,21 @@ static void handle_global(void *data, struct wl_registry *registry, } else if (strcmp(interface, wl_shm_interface.name) == 0) { swaynag->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); } else if (strcmp(interface, wl_output_interface.name) == 0) { - if (!swaynag->output && swaynag->xdg_output_manager) { - swaynag->querying_outputs++; + if (!swaynag->output) { struct swaynag_output *output = calloc(1, sizeof(struct swaynag_output)); output->wl_output = wl_registry_bind(registry, name, - &wl_output_interface, 3); + &wl_output_interface, 4); output->wl_name = name; output->scale = 1; output->swaynag = swaynag; wl_list_insert(&swaynag->outputs, &output->link); wl_output_add_listener(output->wl_output, &output_listener, output); - - struct zxdg_output_v1 *xdg_output; - xdg_output = zxdg_output_manager_v1_get_xdg_output( - swaynag->xdg_output_manager, output->wl_output); - zxdg_output_v1_add_listener(xdg_output, - &xdg_output_listener, output); } } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { swaynag->layer_shell = wl_registry_bind( registry, name, &zwlr_layer_shell_v1_interface, 1); - } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0 - && version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) { - swaynag->xdg_output_manager = wl_registry_bind(registry, name, - &zxdg_output_manager_v1_interface, - ZXDG_OUTPUT_V1_NAME_SINCE_VERSION); } } @@ -453,12 +433,11 @@ void swaynag_setup(struct swaynag *swaynag) { assert(swaynag->compositor && swaynag->layer_shell && swaynag->shm); - while (swaynag->querying_outputs > 0) { - if (wl_display_roundtrip(swaynag->display) < 0) { - sway_log(SWAY_ERROR, "Error during outputs init."); - swaynag_destroy(swaynag); - exit(EXIT_FAILURE); - } + // Second roundtrip to get wl_output properties + if (wl_display_roundtrip(swaynag->display) < 0) { + sway_log(SWAY_ERROR, "Error during outputs init."); + swaynag_destroy(swaynag); + exit(EXIT_FAILURE); } if (!swaynag->output && swaynag->type->output) { From 0b4e3d39eb7af94617a3f95995e2b0ba8bb5513f Mon Sep 17 00:00:00 2001 From: Cole Mickens Date: Mon, 13 Dec 2021 22:28:35 -0800 Subject: [PATCH 33/59] meson.build: require wayland-protocols 1.24 As far as I can tell `ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT` is introduced in wayland-protocols 1.24. --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index be1af04a..452502ff 100644 --- a/meson.build +++ b/meson.build @@ -41,7 +41,7 @@ wayland_server = dependency('wayland-server', version: '>=1.20.0') wayland_client = dependency('wayland-client') wayland_cursor = dependency('wayland-cursor') wayland_egl = dependency('wayland-egl') -wayland_protos = dependency('wayland-protocols', version: '>=1.14') +wayland_protos = dependency('wayland-protocols', version: '>=1.24') xkbcommon = dependency('xkbcommon') cairo = dependency('cairo') pango = dependency('pango') From f2b6d1ec290014674bf2755a3488aef8ab51a182 Mon Sep 17 00:00:00 2001 From: RoastVeg Date: Tue, 9 Jun 2020 16:47:38 +0100 Subject: [PATCH 34/59] Handle border width and height on minimum floating sizes This fixes: https://github.com/swaywm/sway/issues/5337 Co-authored-by: Moon Sungjoon --- sway/input/seatop_resize_floating.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c index 8400a4b3..df683026 100644 --- a/sway/input/seatop_resize_floating.c +++ b/sway/input/seatop_resize_floating.c @@ -80,17 +80,25 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { double height = e->ref_height + grow_height; int min_width, max_width, min_height, max_height; floating_calculate_constraints(&min_width, &max_width, - &min_height, &max_height); - width = fmax(min_width + border_width, fmin(width, max_width)); - height = fmax(min_height + border_height, fmin(height, max_height)); + &min_height, &max_height); + width = fmin(width, max_width - border_width); + width = fmax(width, min_width + border_width); + width = fmax(width, 1); + height = fmin(height, max_height - border_height); + height = fmax(height, min_height + border_height); + height = fmax(height, 1); // Apply the view's min/max size if (con->view) { double view_min_width, view_max_width, view_min_height, view_max_height; view_get_constraints(con->view, &view_min_width, &view_max_width, &view_min_height, &view_max_height); - width = fmax(view_min_width + border_width, fmin(width, view_max_width)); - height = fmax(view_min_height + border_height, fmin(height, view_max_height)); + width = fmin(width, view_max_width - border_width); + width = fmax(width, view_min_width + border_width); + width = fmax(width, 1); + height = fmin(height, view_max_height - border_height); + height = fmax(height, view_min_height + border_height); + height = fmax(height, 1); } From ebfe432ec3064094faebe0913b2d98932d590bfd Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Sun, 24 Oct 2021 18:49:39 -0700 Subject: [PATCH 35/59] output: change output::destroy to output::disable This changes output::destroy to output::disable and emits it only once when an output is disabled, instead of twice in succession. --- include/sway/output.h | 2 +- sway/desktop/layer_shell.c | 2 +- sway/desktop/output.c | 8 ++++++-- sway/tree/output.c | 8 ++------ 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/sway/output.h b/include/sway/output.h index 5dfe0fff..26b9709f 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -48,7 +48,7 @@ struct sway_output { struct wl_listener damage_frame; struct { - struct wl_signal destroy; + struct wl_signal disable; } events; struct timespec last_presentation; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index db78b59f..da59016d 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -664,7 +664,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { struct sway_output *output = layer_surface->output->data; sway_layer->output_destroy.notify = handle_output_destroy; - wl_signal_add(&output->events.destroy, &sway_layer->output_destroy); + wl_signal_add(&output->events.disable, &sway_layer->output_destroy); wl_list_insert(&output->layers[layer_surface->pending.layer], &sway_layer->link); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 3ae97e66..68f095c0 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -754,18 +754,22 @@ static void update_output_manager_config(struct sway_server *server) { static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, destroy); struct sway_server *server = output->server; - wl_signal_emit(&output->events.destroy, output); + output_begin_destroy(output); if (output->enabled) { output_disable(output); } - output_begin_destroy(output); + + wl_list_remove(&output->link); wl_list_remove(&output->destroy.link); wl_list_remove(&output->commit.link); wl_list_remove(&output->mode.link); wl_list_remove(&output->present.link); + output->wlr_output->data = NULL; + output->wlr_output = NULL; + transaction_commit_dirty(); update_output_manager_config(server); diff --git a/sway/tree/output.c b/sway/tree/output.c index 242e6fac..8eefcee3 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -95,7 +95,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) { output->detected_subpixel = wlr_output->subpixel; output->scale_filter = SCALE_FILTER_NEAREST; - wl_signal_init(&output->events.destroy); + wl_signal_init(&output->events.disable); wl_list_insert(&root->all_outputs, &output->link); @@ -262,7 +262,7 @@ void output_disable(struct sway_output *output) { } sway_log(SWAY_DEBUG, "Disabling output '%s'", output->wlr_output->name); - wl_signal_emit(&output->events.destroy, output); + wl_signal_emit(&output->events.disable, output); output_evacuate(output); @@ -289,10 +289,6 @@ void output_begin_destroy(struct sway_output *output) { output->node.destroying = true; node_set_dirty(&output->node); - - wl_list_remove(&output->link); - output->wlr_output->data = NULL; - output->wlr_output = NULL; } struct sway_output *output_from_wlr_output(struct wlr_output *output) { From 9ecbfe366596f627e843886d94e47097e19df5d5 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Sun, 24 Oct 2021 18:51:16 -0700 Subject: [PATCH 36/59] output: emit node::destroy event Now output_begin_destroy emits the node::destroy event similar to workspace_begin_destroy. It currently has no listeners, since they listen to output::disable or wlr_output::destroy instead. --- sway/tree/output.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/tree/output.c b/sway/tree/output.c index 8eefcee3..ad8d2482 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -286,6 +286,7 @@ void output_begin_destroy(struct sway_output *output) { return; } sway_log(SWAY_DEBUG, "Destroying output '%s'", output->wlr_output->name); + wl_signal_emit(&output->node.events.destroy, &output->node); output->node.destroying = true; node_set_dirty(&output->node); From 5d16d15a95bfaa1d55255b108e4c86337b8900b5 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Dec 2021 12:12:54 +0100 Subject: [PATCH 37/59] swaybar: fix errno handling in status_handle_readable If getline fails once, it was not reset before the next getline call. errno is only overwritten by getline on error. (cherry picked from commit 414950bbc8e833362a689cc11720855e8edd1323) --- swaybar/status_line.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swaybar/status_line.c b/swaybar/status_line.c index a97f3525..2e9bb7f1 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c @@ -117,11 +117,11 @@ bool status_handle_readable(struct status_line *status) { status->text = status->buffer; // intentional fall-through case PROTOCOL_TEXT: - errno = 0; while (true) { if (status->buffer[read_bytes - 1] == '\n') { status->buffer[read_bytes - 1] = '\0'; } + errno = 0; read_bytes = getline(&status->buffer, &status->buffer_size, status->read); if (errno == EAGAIN) { From d7867d41c25e0a027a9900f3dde565c6caaa4890 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 21 Dec 2021 12:05:05 +0100 Subject: [PATCH 38/59] Add cairo_image_surface_create error handling cairo_image_surface_create can fail, e.g. when running out of memory or when the size is too big. Avoid crashing in this case. Closes: https://github.com/swaywm/sway/issues/6531 (cherry picked from commit 59aebaa5f9f3afe9cdfbb0d37c4dc631690da3b9) --- sway/tree/container.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sway/tree/container.c b/sway/tree/container.c index 132b6819..e5149fb6 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -536,6 +536,13 @@ static void render_titlebar_text_texture(struct sway_output *output, cairo_surface_t *surface = cairo_image_surface_create( CAIRO_FORMAT_ARGB32, width, height); + cairo_status_t status = cairo_surface_status(surface); + if (status != CAIRO_STATUS_SUCCESS) { + sway_log(SWAY_ERROR, "cairo_image_surface_create failed: %s", + cairo_status_to_string(status)); + return; + } + cairo_t *cairo = cairo_create(surface); cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); cairo_set_font_options(cairo, fo); From 0e5dda3747f56de4937f98fa6c7bd4ec6048818f Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 23 Dec 2021 14:38:35 +0100 Subject: [PATCH 39/59] build: bump version to 1.7-rc1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 452502ff..092be14a 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'sway', 'c', - version: '1.6', + version: '1.7-rc1', license: 'MIT', meson_version: '>=0.60.0', default_options: [ From a235794a96884fa5619790316251f7d5e53e3d2d Mon Sep 17 00:00:00 2001 From: Thomas Hebb Date: Thu, 6 Jan 2022 03:44:55 -0800 Subject: [PATCH 40/59] input/seat: unset has_focus when focus_stack becomes empty We currently track the focus of a seat in two ways: we use a list called focus_stack to track the order in which nodes have been focused, with the first node representing what's currently focused, and we use a variable called has_focus to indicate whether anything has focus--i.e. whether we should actually treat that first node as focused at any given time. In a number of places, we treat has_focus as implying that a focused node exists. If it's true, we attempt to dereference the return value of seat_get_focus(), our helper function for getting the first node in focus_list, with no further checks. But this isn't quite correct with the current implementation of seat_get_focus(): not only does it return NULL when has_focus is false, it also returns NULL when focus_stack contains no items. In most cases, focus_stack never becomes empty and so this doesn't matter at all. Since focus_stack stores a history of focused nodes, we rarely remove nodes from it. The exception to this is when a node itself goes away. In that case, we call seat_node_destroy() to remove it from focus_stack and free it. But we don't unset has_focus if we've removed the final node! This lets us get into a state where has_focus is true but seat_get_focus() returns NULL, leading to a segfault when we try to dereference it. Fix the issue both by updating has_focus in seat_node_destroy() and by adding an assertion in seat_get_focus() that ensures focus_stack and has_focus are in sync, which will make it easier to track down similar issues in the future. Fixes #6395. [1] There's some discussion in #1585 from when this was implemented about whether has_focus is actually necessary; it's possible we could remove it entirely, but for the moment this is the architecture we have. (cherry picked from commit 921b0a863382b70234aeb4bd589c10328e9ff042) --- sway/input/seat.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/sway/input/seat.c b/sway/input/seat.c index c5c8459e..ce933b66 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -51,6 +51,16 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) { static void seat_node_destroy(struct sway_seat_node *seat_node) { wl_list_remove(&seat_node->destroy.link); wl_list_remove(&seat_node->link); + + /* + * This is the only time we remove items from the focus stack without + * immediately re-adding them. If we just removed the last thing, + * mark that nothing has focus anymore. + */ + if (wl_list_empty(&seat_node->seat->focus_stack)) { + seat_node->seat->has_focus = false; + } + free(seat_node); } @@ -1415,9 +1425,8 @@ struct sway_node *seat_get_focus(struct sway_seat *seat) { if (!seat->has_focus) { return NULL; } - if (wl_list_empty(&seat->focus_stack)) { - return NULL; - } + sway_assert(!wl_list_empty(&seat->focus_stack), + "focus_stack is empty, but has_focus is true"); struct sway_seat_node *current = wl_container_of(seat->focus_stack.next, current, link); return current->node; From ec9e4630e08f7da00f3785ae1b1e0e52c2c8f993 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Tue, 14 Sep 2021 13:19:02 -0500 Subject: [PATCH 41/59] swaybar: fix tray_padding vs min-height re: scale Co-authored-by: xdavidwu (cherry picked from commit bb60381c7599677eb07b309fdbe418008201de44) --- swaybar/tray/tray.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/swaybar/tray/tray.c b/swaybar/tray/tray.c index 5fe6f9c3..b0545f4a 100644 --- a/swaybar/tray/tray.c +++ b/swaybar/tray/tray.c @@ -116,8 +116,8 @@ uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) { } } // else display on all - if ((int) output->height*output->scale <= 2*config->tray_padding) { - return 2*config->tray_padding + 1; + if ((int)(output->height * output->scale) <= 2 * config->tray_padding) { + return (2 * config->tray_padding + 1) / output->scale; } uint32_t max_height = 0; From 44bb0aa3ee29eb7f2f15d56ee97d5f988f1a1017 Mon Sep 17 00:00:00 2001 From: Nathan Schulte Date: Fri, 8 Oct 2021 02:45:17 -0500 Subject: [PATCH 42/59] swaybar: fix tray item icon scaling, positioning (cherry picked from commit 107d15fafde279cef0855197e243b64fbffa5c3e) --- swaybar/tray/item.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 19f4beac..6d4b17bf 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -493,24 +493,36 @@ uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, cairo_destroy(cairo_icon); } - int padded_size = icon_size + 2*padding; - *x -= padded_size; - int y = floor((height - padded_size) / 2.0); + double descaled_padding = (double)padding / output->scale; + double descaled_icon_size = (double)icon_size / output->scale; + + int size = descaled_icon_size + 2 * descaled_padding; + *x -= size; + int icon_y = floor((output->height - size) / 2.0); cairo_operator_t op = cairo_get_operator(cairo); cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); - cairo_set_source_surface(cairo, icon, *x + padding, y + padding); - cairo_rectangle(cairo, *x, y, padded_size, padded_size); + + cairo_matrix_t scale_matrix; + cairo_pattern_t *icon_pattern = cairo_pattern_create_for_surface(icon); + // TODO: check cairo_pattern_status for "ENOMEM" + cairo_matrix_init_scale(&scale_matrix, output->scale, output->scale); + cairo_matrix_translate(&scale_matrix, -(*x + descaled_padding), -(icon_y + descaled_padding)); + cairo_pattern_set_matrix(icon_pattern, &scale_matrix); + cairo_set_source(cairo, icon_pattern); + cairo_rectangle(cairo, *x, icon_y, size, size); cairo_fill(cairo); + cairo_set_operator(cairo, op); + cairo_pattern_destroy(icon_pattern); cairo_surface_destroy(icon); struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); hotspot->x = *x; hotspot->y = 0; - hotspot->width = height; - hotspot->height = height; + hotspot->width = size; + hotspot->height = output->height; hotspot->callback = icon_hotspot_callback; hotspot->destroy = free; hotspot->data = strdup(sni->watcher_id); From 828a9a3cfbb14388c13007bbbbcdd7f1ed164eb1 Mon Sep 17 00:00:00 2001 From: David Rosca Date: Tue, 19 Oct 2021 07:54:36 +0200 Subject: [PATCH 43/59] container: Fix crash when view unmaps + maps quickly Followup on 4e4898e90f. If a view quickly maps and unmaps repeatedly, there will be multiple destroyed containers with same view in a single transaction. Each of these containers will then try to destroy this view, resulting in use after free. The container should only destroy the view if the view still belongs to the container. Simple reproducer: couple XMapWindow + XUnmapWindow in a loop followed by XDestroyWindow. See #6605 (cherry picked from commit f92329701b0983ec41fec29d3abc5c751cbe4a28) --- sway/tree/container.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index e5149fb6..79e04ec0 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -80,10 +80,8 @@ void container_destroy(struct sway_container *con) { wlr_texture_destroy(con->marks_urgent); wlr_texture_destroy(con->marks_focused_tab_title); - if (con->view) { - if (con->view->container == con) { - con->view->container = NULL; - } + if (con->view && con->view->container == con) { + con->view->container = NULL; if (con->view->destroying) { view_destroy(con->view); } From 3ab1c7f15376511d3f76ec8a3c42c3758b8bc2a8 Mon Sep 17 00:00:00 2001 From: David96 Date: Sat, 8 Jan 2022 19:33:19 +0100 Subject: [PATCH 44/59] commands/move: Fix crash when pos_y is omitted Fixes #6737 (cherry picked from commit 1bf1d84b7535c3c132240ed7b18414dc6cfe7e8a) --- sway/commands/move.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sway/commands/move.c b/sway/commands/move.c index f2702fa1..1a05a7a6 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -874,6 +874,10 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "Invalid x position specified"); } + if (argc < 1) { + return cmd_results_new(CMD_FAILURE, expected_position_syntax); + } + struct movement_amount ly = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID }; // Y direction num_consumed_args = parse_movement_amount(argc, argv, &ly); From 297a0c9d35703e59b23d8bae59f181c22f52bc68 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Thu, 23 Dec 2021 12:09:14 +0100 Subject: [PATCH 45/59] Destroy sub-surfaces with parent layer-shell surface Closes: https://github.com/swaywm/sway/issues/6337 (cherry picked from commit e2b4c573d6506250c77f01512bc07c72996cd363) --- include/sway/layers.h | 3 +++ sway/desktop/layer_shell.c | 25 ++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/include/sway/layers.h b/include/sway/layers.h index 224dc5e6..14816861 100644 --- a/include/sway/layers.h +++ b/include/sway/layers.h @@ -25,6 +25,8 @@ struct sway_layer_surface { bool mapped; struct wlr_box extent; enum zwlr_layer_shell_v1_layer layer; + + struct wl_list subsurfaces; }; struct sway_layer_popup { @@ -44,6 +46,7 @@ struct sway_layer_popup { struct sway_layer_subsurface { struct wlr_subsurface *wlr_subsurface; struct sway_layer_surface *layer_surface; + struct wl_list link; struct wl_listener map; struct wl_listener unmap; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index da59016d..27e457f1 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -352,6 +352,8 @@ static void unmap(struct sway_layer_surface *sway_layer) { sway_layer->layer_surface->surface, true); } +static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface); + static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_layer_surface *sway_layer = wl_container_of(listener, sway_layer, destroy); @@ -360,6 +362,12 @@ static void handle_destroy(struct wl_listener *listener, void *data) { if (sway_layer->layer_surface->mapped) { unmap(sway_layer); } + + struct sway_layer_subsurface *subsurface, *subsurface_tmp; + wl_list_for_each_safe(subsurface, subsurface_tmp, &sway_layer->subsurfaces, link) { + layer_subsurface_destroy(subsurface); + } + wl_list_remove(&sway_layer->link); wl_list_remove(&sway_layer->destroy.link); wl_list_remove(&sway_layer->map.link); @@ -428,11 +436,8 @@ static void subsurface_handle_commit(struct wl_listener *listener, void *data) { subsurface_damage(subsurface, false); } -static void subsurface_handle_destroy(struct wl_listener *listener, - void *data) { - struct sway_layer_subsurface *subsurface = - wl_container_of(listener, subsurface, destroy); - +static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface) { + wl_list_remove(&subsurface->link); wl_list_remove(&subsurface->map.link); wl_list_remove(&subsurface->unmap.link); wl_list_remove(&subsurface->destroy.link); @@ -440,6 +445,13 @@ static void subsurface_handle_destroy(struct wl_listener *listener, free(subsurface); } +static void subsurface_handle_destroy(struct wl_listener *listener, + void *data) { + struct sway_layer_subsurface *subsurface = + wl_container_of(listener, subsurface, destroy); + layer_subsurface_destroy(subsurface); +} + static struct sway_layer_subsurface *create_subsurface( struct wlr_subsurface *wlr_subsurface, struct sway_layer_surface *layer_surface) { @@ -451,6 +463,7 @@ static struct sway_layer_subsurface *create_subsurface( subsurface->wlr_subsurface = wlr_subsurface; subsurface->layer_surface = layer_surface; + wl_list_insert(&layer_surface->subsurfaces, &subsurface->link); subsurface->map.notify = subsurface_handle_map; wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); @@ -643,6 +656,8 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { return; } + wl_list_init(&sway_layer->subsurfaces); + sway_layer->surface_commit.notify = handle_surface_commit; wl_signal_add(&layer_surface->surface->events.commit, &sway_layer->surface_commit); From 68598619982fe9aa4edf81321c2ca59cd56c1983 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 9 Jan 2022 11:53:35 +0100 Subject: [PATCH 46/59] build: bump version to 1.7-rc2 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 092be14a..e02cd259 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'sway', 'c', - version: '1.7-rc1', + version: '1.7-rc2', license: 'MIT', meson_version: '>=0.60.0', default_options: [ From e0a591fb93a17e0a0f6ee8a8a285392d04a02c01 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 9 Jan 2022 01:03:49 +0100 Subject: [PATCH 47/59] Add safety assert in parse_movement_unit Let's add this just in case a caller passes argc == 0. References: https://github.com/swaywm/sway/issues/6737#issuecomment-1008082540 (cherry picked from commit 6cb69a40c757cc44906fd928c43e60612c0e7ce8) --- common/util.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/util.c b/common/util.c index 199f3ee1..5d4c0673 100644 --- a/common/util.c +++ b/common/util.c @@ -80,6 +80,12 @@ enum movement_unit parse_movement_unit(const char *unit) { int parse_movement_amount(int argc, char **argv, struct movement_amount *amount) { + if (!sway_assert(argc > 0, "Expected args in parse_movement_amount")) { + amount->amount = 0; + amount->unit = MOVEMENT_UNIT_INVALID; + return 0; + } + char *err; amount->amount = (int)strtol(argv[0], &err, 10); if (*err) { From 02a69dde9f1f3a7bd1435effabf5fef9f78d8649 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 11 Jan 2022 11:35:44 +0100 Subject: [PATCH 48/59] meson: check: false on run_command Future meson releases will change the default and warns when the implicit default is used, breaking builds. Explicitly set check: false to maintain behavior and silence warnings. (cherry picked from commit 470e04e8da6e078da77190998b5e0c34e244839a) --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index e02cd259..20452b3f 100644 --- a/meson.build +++ b/meson.build @@ -156,8 +156,8 @@ add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir version = '"@0@"'.format(meson.project_version()) git = find_program('git', native: true, required: false) if git.found() - git_commit = run_command([git, 'rev-parse', '--short', 'HEAD']) - git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD']) + git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'], check: false) + git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: false) if git_commit.returncode() == 0 and git_branch.returncode() == 0 version = '"@0@-@1@ (" __DATE__ ", branch \'@2@\')"'.format( meson.project_version(), From 67d3d952b6cd328ffd053ad4f52dc1687e28a56b Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 11 Jan 2022 11:08:44 +0100 Subject: [PATCH 49/59] Print deprecation notice when running SUID SUID privilege drop is needed for the "builtin"-backend of libseat, which copied our old "direct" backend behavior for the sake of compatibility and ease of transition. libseat now has a better alternative in the form of seatd-launch. It uses the normal seatd daemon and libseat backend and takes care of SUID for us. Add a soft deprecation warning to highlight our future intent of removing this code. The deprecation cycle is needed to avoid surprises when sway no longer drops privileges. (cherry picked from commit e1db1f8218998c428e8b087dda6660449ef2891a) --- sway/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sway/main.c b/sway/main.c index 6c71048b..b6f8a8bf 100644 --- a/sway/main.c +++ b/sway/main.c @@ -153,6 +153,9 @@ static void log_kernel(void) { static bool drop_permissions(void) { if (getuid() != geteuid() || getgid() != getegid()) { + sway_log(SWAY_ERROR, "!!! DEPRECATION WARNING: " + "SUID privilege drop will be removed in a future release, please migrate to seatd-launch"); + // Set the gid and uid in the correct order. if (setgid(getgid()) != 0) { sway_log(SWAY_ERROR, "Unable to drop root group, refusing to start"); From 1a5db66366f04fe545d697d20d7657a9be8c44d9 Mon Sep 17 00:00:00 2001 From: Aleksei Bavshin Date: Wed, 22 Dec 2021 22:25:27 -0800 Subject: [PATCH 50/59] xdg-shell: use toplevel geometry to adjust the popup box `popup_unconstrain` uses view coordinates to init the output box for popups. However wlroots expects the box to be set in a toplevel surface coordinate system, which is not always equal to view. The difference between those is a window geometry set via xdg-shell. GTK4 reserves some space for client-side decoration and thus has a window with top left corner not matching to (0, 0) of a surface. The box calculated without taking that into account was slightly shifted compared to the actual output and allowed to position part of the popup off screen. (cherry picked from commit aa443629b58e1d3d10cf64e689b661c076808d66) --- sway/desktop/xdg_shell.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index c1e5bc68..5fae8296 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -72,8 +72,8 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) { // the output box expressed in the coordinate system of the toplevel parent // of the popup struct wlr_box output_toplevel_sx_box = { - .x = output->lx - view->container->pending.content_x, - .y = output->ly - view->container->pending.content_y, + .x = output->lx - view->container->pending.content_x + view->geometry.x, + .y = output->ly - view->container->pending.content_y + view->geometry.y, .width = output->width, .height = output->height, }; From 6bb3e7ee0570b768032bcaa501cc812b77ce53e6 Mon Sep 17 00:00:00 2001 From: Kirill Chibisov Date: Mon, 10 Jan 2022 17:54:24 +0300 Subject: [PATCH 51/59] build: fix building with basu 02b412a introduced the use of list for sdbus deps, however it was assuming that all packages which were in a list has a version higher than 239. That is true for libsystemd and libelogind, since they use the same versions, however basu is using version numbers which are way lower than what libsystemd/libelogind are using, so basu only build is failing. (cherry picked from commit dbaf2e4fdb327f05f792b69430fe6f893fc9d879) --- meson.build | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/meson.build b/meson.build index 20452b3f..3c87a4b6 100644 --- a/meson.build +++ b/meson.build @@ -92,15 +92,22 @@ if get_option('sd-bus-provider') == 'auto' if not get_option('tray').disabled() assert(get_option('auto_features').auto(), 'sd-bus-provider must not be set to auto since auto_features != auto') endif - sdbus = dependency(['libsystemd', 'libelogind', 'basu'], - required: get_option('tray'), + sdbus = dependency(['libsystemd', 'libelogind'], + required: false, version: '>=239', ) + if not sdbus.found() + sdbus = dependency('basu', required: false) + endif else sdbus = dependency(get_option('sd-bus-provider'), required: get_option('tray')) endif -have_tray = sdbus.found() +tray_deps_found = sdbus.found() +if get_option('tray').enabled() and not tray_deps_found + error('Building with -Dtray=enabled, but sd-bus has not been not found') +endif +have_tray = (not get_option('tray').disabled()) and tray_deps_found conf_data = configuration_data() From c9ff52daa3cccf72f217a6ce0fbea71dc0070cb8 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 16 Jan 2022 19:39:24 +0100 Subject: [PATCH 52/59] ci: checkout wlroots 0.15.0 --- .builds/alpine.yml | 2 +- .builds/archlinux.yml | 2 +- .builds/freebsd.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.builds/alpine.yml b/.builds/alpine.yml index abf636ab..456837df 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml @@ -21,7 +21,7 @@ packages: - xwayland sources: - https://github.com/swaywm/sway - - https://gitlab.freedesktop.org/wlroots/wlroots.git + - https://gitlab.freedesktop.org/wlroots/wlroots.git#0.15.0 tasks: - wlroots: | cd wlroots diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index ac4cdb4d..c79e3fe2 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -18,7 +18,7 @@ packages: - seatd sources: - https://github.com/swaywm/sway - - https://gitlab.freedesktop.org/wlroots/wlroots.git + - https://gitlab.freedesktop.org/wlroots/wlroots.git#0.15.0 tasks: - wlroots: | cd wlroots diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 97e7eccc..5aa0e3dd 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -26,7 +26,7 @@ packages: - x11/xcb-util-wm sources: - https://github.com/swaywm/sway -- https://gitlab.freedesktop.org/wlroots/wlroots.git +- https://gitlab.freedesktop.org/wlroots/wlroots.git#0.15.0 tasks: - setup: | cd sway From ab11f404794583f9e2e349ed1f8d96dedce3bfdf Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sun, 16 Jan 2022 19:40:11 +0100 Subject: [PATCH 53/59] build: bump version to 1.7-rc3 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 3c87a4b6..49ae4b7a 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'sway', 'c', - version: '1.7-rc2', + version: '1.7-rc3', license: 'MIT', meson_version: '>=0.60.0', default_options: [ From 9a2155eed26d3d73059c39dd68a324f2f43332db Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Mon, 17 Jan 2022 16:53:46 -0500 Subject: [PATCH 54/59] input/cursor: count pointer gestures as idle activity Fixes https://github.com/swaywm/sway/issues/6765. (cherry picked from commit fd53f80156cee413a5166fb8e904a11901e45548) --- sway/input/cursor.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index d8b1abeb..322b91fb 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -927,6 +927,7 @@ static void handle_pointer_pinch_begin(struct wl_listener *listener, void *data) struct sway_cursor *cursor = wl_container_of( listener, cursor, pinch_begin); struct wlr_event_pointer_pinch_begin *event = data; + cursor_handle_activity_from_device(cursor, event->device); wlr_pointer_gestures_v1_send_pinch_begin( cursor->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->fingers); @@ -936,6 +937,7 @@ static void handle_pointer_pinch_update(struct wl_listener *listener, void *data struct sway_cursor *cursor = wl_container_of( listener, cursor, pinch_update); struct wlr_event_pointer_pinch_update *event = data; + cursor_handle_activity_from_device(cursor, event->device); wlr_pointer_gestures_v1_send_pinch_update( cursor->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->dx, event->dy, @@ -946,6 +948,7 @@ static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of( listener, cursor, pinch_end); struct wlr_event_pointer_pinch_end *event = data; + cursor_handle_activity_from_device(cursor, event->device); wlr_pointer_gestures_v1_send_pinch_end( cursor->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->cancelled); @@ -964,6 +967,7 @@ static void handle_pointer_swipe_update(struct wl_listener *listener, void *data struct sway_cursor *cursor = wl_container_of( listener, cursor, swipe_update); struct wlr_event_pointer_swipe_update *event = data; + cursor_handle_activity_from_device(cursor, event->device); wlr_pointer_gestures_v1_send_swipe_update( cursor->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->dx, event->dy); @@ -973,6 +977,7 @@ static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) { struct sway_cursor *cursor = wl_container_of( listener, cursor, swipe_end); struct wlr_event_pointer_swipe_end *event = data; + cursor_handle_activity_from_device(cursor, event->device); wlr_pointer_gestures_v1_send_swipe_end( cursor->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->cancelled); From 7a5e62036dededd0c161d4d9980f8d9e27627f7e Mon Sep 17 00:00:00 2001 From: Tudor Brindus Date: Mon, 17 Jan 2022 17:13:26 -0500 Subject: [PATCH 55/59] input/cursor: treat swipe begin as idle activity too Accidentally overlooked in fd53f80. (cherry picked from commit 7d1ccafae5a5d2eddfda2f857ea81ce88f141ddc) --- sway/input/cursor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 322b91fb..6fddee90 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -958,6 +958,7 @@ static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data) struct sway_cursor *cursor = wl_container_of( listener, cursor, swipe_begin); struct wlr_event_pointer_swipe_begin *event = data; + cursor_handle_activity_from_device(cursor, event->device); wlr_pointer_gestures_v1_send_swipe_begin( cursor->pointer_gestures, cursor->seat->wlr_seat, event->time_msec, event->fingers); From cd1a0aa29358cbc9f18517807cd9b329b67dd526 Mon Sep 17 00:00:00 2001 From: Patrick Hilhorst Date: Mon, 22 Nov 2021 19:44:22 +0100 Subject: [PATCH 56/59] treat fullscreen windows as 'tiled' for commands/focus (cherry picked from commit b2ee964434b25a0ccbccb1486b027f69ef34acff) --- sway/commands/focus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sway/commands/focus.c b/sway/commands/focus.c index ceb43d45..b8d28480 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -451,7 +451,8 @@ struct cmd_results *cmd_focus(int argc, char **argv) { return cmd_results_new(CMD_FAILURE, ""); } struct sway_node *next_focus = NULL; - if (container_is_floating(container)) { + if (container_is_floating(container) && + container->pending.fullscreen_mode == FULLSCREEN_NONE) { next_focus = node_get_in_direction_floating(container, seat, direction); } else { next_focus = node_get_in_direction_tiling(container, seat, direction, descend); From 0adcf77f3f19dccd7cc50f303c7708a22c5f33b4 Mon Sep 17 00:00:00 2001 From: Rouven Czerwinski Date: Tue, 18 Jan 2022 19:13:01 +0100 Subject: [PATCH 57/59] transaction: destroying nodes aren't hidden Commit 37d7bc69986f ("transaction: Only wait for ack from visible views") introduced a check which uses view_is_visible() to check if a view is still visible on the screen. However view_is_visible() will early return in case the node is in the destroying state. This is incorrect for transactions, since a destroying view which is visible will trigger configure events for other clients. This bug was visible when repeatedly opening and closing two views side by side, since we ignore the destroying node we get a frame where the still open view is shown with the old configure values and the rest is the desktop background. The next frame is than correct again. Fix this by considering destroying views as visible, we correctly wait for them and send the configure events to other views in time, fixing the background flicker. Fixes #6473 (cherry picked from commit e4909ab4a3514d9b3bfb01473cd3cd1704c8cd05) --- sway/desktop/transaction.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index b1f3fb32..f5a3a053 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -402,7 +402,7 @@ static void transaction_commit(struct sway_transaction *transaction) { struct sway_transaction_instruction *instruction = transaction->instructions->items[i]; struct sway_node *node = instruction->node; - bool hidden = node_is_view(node) && + bool hidden = node_is_view(node) && !node->destroying && !view_is_visible(node->sway_container->view); if (should_configure(node, instruction)) { instruction->serial = view_configure(node->sway_container->view, From 3a65ad427a2922ef747521ac173caab9eb6cdab1 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Sat, 22 Jan 2022 10:52:03 -0700 Subject: [PATCH 58/59] cmd/swap: error on swapping a container with itself (cherry picked from commit feea4b44108cf971ff8d1d474a75128dd737c1db) --- sway/commands/swap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sway/commands/swap.c b/sway/commands/swap.c index ce5e5128..9355944d 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c @@ -126,10 +126,10 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) { } enum sway_fullscreen_mode fs1 = con1->pending.fullscreen_mode; - enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode; if (fs1) { container_fullscreen_disable(con1); } + enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode; if (fs2) { container_fullscreen_disable(con2); } @@ -247,6 +247,9 @@ struct cmd_results *cmd_swap(int argc, char **argv) { } else if (!current) { error = cmd_results_new(CMD_FAILURE, "Can only swap with containers and views"); + } else if (current == other) { + error = cmd_results_new(CMD_FAILURE, + "Cannot swap a container with itself"); } else if (container_has_ancestor(current, other) || container_has_ancestor(other, current)) { error = cmd_results_new(CMD_FAILURE, From 5543acff06981639086bc9a0fc9b608796a23e84 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 22 Jan 2022 23:55:11 +0100 Subject: [PATCH 59/59] build: bump version to 1.7 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 49ae4b7a..5e4de87f 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'sway', 'c', - version: '1.7-rc3', + version: '1.7', license: 'MIT', meson_version: '>=0.60.0', default_options: [