diff --git a/config.in b/config.in index a2a01dda9..872ef0574 100644 --- a/config.in +++ b/config.in @@ -46,14 +46,18 @@ output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill # # Example configuration: # -# input "2:14:SynPS/2_Synaptics_TouchPad" { +# input type:touchpad { # dwt enabled # tap enabled # natural_scroll enabled # middle_emulation enabled # } # -# You can get the names of your inputs by running: swaymsg -t get_inputs +# input type:keyboard { +# xkb_layout "eu" +# } +# +# You can also configure each device individually. # Read `man 5 sway-input` for more information about this section. ### Key bindings diff --git a/include/sway/desktop/idle_inhibit_v1.h b/include/sway/desktop/idle_inhibit_v1.h index 84cc666d0..447ac8708 100644 --- a/include/sway/desktop/idle_inhibit_v1.h +++ b/include/sway/desktop/idle_inhibit_v1.h @@ -13,6 +13,7 @@ enum sway_idle_inhibit_mode { struct sway_idle_inhibit_manager_v1 { struct wlr_idle_inhibit_manager_v1 *wlr_manager; struct wl_listener new_idle_inhibitor_v1; + struct wl_listener manager_destroy; struct wl_list inhibitors; }; diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index b014e18f8..5113844d8 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -39,6 +39,8 @@ struct sway_input_manager { struct sway_input_manager *input_manager_create(struct sway_server *server); +void input_manager_finish(struct sway_input_manager *input); + bool input_manager_has_focus(struct sway_node *node); void input_manager_set_focus(struct sway_node *node); diff --git a/include/sway/input/text_input.h b/include/sway/input/text_input.h index 1993f928f..1818749ad 100644 --- a/include/sway/input/text_input.h +++ b/include/sway/input/text_input.h @@ -25,8 +25,10 @@ struct sway_input_method_relay { struct wlr_input_method_v2 *input_method; // doesn't have to be present struct wl_listener text_input_new; + struct wl_listener text_input_manager_destroy; struct wl_listener input_method_new; + struct wl_listener input_method_manager_destroy; struct wl_listener input_method_commit; struct wl_listener input_method_new_popup_surface; struct wl_listener input_method_grab_keyboard; diff --git a/include/sway/server.h b/include/sway/server.h index feb516c5b..e7d7094f1 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -46,6 +46,7 @@ struct sway_server { struct wl_listener new_output; struct wl_listener renderer_lost; + struct wl_event_source *recreating_renderer; struct wlr_idle_notifier_v1 *idle_notifier_v1; struct sway_idle_inhibit_manager_v1 idle_inhibit_manager_v1; @@ -150,21 +151,19 @@ struct sway_debug { bool noatomic; // Ignore atomic layout updates bool txn_timings; // Log verbose messages about transactions bool txn_wait; // Always wait for the timeout before applying - bool legacy_wl_drm; // Enable the legacy wl_drm interface }; extern struct sway_debug debug; extern bool allow_unsupported_gpu; +void sway_terminate(int exit_code); + bool server_init(struct sway_server *server); 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 restore_signals(void); - void handle_new_output(struct wl_listener *listener, void *data); void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data); diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 4608b8ac2..4fb2d7208 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h @@ -95,6 +95,7 @@ struct sway_container { struct wl_listener output_enter; struct wl_listener output_leave; + struct wl_listener output_handler_destroy; struct sway_container_state current; struct sway_container_state pending; diff --git a/include/sway/tree/workspace.h b/include/sway/tree/workspace.h index 58bde20cb..27ed649fd 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h @@ -96,7 +96,7 @@ void workspace_output_add_priority(struct sway_workspace *workspace, struct sway_output *output); struct sway_output *workspace_output_get_highest_available( - struct sway_workspace *ws, struct sway_output *exclude); + struct sway_workspace *ws); void workspace_detect_urgent(struct sway_workspace *workspace); diff --git a/include/swaybar/config.h b/include/swaybar/config.h index 361acd991..ad58b3c3c 100644 --- a/include/swaybar/config.h +++ b/include/swaybar/config.h @@ -14,6 +14,11 @@ struct box_colors { uint32_t text; }; +struct box_size { + uint32_t width; + uint32_t height; +}; + struct config_output { struct wl_list link; // swaybar_config::outputs char *name; diff --git a/meson.build b/meson.build index 9ce5723e7..07a6bccff 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project( 'sway', 'c', - version: '1.10-dev', + version: '1.11-rc2', license: 'MIT', meson_version: '>=1.3', default_options: [ @@ -38,14 +38,14 @@ if is_freebsd endif # Execute the wlroots subproject, if any -wlroots_version = ['>=0.19.0', '<0.20.0'] +wlroots_version = ['>=0.20.0', '<0.21.0'] subproject( 'wlroots', default_options: ['examples=false'], required: false, version: wlroots_version, ) -wlroots = dependency('wlroots-0.19', version: wlroots_version, fallback: 'wlroots') +wlroots = dependency('wlroots-0.20', version: wlroots_version, fallback: 'wlroots') wlroots_features = { 'xwayland': false, 'libinput_backend': false, @@ -79,7 +79,7 @@ libudev = wlroots_features['libinput_backend'] ? dependency('libudev') : null_de math = cc.find_library('m') rt = cc.find_library('rt') xcb_icccm = wlroots_features['xwayland'] ? dependency('xcb-icccm') : null_dep -threads = dependency('threads') # for pthread_setschedparam +threads = dependency('threads') # for pthread_setschedparam and pthread_atfork if get_option('sd-bus-provider') == 'auto' if not get_option('tray').disabled() diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 32d4f8916..15373d5a8 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -367,7 +367,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, } } else if (strcmp("--exclude-titlebar", argv[0]) == 0) { exclude_titlebar = true; - } else if (has_prefix("--input-device=", argv[0])) { + } else if (has_prefix(argv[0], "--input-device=")) { free(binding->input); binding->input = strdup(argv[0] + strlen("--input-device=")); strip_quotes(binding->input); diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index 8f02bbdc7..a966696c5 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -51,8 +51,6 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) { // Fork process pid_t child = fork(); if (child == 0) { - restore_nofile_limit(); - restore_signals(); setsid(); if (ctx) { diff --git a/sway/commands/exit.c b/sway/commands/exit.c index 10cde640c..0f326cea6 100644 --- a/sway/commands/exit.c +++ b/sway/commands/exit.c @@ -1,8 +1,7 @@ #include #include "sway/commands.h" #include "sway/config.h" - -void sway_terminate(int exit_code); +#include "sway/server.h" struct cmd_results *cmd_exit(int argc, char **argv) { struct cmd_results *error = NULL; diff --git a/sway/commands/gesture.c b/sway/commands/gesture.c index e63b7ac6e..8dff29a34 100644 --- a/sway/commands/gesture.c +++ b/sway/commands/gesture.c @@ -121,7 +121,7 @@ static struct cmd_results *cmd_bind_or_unbind_gesture(int argc, char **argv, boo binding->flags |= BINDING_EXACT; } else if (strcmp("--no-warn", argv[0]) == 0) { warn = false; - } else if (has_prefix("--input-device=", argv[0])) { + } else if (has_prefix(argv[0], "--input-device=")) { free(binding->input); binding->input = strdup(argv[0] + strlen("--input-device=")); } else { diff --git a/sway/commands/move.c b/sway/commands/move.c index 15d442109..291e55407 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -222,6 +222,7 @@ static void container_move_to_workspace(struct sway_container *container, container_detach(container); if (workspace_is_empty(workspace) && container->pending.children) { workspace_unwrap_children(workspace, container); + container_reap_empty(container); } else { container->pending.width = container->pending.height = 0; container->width_fraction = container->height_fraction = 0; diff --git a/sway/commands/resize.c b/sway/commands/resize.c index 32b746eaf..49731a641 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c @@ -457,7 +457,7 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) { if (argc > num_consumed_args) { return cmd_results_new(CMD_INVALID, "%s", usage); } - if (width.unit == MOVEMENT_UNIT_INVALID) { + if (height.unit == MOVEMENT_UNIT_INVALID) { return cmd_results_new(CMD_INVALID, "%s", usage); } } diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c index c995f2f08..8a63740c3 100644 --- a/sway/commands/scratchpad.c +++ b/sway/commands/scratchpad.c @@ -118,10 +118,10 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) { // If using criteria, this command is executed for every container which // matches the criteria. If this container isn't in the scratchpad, - // we'll just silently return a success. The same is true if the + // we'll return an error. The same is true if the // overridden node is not a container. if (!con || !con->scratchpad) { - return cmd_results_new(CMD_SUCCESS, NULL); + return cmd_results_new(CMD_INVALID, "Container is not in scratchpad."); } scratchpad_toggle_container(con); } else { diff --git a/sway/config.c b/sway/config.c index ec7059687..d579022d3 100644 --- a/sway/config.c +++ b/sway/config.c @@ -552,28 +552,12 @@ bool load_main_config(const char *file, bool is_active, bool validating) { return success; } -static bool load_include_config(const char *path, const char *parent_dir, - struct sway_config *config, struct swaynag_instance *swaynag) { +static bool load_include_config(const char *path, struct sway_config *config, + struct swaynag_instance *swaynag) { // save parent config const char *parent_config = config->current_config_path; - char *full_path; - int len = strlen(path); - if (len >= 1 && path[0] != '/') { - len = len + strlen(parent_dir) + 2; - full_path = malloc(len * sizeof(char)); - if (!full_path) { - sway_log(SWAY_ERROR, - "Unable to allocate full path to included config"); - return false; - } - snprintf(full_path, len, "%s/%s", parent_dir, path); - } else { - full_path = strdup(path); - } - - char *real_path = realpath(full_path, NULL); - free(full_path); + char *real_path = realpath(path, NULL); if (real_path == NULL) { sway_log(SWAY_DEBUG, "%s not found.", path); @@ -625,7 +609,7 @@ void load_include_configs(const char *path, struct sway_config *config, char **w = p.we_wordv; size_t i; for (i = 0; i < p.we_wordc; ++i) { - load_include_config(w[i], parent_dir, config, swaynag); + load_include_config(w[i], config, swaynag); } wordfree(&p); } diff --git a/sway/config/bar.c b/sway/config/bar.c index 6cace0da2..f4efb276c 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -213,8 +213,6 @@ static void invoke_swaybar(struct bar_config *bar) { sway_log(SWAY_ERROR, "Failed to create fork for swaybar"); return; } else if (pid == 0) { - restore_nofile_limit(); - restore_signals(); if (!sway_set_cloexec(sockets[1], false)) { _exit(EXIT_FAILURE); } diff --git a/sway/config/output.c b/sway/config/output.c index b8a613cc5..df80cab64 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -67,7 +67,7 @@ struct output_config *new_output_config(const char *name) { oc->refresh_rate = -1; oc->custom_mode = -1; oc->drm_mode.type = -1; - oc->x = oc->y = -1; + oc->x = oc->y = INT_MAX; oc->scale = -1; oc->scale_filter = SCALE_FILTER_DEFAULT; oc->transform = -1; @@ -93,11 +93,11 @@ static void supersede_output_config(struct output_config *dst, struct output_con if (src->height != -1) { dst->height = -1; } - if (src->x != -1) { - dst->x = -1; + if (src->x != INT_MAX) { + dst->x = INT_MAX; } - if (src->y != -1) { - dst->y = -1; + if (src->y != INT_MAX) { + dst->y = INT_MAX; } if (src->scale != -1) { dst->scale = -1; @@ -129,6 +129,13 @@ static void supersede_output_config(struct output_config *dst, struct output_con if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { dst->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT; } + if (src->set_color_transform) { + if (dst->color_transform) { + wlr_color_transform_unref(dst->color_transform); + dst->color_transform = NULL; + } + dst->set_color_transform = false; + } if (src->background) { free(dst->background); dst->background = NULL; @@ -144,6 +151,9 @@ static void supersede_output_config(struct output_config *dst, struct output_con if (src->power != -1) { dst->power = -1; } + if (src->allow_tearing != -1) { + dst->allow_tearing = -1; + } } // merge_output_config sets all fields in dst that were set in src @@ -157,10 +167,10 @@ static void merge_output_config(struct output_config *dst, struct output_config if (src->height != -1) { dst->height = src->height; } - if (src->x != -1) { + if (src->x != INT_MAX) { dst->x = src->x; } - if (src->y != -1) { + if (src->y != INT_MAX) { dst->y = src->y; } if (src->scale != -1) { @@ -527,7 +537,7 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output } // Find position for it - if (oc && (oc->x != -1 || oc->y != -1)) { + if (oc && oc->x != INT_MAX && oc->y != INT_MAX) { sway_log(SWAY_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y); wlr_output_layout_add(root->output_layout, wlr_output, oc->x, oc->y); } else { @@ -1060,8 +1070,6 @@ static bool _spawn_swaybg(char **command) { sway_log_errno(SWAY_ERROR, "fork failed"); return false; } else if (pid == 0) { - restore_nofile_limit(); - restore_signals(); if (!sway_set_cloexec(sockets[1], false)) { _exit(EXIT_FAILURE); } diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index f3af7aa1b..6b2761fcd 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -1,5 +1,6 @@ #include #include +#include #include "log.h" #include "sway/desktop/idle_inhibit_v1.h" #include "sway/input/seat.h" @@ -44,6 +45,14 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { sway_idle_inhibit_v1_check_active(); } +void handle_manager_destroy(struct wl_listener *listener, void *data) { + struct sway_idle_inhibit_manager_v1 *manager = + wl_container_of(listener, manager, manager_destroy); + + wl_list_remove(&manager->manager_destroy.link); + wl_list_remove(&manager->new_idle_inhibitor_v1.link); +} + void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view, enum sway_idle_inhibit_mode mode) { struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1; @@ -103,11 +112,34 @@ void sway_idle_inhibit_v1_user_inhibitor_destroy( } bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { + if (server.session_lock.lock) { + // A session lock is active. In this case, only application inhibitors + // on the session lock surface can have any effect. + if (inhibitor->mode != INHIBIT_IDLE_APPLICATION) { + return false; + } + struct wlr_surface *wlr_surface = inhibitor->wlr_inhibitor->surface; + if (!wlr_session_lock_surface_v1_try_from_wlr_surface(wlr_surface)) { + return false; + } + return wlr_surface->mapped; + } + switch (inhibitor->mode) { case INHIBIT_IDLE_APPLICATION:; - // If there is no view associated with the inhibitor, assume visible - struct sway_view *view = view_from_wlr_surface(inhibitor->wlr_inhibitor->surface); - return !view || !view->container || view_is_visible(view); + struct wlr_surface *wlr_surface = inhibitor->wlr_inhibitor->surface; + struct wlr_layer_surface_v1 *layer_surface = + wlr_layer_surface_v1_try_from_wlr_surface(wlr_surface); + if (layer_surface) { + // Layer surfaces can be occluded but are always on screen after + // they have been mapped. + return layer_surface->output && layer_surface->output->enabled && + wlr_surface->mapped; + } + + // If there is no view associated with the inhibitor, assume invisible + struct sway_view *view = view_from_wlr_surface(wlr_surface); + return view && view->container && view_is_visible(view); case INHIBIT_IDLE_FOCUS:; struct sway_seat *seat = NULL; wl_list_for_each(seat, &server.input->seats, link) { @@ -153,6 +185,9 @@ bool sway_idle_inhibit_manager_v1_init(void) { wl_signal_add(&manager->wlr_manager->events.new_inhibitor, &manager->new_idle_inhibitor_v1); manager->new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1; + wl_signal_add(&manager->wlr_manager->events.destroy, + &manager->manager_destroy); + manager->manager_destroy.notify = handle_manager_destroy; wl_list_init(&manager->inhibitors); return true; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 05faa4656..08b5b1de2 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -221,7 +221,7 @@ static void handle_output_destroy(struct wl_listener *listener, void *data) { wl_container_of(listener, layer, output_destroy); layer->output = NULL; - wlr_scene_node_destroy(&layer->scene->tree->node); + wlr_layer_surface_v1_destroy(layer->layer_surface); } static void handle_node_destroy(struct wl_listener *listener, void *data) { @@ -269,12 +269,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) { wl_container_of(listener, surface, surface_commit); struct wlr_layer_surface_v1 *layer_surface = surface->layer_surface; - if (!layer_surface->initialized) { - return; - } - uint32_t committed = layer_surface->current.committed; - if (committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) { + if (layer_surface->initialized && committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) { enum zwlr_layer_shell_v1_layer layer_type = layer_surface->current.layer; struct wlr_scene_tree *output_layer = sway_layer_get_scene( surface->output, layer_type); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index e24193175..e6fe2ee4d 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -264,7 +264,7 @@ static int output_repaint_timer_handler(void *data) { struct sway_output *output = data; output->wlr_output->frame_pending = false; - if (!output->enabled) { + if (!output->wlr_output->enabled) { return 0; } @@ -422,13 +422,6 @@ void force_modeset(void) { } static void begin_destroy(struct sway_output *output) { - if (output->enabled) { - output_disable(output); - } - - output_begin_destroy(output); - - wl_list_remove(&output->link); wl_list_remove(&output->layout_destroy.link); wl_list_remove(&output->destroy.link); @@ -436,8 +429,17 @@ static void begin_destroy(struct sway_output *output) { wl_list_remove(&output->frame.link); wl_list_remove(&output->request_state.link); + // Remove the scene_output first to ensure that the scene does not emit + // events for this output. wlr_scene_output_destroy(output->scene_output); output->scene_output = NULL; + + if (output->enabled) { + output_disable(output); + } + output_begin_destroy(output); + wl_list_remove(&output->link); + output->wlr_output->data = NULL; output->wlr_output = NULL; diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 52c03b18a..325a30226 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -309,12 +309,13 @@ static void arrange_children(enum sway_container_layout layout, list_t *children arrange_title_bar(child, title_offset, -title_bar_height, next_title_offset - title_offset, title_bar_height); wlr_scene_node_set_enabled(&child->border.tree->node, activated); + wlr_scene_node_set_enabled(&child->scene_tree->node, true); wlr_scene_node_set_position(&child->scene_tree->node, 0, title_bar_height); wlr_scene_node_reparent(&child->scene_tree->node, content); - if (activated) { - arrange_container(child, width, height - title_bar_height, - title_bar_height == 0, 0); + int net_height = height - title_bar_height; + if (activated && width > 0 && net_height > 0) { + arrange_container(child, width, net_height, title_bar_height == 0, 0); } else { disable_container(child); } @@ -338,12 +339,13 @@ static void arrange_children(enum sway_container_layout layout, list_t *children arrange_title_bar(child, 0, y - title_height, width, title_bar_height); wlr_scene_node_set_enabled(&child->border.tree->node, activated); + wlr_scene_node_set_enabled(&child->scene_tree->node, true); wlr_scene_node_set_position(&child->scene_tree->node, 0, title_height); wlr_scene_node_reparent(&child->scene_tree->node, content); - if (activated) { - arrange_container(child, width, height - title_height, - title_bar_height == 0, 0); + int net_height = height - title_height; + if (activated && width > 0 && net_height > 0) { + arrange_container(child, width, net_height, title_bar_height == 0, 0); } else { disable_container(child); } @@ -359,8 +361,12 @@ static void arrange_children(enum sway_container_layout layout, list_t *children wlr_scene_node_set_enabled(&child->border.tree->node, true); wlr_scene_node_set_position(&child->scene_tree->node, 0, off); wlr_scene_node_reparent(&child->scene_tree->node, content); - arrange_container(child, width, cheight, true, gaps); - off += cheight + gaps; + if (width > 0 && cheight > 0) { + arrange_container(child, width, cheight, true, gaps); + off += cheight + gaps; + } else { + disable_container(child); + } } } else if (layout == L_HORIZ) { int off = 0; @@ -371,8 +377,12 @@ static void arrange_children(enum sway_container_layout layout, list_t *children wlr_scene_node_set_enabled(&child->border.tree->node, true); wlr_scene_node_set_position(&child->scene_tree->node, off, 0); wlr_scene_node_reparent(&child->scene_tree->node, content); - arrange_container(child, cwidth, height, true, gaps); - off += cwidth + gaps; + if (cwidth > 0 && height > 0) { + arrange_container(child, cwidth, height, true, gaps); + off += cwidth + gaps; + } else { + disable_container(child); + } } } else { sway_assert(false, "unreachable"); @@ -524,6 +534,7 @@ static void arrange_workspace_floating(struct sway_workspace *ws) { wlr_scene_node_set_position(&floater->scene_tree->node, floater->current.x, floater->current.y); wlr_scene_node_set_enabled(&floater->scene_tree->node, true); + wlr_scene_node_set_enabled(&floater->border.tree->node, true); arrange_container(floater, floater->current.width, floater->current.height, true, ws->gaps_inner); @@ -576,15 +587,16 @@ static void arrange_output(struct sway_output *output, int width, int height) { wlr_scene_node_set_enabled(&child->layers.tiling->node, !fs); wlr_scene_node_set_enabled(&child->layers.fullscreen->node, fs); - arrange_workspace_floating(child); - wlr_scene_node_set_enabled(&output->layers.shell_background->node, !fs); wlr_scene_node_set_enabled(&output->layers.shell_bottom->node, !fs); wlr_scene_node_set_enabled(&output->layers.fullscreen->node, fs); if (fs) { + disable_workspace(child); + wlr_scene_rect_set_size(output->fullscreen_background, width, height); + arrange_workspace_floating(child); arrange_fullscreen(child->layers.fullscreen, fs, child, width, height); } else { @@ -597,6 +609,7 @@ static void arrange_output(struct sway_output *output, int width, int height) { arrange_workspace_tiling(child, area->width - gaps->left - gaps->right, area->height - gaps->top - gaps->bottom); + arrange_workspace_floating(child); } } else { wlr_scene_node_set_enabled(&child->layers.tiling->node, false); @@ -654,6 +667,13 @@ static void arrange_root(struct sway_root *root) { wlr_scene_output_set_position(output->scene_output, output->lx, output->ly); + // disable all workspaces to get to a known state + for (int j = 0; j < output->current.workspaces->length; j++) { + struct sway_workspace *workspace = output->current.workspaces->items[j]; + disable_workspace(workspace); + } + + // arrange the active workspace if (ws) { arrange_workspace_floating(ws); } diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 99af4c691..ffcf8fc52 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -493,6 +493,14 @@ struct sway_input_manager *input_manager_create(struct sway_server *server) { return input; } +void input_manager_finish(struct sway_input_manager *input) { + wl_list_remove(&input->new_input.link); + wl_list_remove(&input->virtual_keyboard_new.link); + wl_list_remove(&input->virtual_pointer_new.link); + wl_list_remove(&input->keyboard_shortcuts_inhibit_new_inhibitor.link); + wl_list_remove(&input->transient_seat_create.link); +} + bool input_manager_has_focus(struct sway_node *node) { struct sway_seat *seat = NULL; wl_list_for_each(seat, &server.input->seats, link) { diff --git a/sway/input/libinput.c b/sway/input/libinput.c index f76c6505c..b98c4cc86 100644 --- a/sway/input/libinput.c +++ b/sway/input/libinput.c @@ -399,6 +399,19 @@ void sway_input_reset_libinput_device(struct sway_input_device *input_device) { } } +static bool sway_udev_device_is_builtin(struct udev_device *udev_device) { + const char *id_path = udev_device_get_property_value(udev_device, "ID_PATH"); + if (!id_path) { + return false; + } + + if (has_prefix(id_path, "platform-")) { + return true; + } + + return has_prefix(id_path, "pci-") && strstr(id_path, "-platform-"); +} + bool sway_libinput_device_is_builtin(struct sway_input_device *sway_device) { if (!wlr_input_device_is_libinput(sway_device->wlr_device)) { return false; @@ -412,14 +425,7 @@ bool sway_libinput_device_is_builtin(struct sway_input_device *sway_device) { return false; } - const char *id_path = udev_device_get_property_value(udev_device, "ID_PATH"); - if (!id_path) { - return false; - } - - if (has_prefix(id_path, "platform-")) { - return true; - } - - return has_prefix(id_path, "pci-") && strstr(id_path, "-platform-"); + bool is_builtin = sway_udev_device_is_builtin(udev_device); + udev_device_unref(udev_device); + return is_builtin; } diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c index 340e334bf..f64e5a4f2 100644 --- a/sway/input/seatop_down.c +++ b/sway/input/seatop_down.c @@ -100,6 +100,7 @@ static void handle_touch_down(struct sway_seat *seat, if (focused_node) { seat_set_focus(seat, focused_node); + transaction_commit_dirty(); } } diff --git a/sway/input/text_input.c b/sway/input/text_input.c index e16724671..0eb76eb16 100644 --- a/sway/input/text_input.c +++ b/sway/input/text_input.c @@ -10,6 +10,7 @@ #include "sway/input/text_input_popup.h" #include "sway/layers.h" #include "sway/server.h" +#include static struct sway_text_input *relay_get_focusable_text_input( struct sway_input_method_relay *relay) { @@ -385,6 +386,8 @@ static void input_popup_set_focus(struct sway_input_popup *popup, struct wlr_layer_surface_v1 *layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(surface); + struct wlr_session_lock_surface_v1 *lock_surface = + wlr_session_lock_surface_v1_try_from_wlr_surface(surface); struct wlr_scene_tree *relative_parent; if (layer_surface) { @@ -404,8 +407,30 @@ static void input_popup_set_focus(struct sway_input_popup *popup, // surface. Layer surfaces get destroyed as part of the output being // destroyed, thus also trickling down to popups. popup->fixed_output = layer->layer_surface->output; + } else if (lock_surface) { + wl_signal_add(&lock_surface->surface->events.unmap, + &popup->focused_surface_unmap); + + struct sway_layer_surface *lock = lock_surface->data; + if (lock == NULL) { + return; + } + + relative_parent = lock->scene->tree; + popup->desc.view = NULL; + + // we don't need to add an event here to NULL out this field because + // this field will only be initialized if the popup is part of a layer + // surface. Layer surfaces get destroyed as part of the output being + // destroyed, thus also trickling down to popups. + popup->fixed_output = lock->layer_surface->output; } else { struct sway_view *view = view_from_wlr_surface(surface); + // In the future there may be other shells been added, so we also need to check here. + if (view == NULL) { + sway_log(SWAY_DEBUG, "Unsupported IME focus surface"); + return; + } wl_signal_add(&view->events.unmap, &popup->focused_surface_unmap); relative_parent = view->scene_tree; popup->desc.view = view; @@ -572,6 +597,34 @@ static void relay_handle_input_method(struct wl_listener *listener, } } +static void sway_input_method_relay_finish_text_input(struct sway_input_method_relay *relay) { + wl_list_remove(&relay->text_input_new.link); + wl_list_remove(&relay->text_input_manager_destroy.link); + wl_list_init(&relay->text_input_new.link); + wl_list_init(&relay->text_input_manager_destroy.link); +} + +static void relay_handle_text_input_manager_destroy(struct wl_listener *listener, void *data) { + struct sway_input_method_relay *relay = wl_container_of(listener, relay, + text_input_manager_destroy); + + sway_input_method_relay_finish_text_input(relay); +} + +static void sway_input_method_relay_finish_input_method(struct sway_input_method_relay *relay) { + wl_list_remove(&relay->input_method_new.link); + wl_list_remove(&relay->input_method_manager_destroy.link); + wl_list_init(&relay->input_method_new.link); + wl_list_init(&relay->input_method_manager_destroy.link); +} + +static void relay_handle_input_method_manager_destroy(struct wl_listener *listener, void *data) { + struct sway_input_method_relay *relay = wl_container_of(listener, relay, + input_method_manager_destroy); + + sway_input_method_relay_finish_input_method(relay); +} + void sway_input_method_relay_init(struct sway_seat *seat, struct sway_input_method_relay *relay) { relay->seat = seat; @@ -579,18 +632,24 @@ void sway_input_method_relay_init(struct sway_seat *seat, wl_list_init(&relay->input_popups); relay->text_input_new.notify = relay_handle_text_input; - wl_signal_add(&server.text_input->events.text_input, + wl_signal_add(&server.text_input->events.new_text_input, &relay->text_input_new); + relay->text_input_manager_destroy.notify = relay_handle_text_input_manager_destroy; + wl_signal_add(&server.text_input->events.destroy, + &relay->text_input_manager_destroy); relay->input_method_new.notify = relay_handle_input_method; wl_signal_add( &server.input_method->events.input_method, &relay->input_method_new); + relay->input_method_manager_destroy.notify = relay_handle_input_method_manager_destroy; + wl_signal_add(&server.input_method->events.destroy, + &relay->input_method_manager_destroy); } void sway_input_method_relay_finish(struct sway_input_method_relay *relay) { - wl_list_remove(&relay->input_method_new.link); - wl_list_remove(&relay->text_input_new.link); + sway_input_method_relay_finish_text_input(relay); + sway_input_method_relay_finish_input_method(relay); } void sway_input_method_relay_set_focus(struct sway_input_method_relay *relay, diff --git a/sway/lock.c b/sway/lock.c index 43f313308..c8975c747 100644 --- a/sway/lock.c +++ b/sway/lock.c @@ -234,6 +234,9 @@ static void handle_unlock(struct wl_listener *listener, void *data) { struct sway_output *output = root->outputs->items[i]; arrange_layers(output); } + + // Views are now visible, so check if we need to activate inhibition again. + sway_idle_inhibit_v1_check_active(); } static void handle_abandon(struct wl_listener *listener, void *data) { @@ -297,6 +300,10 @@ static void handle_session_lock(struct wl_listener *listener, void *data) { wlr_session_lock_v1_send_locked(lock); server.session_lock.lock = sway_lock; + + // The lock screen covers everything, so check if any active inhibition got + // deactivated due to lost visibility. + sway_idle_inhibit_v1_check_active(); } static void handle_session_lock_destroy(struct wl_listener *listener, void *data) { diff --git a/sway/main.c b/sway/main.c index cabdd3aa0..69efd6cb4 100644 --- a/sway/main.c +++ b/sway/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -44,10 +45,6 @@ void sway_terminate(int exit_code) { } } -void sig_handler(int signal) { - sway_terminate(EXIT_SUCCESS); -} - void run_as_ipc_client(char *command, char *socket_path) { int socketfd = ipc_open_socket(socket_path); uint32_t len = strlen(command); @@ -125,6 +122,16 @@ static bool detect_suid(void) { return true; } +static 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"); + } +} + 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: " @@ -139,25 +146,38 @@ static void increase_nofile_limit(void) { "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"); - } + + pthread_atfork(NULL, NULL, restore_nofile_limit); } -void restore_signals(void) { +static int term_signal(int signal, void *data) { + sway_terminate(EXIT_SUCCESS); + return 0; +} + +static void restore_signals(void) { sigset_t set; sigemptyset(&set); sigprocmask(SIG_SETMASK, &set, NULL); - signal(SIGCHLD, SIG_DFL); - signal(SIGPIPE, SIG_DFL); + + struct sigaction sa_dfl = { .sa_handler = SIG_DFL }; + sigaction(SIGCHLD, &sa_dfl, NULL); + sigaction(SIGPIPE, &sa_dfl, NULL); +} + +static void init_signals(void) { + wl_event_loop_add_signal(server.wl_event_loop, SIGTERM, term_signal, NULL); + wl_event_loop_add_signal(server.wl_event_loop, SIGINT, term_signal, NULL); + + struct sigaction sa_ign = { .sa_handler = SIG_IGN }; + // avoid need to reap children + sigaction(SIGCHLD, &sa_ign, NULL); + // prevent ipc write errors from crashing sway + sigaction(SIGPIPE, &sa_ign, NULL); + + pthread_atfork(NULL, NULL, restore_signals); } void enable_debug_flag(const char *flag) { @@ -169,8 +189,6 @@ void enable_debug_flag(const char *flag) { debug.txn_timings = true; } else if (has_prefix(flag, "txn-timeout=")) { server.txn_timeout_ms = atoi(&flag[strlen("txn-timeout=")]); - } else if (strcmp(flag, "legacy-wl-drm") == 0) { - debug.legacy_wl_drm = true; } else { sway_log(SWAY_ERROR, "Unknown debug flag: %s", flag); } @@ -330,22 +348,14 @@ int main(int argc, char **argv) { increase_nofile_limit(); - // handle SIGTERM signals - signal(SIGTERM, sig_handler); - signal(SIGINT, sig_handler); - - // avoid need to reap children - signal(SIGCHLD, SIG_IGN); - - // prevent ipc from crashing sway - signal(SIGPIPE, SIG_IGN); - sway_log(SWAY_INFO, "Starting sway version " SWAY_VERSION); if (!server_init(&server)) { return 1; } + init_signals(); + if (server.linux_dmabuf_v1) { wlr_scene_set_linux_dmabuf_v1(root->root_scene, server.linux_dmabuf_v1); } diff --git a/sway/server.c b/sway/server.c index 5de6648f6..979761486 100644 --- a/sway/server.c +++ b/sway/server.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -182,11 +181,11 @@ static void detect_proprietary(struct wlr_backend *backend, void *data) { drmFreeVersion(version); } -static void handle_renderer_lost(struct wl_listener *listener, void *data) { - struct sway_server *server = wl_container_of(listener, server, renderer_lost); +static void do_renderer_recreate(void *data) { + struct sway_server *server = data; + server->recreating_renderer = NULL; sway_log(SWAY_INFO, "Re-creating renderer after GPU reset"); - struct wlr_renderer *renderer = wlr_renderer_autocreate(server->backend); if (renderer == NULL) { sway_log(SWAY_ERROR, "Unable to create renderer"); @@ -221,6 +220,18 @@ static void handle_renderer_lost(struct wl_listener *listener, void *data) { wlr_renderer_destroy(old_renderer); } +static void handle_renderer_lost(struct wl_listener *listener, void *data) { + struct sway_server *server = wl_container_of(listener, server, renderer_lost); + + if (server->recreating_renderer != NULL) { + sway_log(SWAY_DEBUG, "Re-creation of renderer already scheduled"); + return; + } + + sway_log(SWAY_INFO, "Scheduling re-creation of renderer after GPU reset"); + server->recreating_renderer = wl_event_loop_add_idle(server->wl_event_loop, do_renderer_recreate, server); +} + bool server_init(struct sway_server *server) { sway_log(SWAY_DEBUG, "Initializing Wayland server"); server->wl_display = wl_display_create(); @@ -253,9 +264,6 @@ bool server_init(struct sway_server *server) { if (wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF) != NULL) { server->linux_dmabuf_v1 = wlr_linux_dmabuf_v1_create_with_renderer( server->wl_display, 4, server->renderer); - if (debug.legacy_wl_drm) { - wlr_drm_create(server->wl_display, server->renderer); - } } if (wlr_renderer_get_drm_fd(server->renderer) >= 0 && server->renderer->features.timeline && @@ -460,9 +468,35 @@ bool server_init(struct sway_server *server) { } void server_fini(struct sway_server *server) { + // remove listeners + wl_list_remove(&server->renderer_lost.link); + wl_list_remove(&server->new_output.link); + wl_list_remove(&server->layer_shell_surface.link); + wl_list_remove(&server->xdg_shell_toplevel.link); + wl_list_remove(&server->server_decoration.link); + wl_list_remove(&server->xdg_decoration.link); + wl_list_remove(&server->pointer_constraint.link); + wl_list_remove(&server->output_manager_apply.link); + wl_list_remove(&server->output_manager_test.link); + wl_list_remove(&server->output_power_manager_set_mode.link); +#if WLR_HAS_DRM_BACKEND + if (server->drm_lease_manager) { + wl_list_remove(&server->drm_lease_request.link); + } +#endif + wl_list_remove(&server->tearing_control_new_object.link); + wl_list_remove(&server->xdg_activation_v1_request_activate.link); + wl_list_remove(&server->xdg_activation_v1_new_token.link); + wl_list_remove(&server->request_set_cursor_shape.link); + input_manager_finish(server->input); + // TODO: free sway-specific resources #if WLR_HAS_XWAYLAND - wlr_xwayland_destroy(server->xwayland.wlr_xwayland); + if (server->xwayland.wlr_xwayland != NULL) { + wl_list_remove(&server->xwayland_surface.link); + wl_list_remove(&server->xwayland_ready.link); + wlr_xwayland_destroy(server->xwayland.wlr_xwayland); + } #endif wl_display_destroy_clients(server->wl_display); wlr_backend_destroy(server->backend); diff --git a/sway/sway.5.scd b/sway/sway.5.scd index a15f6087d..a4ce1c6b1 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -973,7 +973,7 @@ The default colors are: A criteria is a string in the form of, for example: ``` -[class="[Rr]egex.*" title="some title"] +[app_id="some-application" title="[Rr]egex.*"] ``` The string contains one or more (space separated) attribute/value pairs. They @@ -993,10 +993,19 @@ Focus on a window with the mark "IRC": [con_mark="IRC"] focus ``` -Kill all windows with the title "Emacs": +Kill all windows where the title contains "Emacs": ``` -[class="Emacs"] kill +[title="Emacs"] kill +``` + +Several attributes allow regular expressions. These use Perl-compatible regular +expressions (PCRE2), which are documented in *pcre2pattern*(3) and summarized in +*pcre2syntax*(3). For example, this moves all windows with titles ending in +"sway" or "Sway" to workspace 1: + +``` +[title="[Ss]way$"] move workspace 1 ``` You may like to use swaymsg -t get_tree for finding the values of these @@ -1095,3 +1104,4 @@ The following attributes may be matched with: # SEE ALSO *sway*(1) *sway-input*(5) *sway-output*(5) *sway-bar*(5) *sway-ipc*(7) +*pcre2pattern*(3) *pcre2syntax*(3) diff --git a/sway/swaynag.c b/sway/swaynag.c index f0a31218a..204a5791a 100644 --- a/sway/swaynag.c +++ b/sway/swaynag.c @@ -63,7 +63,6 @@ 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(); if (!sway_set_cloexec(sockets[1], false)) { _exit(EXIT_FAILURE); } @@ -148,4 +147,3 @@ void swaynag_show(struct swaynag_instance *swaynag) { close(swaynag->fd[1]); } } - diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 2b95a6dc9..faf54d02a 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -29,7 +29,7 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) { } } - // Calculate each height fraction + // Calculate each width fraction double total_width_fraction = 0; for (int i = 0; i < children->length; ++i) { struct sway_container *child = children->items[i]; @@ -82,12 +82,18 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) { child->pending.y = parent->y; child->pending.width = round(child->width_fraction * child_total_width); child->pending.height = parent->height; - child_x += child->pending.width + inner_gap; // Make last child use remaining width of parent if (i == children->length - 1) { child->pending.width = parent->x + parent->width - child->pending.x; } + + // Arbitrary lower bound for window size + if (child->pending.width < 10 || child->pending.height < 10) { + child->pending.width = 0; + child->pending.height = 0; + } + child_x += child->pending.width + inner_gap; } } @@ -161,12 +167,18 @@ static void apply_vert_layout(list_t *children, struct wlr_box *parent) { child->pending.y = child_y; child->pending.width = parent->width; child->pending.height = round(child->height_fraction * child_total_height); - child_y += child->pending.height + inner_gap; // Make last child use remaining height of parent if (i == children->length - 1) { child->pending.height = parent->y + parent->height - child->pending.y; } + + // Arbitrary lower bound for window size + if (child->pending.width < 10 || child->pending.height < 10) { + child->pending.width = 0; + child->pending.height = 0; + } + child_y += child->pending.height + inner_gap; } } diff --git a/sway/tree/container.c b/sway/tree/container.c index 6ff4036fa..0385d7c17 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -50,6 +50,14 @@ static void handle_output_leave( } } +static void handle_destroy( + struct wl_listener *listener, void *data) { + struct sway_container *con = wl_container_of( + listener, con, output_handler_destroy); + + container_begin_destroy(con); +} + static bool handle_point_accepts_input( struct wlr_scene_buffer *buffer, double *x, double *y) { return false; @@ -135,6 +143,9 @@ struct sway_container *container_create(struct sway_view *view) { c->output_leave.notify = handle_output_leave; wl_signal_add(&c->output_handler->events.output_leave, &c->output_leave); + c->output_handler_destroy.notify = handle_destroy; + wl_signal_add(&c->output_handler->node.events.destroy, + &c->output_handler_destroy); c->output_handler->point_accepts_input = handle_point_accepts_input; } } @@ -508,8 +519,6 @@ void container_destroy(struct sway_container *con) { if (con->view && con->view->container == con) { con->view->container = NULL; - wl_list_remove(&con->output_enter.link); - wl_list_remove(&con->output_leave.link); wlr_scene_node_destroy(&con->output_handler->node); if (con->view->destroying) { view_destroy(con->view); @@ -552,6 +561,12 @@ void container_begin_destroy(struct sway_container *con) { if (con->pending.parent || con->pending.workspace) { container_detach(con); } + + if (con->view && con->view->container == con) { + wl_list_remove(&con->output_enter.link); + wl_list_remove(&con->output_leave.link); + wl_list_remove(&con->output_handler_destroy.link); + } } void container_reap_empty(struct sway_container *con) { diff --git a/sway/tree/output.c b/sway/tree/output.c index 65d9e3e71..b02c1a2ce 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -37,7 +37,7 @@ static void restore_workspaces(struct sway_output *output) { for (int j = 0; j < other->workspaces->length; j++) { struct sway_workspace *ws = other->workspaces->items[j]; struct sway_output *highest = - workspace_output_get_highest_available(ws, NULL); + workspace_output_get_highest_available(ws); if (highest == output) { workspace_detach(ws); output_add_workspace(output, ws); @@ -205,11 +205,8 @@ static void output_evacuate(struct sway_output *output) { return; } struct sway_output *fallback_output = NULL; - if (root->outputs->length > 1) { + if (root->outputs->length > 0) { fallback_output = root->outputs->items[0]; - if (fallback_output == output) { - fallback_output = root->outputs->items[1]; - } } while (output->workspaces->length) { @@ -218,7 +215,7 @@ static void output_evacuate(struct sway_output *output) { workspace_detach(workspace); struct sway_output *new_output = - workspace_output_get_highest_available(workspace, output); + workspace_output_get_highest_available(workspace); if (!new_output) { new_output = fallback_output; } @@ -289,11 +286,13 @@ void output_disable(struct sway_output *output) { sway_log(SWAY_DEBUG, "Disabling output '%s'", output->wlr_output->name); wl_signal_emit_mutable(&output->events.disable, output); - output_evacuate(output); - + // Remove the output now to avoid interacting with it during e.g., + // transactions, as the output might be physically removed with the scene + // output destroyed. list_del(root->outputs, index); - output->enabled = false; + + output_evacuate(output); } void output_begin_destroy(struct sway_output *output) { diff --git a/sway/tree/root.c b/sway/tree/root.c index 19d072b5c..33c29d381 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c @@ -199,6 +199,8 @@ void root_scratchpad_show(struct sway_container *con) { if (old_ws) { workspace_consider_destroy(old_ws); } + + container_raise_floating(con); } static void disable_fullscreen(struct sway_container *con, void *data) { diff --git a/sway/tree/view.c b/sway/tree/view.c index 33161cc53..9a5cf06e0 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -12,6 +12,7 @@ #include #include #include +#include #if WLR_HAS_XWAYLAND #include #endif @@ -217,6 +218,10 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, } bool view_inhibit_idle(struct sway_view *view) { + if (server.session_lock.lock) { + return false; + } + struct sway_idle_inhibitor_v1 *user_inhibitor = sway_idle_inhibit_v1_user_inhibitor_for_view(view); @@ -512,10 +517,12 @@ void view_execute_criteria(struct sway_view *view) { sway_log(SWAY_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", criteria->raw, view, criteria->cmdlist); list_add(view->executed_criteria, criteria); - list_t *res_list = execute_command( - criteria->cmdlist, NULL, view->container); + list_t *res_list = execute_command(criteria->cmdlist, NULL, view->container); while (res_list->length) { struct cmd_results *res = res_list->items[0]; + if (res->status != CMD_SUCCESS) { + sway_log(SWAY_ERROR, "for_window '%s' failed: %s", criteria->raw, res->error); + } free_cmd_results(res); list_del(res_list, 0); } @@ -1010,6 +1017,9 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { if (wlr_layer_surface_v1_try_from_wlr_surface(wlr_surface) != NULL) { return NULL; } + if (wlr_session_lock_surface_v1_try_from_wlr_surface(wlr_surface) != NULL) { + return NULL; + } const char *role = wlr_surface->role ? wlr_surface->role->name : NULL; sway_log(SWAY_DEBUG, "Surface of unknown type (role %s): %p", diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index a09dc3a45..f2be4cd13 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -659,13 +659,9 @@ void workspace_output_add_priority(struct sway_workspace *workspace, } struct sway_output *workspace_output_get_highest_available( - struct sway_workspace *ws, struct sway_output *exclude) { + struct sway_workspace *ws) { for (int i = 0; i < ws->output_priority->length; i++) { const char *name = ws->output_priority->items[i]; - if (exclude && output_match_name_or_id(exclude, name)) { - continue; - } - struct sway_output *output = output_by_name_or_id(name); if (output) { return output; diff --git a/swaybar/ipc.c b/swaybar/ipc.c index f651f0359..68d8dd32d 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -46,7 +46,7 @@ void ipc_send_workspace_command(struct swaybar *bar, const char *ws) { char *parse_font(const char *font) { char *new_font = NULL; - if (has_prefix("pango:", font)) { + if (has_prefix(font, "pango:")) { font += strlen("pango:"); } new_font = strdup(font); diff --git a/swaybar/main.c b/swaybar/main.c index 3dc672334..e1b0cecac 100644 --- a/swaybar/main.c +++ b/swaybar/main.c @@ -93,8 +93,9 @@ int main(int argc, char **argv) { free(socket_path); - signal(SIGINT, sig_handler); - signal(SIGTERM, sig_handler); + struct sigaction sa = { .sa_handler = sig_handler }; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); swaybar.running = true; bar_run(&swaybar); diff --git a/swaybar/render.c b/swaybar/render.c index 45faefa97..c51321f18 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -13,7 +13,6 @@ #include "swaybar/ipc.h" #include "swaybar/render.h" #include "swaybar/status_line.h" -#include "log.h" #if HAVE_TRAY #include "swaybar/tray/tray.h" #endif @@ -21,7 +20,7 @@ static const int WS_HORIZONTAL_PADDING = 5; static const double WS_VERTICAL_PADDING = 1.5; -static const double BORDER_WIDTH = 1; +static const int BORDER_WIDTH = 1; struct render_context { cairo_t *cairo; @@ -541,6 +540,63 @@ static uint32_t render_status_line(struct render_context *ctx, double *x) { return 0; } +static struct box_size render_box(struct render_context *ctx, double x, + struct box_colors colors, const char *label, bool pango_markup) { + struct swaybar_output *output = ctx->output; + struct swaybar_config *config = output->bar->config; + cairo_t *cairo = ctx->cairo; + + int text_width, text_height; + get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, + 1, pango_markup, "%s", label); + + uint32_t width = text_width + WS_HORIZONTAL_PADDING * 2 + BORDER_WIDTH * 2; + if (width < config->workspace_min_width) { + width = config->workspace_min_width; + } + + uint32_t ideal_height = text_height + WS_VERTICAL_PADDING * 2 + + BORDER_WIDTH * 2; + uint32_t ideal_surface_height = ideal_height; + if (!output->bar->config->height && + output->height < ideal_surface_height) { + return (struct box_size) { + .width = width, + .height = ideal_surface_height, + }; + } + + uint32_t height = output->height; + cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); + cairo_set_source_u32(cairo, colors.background); + ctx->background_color = colors.background; + ctx->has_transparency |= (colors.background & 0xFF) != 0xFF; + cairo_rectangle(cairo, x, 0, width, height); + cairo_fill(cairo); + + cairo_set_source_u32(cairo, colors.border); + cairo_rectangle(cairo, x, 0, width, BORDER_WIDTH); + cairo_fill(cairo); + cairo_rectangle(cairo, x, 0, BORDER_WIDTH, height); + cairo_fill(cairo); + cairo_rectangle(cairo, x + width - BORDER_WIDTH, 0, BORDER_WIDTH, height); + cairo_fill(cairo); + cairo_rectangle(cairo, x, height - BORDER_WIDTH, width, BORDER_WIDTH); + cairo_fill(cairo); + + double text_y = height / 2.0 - text_height / 2.0; + cairo_set_source_u32(cairo, colors.text); + cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); + choose_text_aa_mode(ctx, colors.text); + render_text(cairo, config->font_description, 1, pango_markup, + "%s", label); + + return (struct box_size) { + .width = width, + .height = output->height, + }; +} + static uint32_t render_binding_mode_indicator(struct render_context *ctx, double x) { struct swaybar_output *output = ctx->output; @@ -549,54 +605,9 @@ static uint32_t render_binding_mode_indicator(struct render_context *ctx, return 0; } - cairo_t *cairo = ctx->cairo; - struct swaybar_config *config = output->bar->config; - int text_width, text_height; - get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, - 1, output->bar->mode_pango_markup, - "%s", mode); - - int ws_vertical_padding = WS_VERTICAL_PADDING; - int ws_horizontal_padding = WS_HORIZONTAL_PADDING; - int border_width = BORDER_WIDTH; - - uint32_t ideal_height = text_height + ws_vertical_padding * 2 - + border_width * 2; - uint32_t ideal_surface_height = ideal_height; - if (!output->bar->config->height && - output->height < ideal_surface_height) { - return ideal_surface_height; - } - uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; - if (width < config->workspace_min_width) { - width = config->workspace_min_width; - } - - uint32_t height = output->height; - cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); - cairo_set_source_u32(cairo, config->colors.binding_mode.background); - ctx->background_color = config->colors.binding_mode.background; - ctx->has_transparency |= (config->colors.binding_mode.background & 0xFF) != 0xFF; - cairo_rectangle(cairo, x, 0, width, height); - cairo_fill(cairo); - - cairo_set_source_u32(cairo, config->colors.binding_mode.border); - cairo_rectangle(cairo, x, 0, width, border_width); - cairo_fill(cairo); - cairo_rectangle(cairo, x, 0, border_width, height); - cairo_fill(cairo); - cairo_rectangle(cairo, x + width - border_width, 0, border_width, height); - cairo_fill(cairo); - cairo_rectangle(cairo, x, height - border_width, width, border_width); - cairo_fill(cairo); - - double text_y = height / 2.0 - text_height / 2.0; - cairo_set_source_u32(cairo, config->colors.binding_mode.text); - cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); - choose_text_aa_mode(ctx, config->colors.binding_mode.text); - render_text(cairo, config->font_description, 1, output->bar->mode_pango_markup, - "%s", mode); - return output->height; + struct box_size size = render_box(ctx, x, output->bar->config->colors.binding_mode, + mode, output->bar->mode_pango_markup); + return size.height; } static enum hotspot_event_handling workspace_hotspot_callback( @@ -618,6 +629,7 @@ static uint32_t render_workspace_button(struct render_context *ctx, struct swaybar_workspace *ws, double *x) { struct swaybar_output *output = ctx->output; struct swaybar_config *config = output->bar->config; + struct box_colors box_colors; if (ws->urgent) { box_colors = config->colors.urgent_workspace; @@ -629,66 +641,21 @@ static uint32_t render_workspace_button(struct render_context *ctx, box_colors = config->colors.inactive_workspace; } - uint32_t height = output->height; - - cairo_t *cairo = ctx->cairo; - int text_width, text_height; - get_text_size(cairo, config->font_description, &text_width, &text_height, NULL, - 1, config->pango_markup, "%s", ws->label); - - int ws_vertical_padding = WS_VERTICAL_PADDING; - int ws_horizontal_padding = WS_HORIZONTAL_PADDING; - int border_width = BORDER_WIDTH; - - uint32_t ideal_height = ws_vertical_padding * 2 + text_height - + border_width * 2; - uint32_t ideal_surface_height = ideal_height; - if (!output->bar->config->height && - output->height < ideal_surface_height) { - return ideal_surface_height; - } - - uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; - if (width < config->workspace_min_width) { - width = config->workspace_min_width; - } - - cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); - cairo_set_source_u32(cairo, box_colors.background); - ctx->background_color = box_colors.background; - ctx->has_transparency |= (box_colors.background & 0xFF) != 0xFF; - cairo_rectangle(cairo, *x, 0, width, height); - cairo_fill(cairo); - - cairo_set_source_u32(cairo, box_colors.border); - cairo_rectangle(cairo, *x, 0, width, border_width); - cairo_fill(cairo); - cairo_rectangle(cairo, *x, 0, border_width, height); - cairo_fill(cairo); - cairo_rectangle(cairo, *x + width - border_width, 0, border_width, height); - cairo_fill(cairo); - cairo_rectangle(cairo, *x, height - border_width, width, border_width); - cairo_fill(cairo); - - double text_y = height / 2.0 - text_height / 2.0; - cairo_set_source_u32(cairo, box_colors.text); - cairo_move_to(cairo, *x + width / 2 - text_width / 2, (int)floor(text_y)); - choose_text_aa_mode(ctx, box_colors.text); - render_text(cairo, config->font_description, 1, config->pango_markup, - "%s", ws->label); + struct box_size size = render_box(ctx, *x, box_colors, + ws->label, config->pango_markup); struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); hotspot->x = *x; hotspot->y = 0; - hotspot->width = width; - hotspot->height = height; + hotspot->width = size.width; + hotspot->height = size.height; hotspot->callback = workspace_hotspot_callback; hotspot->destroy = free; hotspot->data = strdup(ws->name); wl_list_insert(&output->hotspots, &hotspot->link); - *x += width; - return output->height; + *x += size.width; + return size.height; } static uint32_t render_to_cairo(struct render_context *ctx) { diff --git a/swaymsg/main.c b/swaymsg/main.c index 7534ea6db..6a9eb1987 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -16,10 +16,6 @@ #include "ipc-client.h" #include "log.h" -void sway_terminate(int exit_code) { - exit(exit_code); -} - static bool success_object(json_object *result) { json_object *success; @@ -99,7 +95,7 @@ static const char *pretty_type_name(const char *name) { const char *b; } type_names[] = { { "keyboard", "Keyboard" }, - { "pointer", "Mouse" }, + { "pointer", "Pointer" }, { "touchpad", "Touchpad" }, { "tablet_pad", "Tablet pad" }, { "tablet_tool", "Tablet tool" }, diff --git a/swaynag/main.c b/swaynag/main.c index 634bddbfc..b68157ff2 100644 --- a/swaynag/main.c +++ b/swaynag/main.c @@ -13,11 +13,6 @@ void sig_handler(int signal) { exit(EXIT_FAILURE); } -void sway_terminate(int code) { - swaynag_destroy(&swaynag); - exit(code); -} - int main(int argc, char **argv) { int status = EXIT_SUCCESS; @@ -107,7 +102,8 @@ int main(int argc, char **argv) { sway_log(SWAY_DEBUG, "\t[%s] `%s`", button->text, button->action); } - signal(SIGTERM, sig_handler); + struct sigaction sa = { .sa_handler = sig_handler }; + sigaction(SIGTERM, &sa, NULL); swaynag_setup(&swaynag); swaynag_run(&swaynag);