diff --git a/common/stringop.c b/common/stringop.c index 8af0d60fa..709be6842 100644 --- a/common/stringop.c +++ b/common/stringop.c @@ -258,6 +258,9 @@ int unescape_string(char *string) { } char *join_args(char **argv, int argc) { + if (!sway_assert(argc > 0, "argc should be positive")) { + return NULL; + } int len = 0, i; for (i = 0; i < argc; ++i) { len += strlen(argv[i]) + 1; diff --git a/include/sway/commands.h b/include/sway/commands.h index 3ed007635..764821a0e 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -112,7 +112,6 @@ sway_cmd cmd_client_placeholder; sway_cmd cmd_client_background; sway_cmd cmd_commands; sway_cmd cmd_create_output; -sway_cmd cmd_debuglog; sway_cmd cmd_default_border; sway_cmd cmd_default_floating_border; sway_cmd cmd_default_orientation; diff --git a/include/sway/config.h b/include/sway/config.h index 43ea77788..54cdcc908 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -586,6 +586,8 @@ struct output_config *store_output_config(struct output_config *oc); void apply_output_config_to_outputs(struct output_config *oc); +void reset_outputs(void); + void free_output_config(struct output_config *oc); int workspace_output_cmp_workspace(const void *a, const void *b); diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 072a56ca1..98eb4679b 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h @@ -72,6 +72,7 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat); * This chooses a cursor icon and sends a motion event to the surface. */ void cursor_rebase(struct sway_cursor *cursor); +void cursor_rebase_all(void); void cursor_handle_activity(struct sway_cursor *cursor); void cursor_unhide(struct sway_cursor *cursor); diff --git a/include/sway/input/input-manager.h b/include/sway/input/input-manager.h index 8e8bf1f20..e166a2377 100644 --- a/include/sway/input/input-manager.h +++ b/include/sway/input/input-manager.h @@ -45,7 +45,7 @@ void input_manager_apply_seat_config(struct seat_config *seat_config); struct sway_seat *input_manager_get_default_seat(void); -struct sway_seat *input_manager_get_seat(const char *seat_name); +struct sway_seat *input_manager_get_seat(const char *seat_name, bool create); /** * If none of the seat configs have a fallback setting (either true or false), diff --git a/include/sway/output.h b/include/sway/output.h index 479897ef2..ea7a21741 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -21,6 +21,7 @@ struct sway_output { struct sway_node node; struct wlr_output *wlr_output; struct sway_server *server; + struct wl_list link; struct wl_list layers[4]; // sway_layer_surface::link struct wlr_box usable_area; @@ -36,6 +37,8 @@ struct sway_output { struct sway_output_state current; + struct wl_client *swaybg_client; + struct wl_listener destroy; struct wl_listener mode; struct wl_listener transform; @@ -43,10 +46,7 @@ struct sway_output { struct wl_listener present; struct wl_listener damage_destroy; struct wl_listener damage_frame; - - struct wl_list link; - - pid_t bg_pid; + struct wl_listener swaybg_client_destroy; struct { struct wl_signal destroy; diff --git a/include/sway/tree/output.h b/include/sway/tree/output.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 2d9ba0d9b..2518d5aa8 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -46,6 +46,8 @@ struct swaybar { #if HAVE_TRAY struct swaybar_tray *tray; #endif + + bool running; }; struct swaybar_output { diff --git a/meson.build b/meson.build index 766bf012f..d3172bdd8 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,7 @@ project( 'sway', 'c', + version: '1.0', license: 'MIT', meson_version: '>=0.48.0', default_options: [ @@ -59,7 +60,11 @@ rt = cc.find_library('rt') git = find_program('git', required: false) # Try first to find wlroots as a subproject, then as a system dependency -wlroots_proj = subproject('wlroots', required: false) +wlroots_proj = subproject( + 'wlroots', + default_options: ['rootston=false', 'examples=false'], + required: false, +) if wlroots_proj.found() wlroots = wlroots_proj.get_variable('wlroots') wlroots_conf = wlroots_proj.get_variable('conf_data') @@ -127,17 +132,13 @@ endif add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir)), language : 'c') -version = get_option('sway-version') -if version != '' - version = '"@0@"'.format(version) -else - if not git.found() - error('git is required to make the version string') +version = '"@0@"'.format(meson.project_version()) +if git.found() + git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags']) + git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']) + if git_commit_hash.returncode() == 0 and git_branch.returncode() == 0 + version = '"@0@ (" __DATE__ ", branch \'@1@\')"'.format(git_commit_hash.stdout().strip(), git_branch.stdout().strip()) endif - - git_commit_hash = run_command([git.path(), 'describe', '--always', '--tags']).stdout().strip() - git_branch = run_command([git.path(), 'rev-parse', '--abbrev-ref', 'HEAD']).stdout().strip() - version = '"@0@ (" __DATE__ ", branch \'@1@\')"'.format(git_commit_hash, git_branch) endif add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c') diff --git a/meson_options.txt b/meson_options.txt index 04b29e17a..d3667acfd 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,4 +1,3 @@ -option('sway-version', type : 'string', description: 'The version string reported in `sway --version`.') option('default-wallpaper', type: 'boolean', value: true, description: 'Install the default wallpaper.') option('zsh-completions', type: 'boolean', value: true, description: 'Install zsh shell completions.') option('bash-completions', type: 'boolean', value: true, description: 'Install bash shell completions.') diff --git a/sway/commands.c b/sway/commands.c index dd994fa15..3fc4f86e4 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -254,7 +254,8 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, //TODO better handling of argv int argc; char **argv = split_args(cmd, &argc); - if (strcmp(argv[0], "exec") != 0) { + if (strcmp(argv[0], "exec") != 0 && + strcmp(argv[0], "exec_always") != 0) { int i; for (i = 1; i < argc; ++i) { if (*argv[i] == '\"' || *argv[i] == '\'') { diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c index d89ddf24e..68a80abf6 100644 --- a/sway/commands/bar/mode.c +++ b/sway/commands/bar/mode.c @@ -11,7 +11,7 @@ static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode if (strcasecmp("toggle", mode) == 0 && !config->reading) { if (strcasecmp("dock", bar->mode) == 0) { bar->mode = strdup("hide"); - } else if (strcasecmp("hide", bar->mode) == 0) { + } else{ bar->mode = strdup("dock"); } } else if (strcasecmp("dock", mode) == 0) { diff --git a/sway/commands/bar/modifier.c b/sway/commands/bar/modifier.c index c95250d11..d25d01d4b 100644 --- a/sway/commands/bar/modifier.c +++ b/sway/commands/bar/modifier.c @@ -15,19 +15,26 @@ struct cmd_results *bar_cmd_modifier(int argc, char **argv) { } uint32_t mod = 0; - list_t *split = split_string(argv[0], "+"); - for (int i = 0; i < split->length; ++i) { - uint32_t tmp_mod; - if ((tmp_mod = get_modifier_mask_by_name(split->items[i])) > 0) { - mod |= tmp_mod; - } else { - error = cmd_results_new(CMD_INVALID, - "Unknown modifier '%s'", (char *)split->items[i]); - list_free_items_and_destroy(split); - return error; + if (strcmp(argv[0], "none") != 0) { + list_t *split = split_string(argv[0], "+"); + for (int i = 0; i < split->length; ++i) { + uint32_t tmp_mod; + if ((tmp_mod = get_modifier_mask_by_name(split->items[i])) > 0) { + mod |= tmp_mod; + } else if (strcmp(split->items[i], "none") == 0) { + error = cmd_results_new(CMD_INVALID, + "none cannot be used along with other modifiers"); + list_free_items_and_destroy(split); + return error; + } else { + error = cmd_results_new(CMD_INVALID, + "Unknown modifier '%s'", (char *)split->items[i]); + list_free_items_and_destroy(split); + return error; + } } + list_free_items_and_destroy(split); } - list_free_items_and_destroy(split); config->current_bar->modifier = mod; sway_log(SWAY_DEBUG, "Show/Hide the bar when pressing '%s' in hide mode.", argv[0]); diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 59116d67f..172e6b8ae 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -1,10 +1,11 @@ #define _POSIX_C_SOURCE 200809L #include #include -#include -#include #include #include +#include +#include +#include #include "sway/commands.h" #include "sway/config.h" #include "sway/input/cursor.h" @@ -330,7 +331,20 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) { void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { sway_log(SWAY_DEBUG, "running command for binding: %s", binding->command); - list_t *res_list = execute_command(binding->command, seat, NULL); + struct sway_container *con = NULL; + if (binding->type == BINDING_MOUSESYM + || binding->type == BINDING_MOUSECODE) { + struct wlr_surface *surface = NULL; + double sx, sy; + struct sway_node *node = node_at_coords(seat, + seat->cursor->cursor->x, seat->cursor->cursor->y, + &surface, &sx, &sy); + if (node && node->type == N_CONTAINER) { + con = node->sway_container; + } + } + + list_t *res_list = execute_command(binding->command, seat, con); bool success = true; for (int i = 0; i < res_list->length; ++i) { struct cmd_results *results = res_list->items[i]; diff --git a/sway/commands/move.c b/sway/commands/move.c index 8c3afae97..16f8cdb6f 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -516,7 +516,6 @@ static struct cmd_results *cmd_move_container(int argc, char **argv) { // move container if (container->scratchpad) { - root_scratchpad_remove_container(container); root_scratchpad_show(container); } switch (destination->type) { diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c index f65904bb8..5a15ed0fc 100644 --- a/sway/commands/output/background.c +++ b/sway/commands/output/background.c @@ -61,6 +61,9 @@ struct cmd_results *output_cmd_background(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "Missing background scaling mode."); } + if (j == 0) { + return cmd_results_new(CMD_INVALID, "Missing background file"); + } wordexp_t p = {0}; char *src = join_args(argv, j); diff --git a/sway/commands/seat.c b/sway/commands/seat.c index 5b23dcc6a..aa36ba955 100644 --- a/sway/commands/seat.c +++ b/sway/commands/seat.c @@ -50,5 +50,5 @@ struct cmd_results *cmd_seat(int argc, char **argv) { } config->handler_context.seat_config = NULL; - return cmd_results_new(CMD_SUCCESS, NULL); + return res ? res : cmd_results_new(CMD_SUCCESS, NULL); } diff --git a/sway/commands/seat/cursor.c b/sway/commands/seat/cursor.c index 4f805b227..085e6a33f 100644 --- a/sway/commands/seat/cursor.c +++ b/sway/commands/seat/cursor.c @@ -12,7 +12,7 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor, static const char expected_syntax[] = "Expected 'cursor ' or " "'cursor ' or " - "'curor '"; + "'cursor '"; static struct cmd_results *handle_command(struct sway_cursor *cursor, int argc, char **argv) { @@ -61,9 +61,10 @@ struct cmd_results *seat_cmd_cursor(int argc, char **argv) { } if (strcmp(sc->name, "*") != 0) { - struct sway_seat *seat = input_manager_get_seat(sc->name); + struct sway_seat *seat = input_manager_get_seat(sc->name, false); if (!seat) { - return cmd_results_new(CMD_FAILURE, "Failed to get seat"); + return cmd_results_new(CMD_FAILURE, + "Seat %s does not exist", sc->name); } error = handle_command(seat->cursor, argc, argv); } else { diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index c5d6435a4..65a3f4075 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -76,7 +76,6 @@ static struct cmd_results *cmd_workspace_gaps(int argc, char **argv, char *end; int amount = strtol(argv[gaps_location + 2], &end, 10); if (strlen(end)) { - free(end); return cmd_results_new(CMD_FAILURE, expected); } diff --git a/sway/config.c b/sway/config.c index 7cb27d955..206ca95cb 100644 --- a/sway/config.c +++ b/sway/config.c @@ -118,7 +118,7 @@ void free_config(struct sway_config *config) { } list_free(config->no_focus); list_free(config->active_bar_modifiers); - list_free(config->config_chain); + list_free_items_and_destroy(config->config_chain); list_free(config->command_policies); list_free(config->feature_policies); list_free(config->ipc_policies); @@ -141,11 +141,18 @@ static void destroy_removed_seats(struct sway_config *old_config, int i; for (i = 0; i < old_config->seat_configs->length; i++) { seat_config = old_config->seat_configs->items[i]; + // Skip the wildcard seat config, it won't have a matching real seat. + if (strcmp(seat_config->name, "*") == 0) { + continue; + } + /* Also destroy seats that aren't present in new config */ if (new_config && list_seq_find(new_config->seat_configs, seat_name_cmp, seat_config->name) < 0) { - seat = input_manager_get_seat(seat_config->name); - seat_destroy(seat); + seat = input_manager_get_seat(seat_config->name, false); + if (seat) { + seat_destroy(seat); + } } } } @@ -372,6 +379,13 @@ bool load_main_config(const char *file, bool is_active, bool validating) { path = get_config_path(); } + char *real_path = realpath(path, NULL); + if (real_path == NULL) { + sway_log(SWAY_DEBUG, "%s not found.", path); + free(path); + return false; + } + struct sway_config *old_config = config; config = calloc(1, sizeof(struct sway_config)); if (!config) { @@ -395,7 +409,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { } config->current_config_path = path; - list_add(config->config_chain, path); + list_add(config->config_chain, real_path); config->reading = true; @@ -457,9 +471,8 @@ bool load_main_config(const char *file, bool is_active, bool validating) { } if (is_active) { - for (int i = 0; i < config->output_configs->length; i++) { - apply_output_config_to_outputs(config->output_configs->items[i]); - } + reset_outputs(); + config->reloading = false; if (config->swaynag_config_errors.pid > 0) { swaynag_show(&config->swaynag_config_errors); @@ -550,7 +563,7 @@ bool load_include_configs(const char *path, struct sway_config *config, wordexp_t p; - if (wordexp(path, &p, 0) < 0) { + if (wordexp(path, &p, 0) != 0) { free(parent_path); free(wd); return false; diff --git a/sway/config/bar.c b/sway/config/bar.c index bafef307c..2e28fa1ef 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -46,6 +46,7 @@ void free_bar_config(struct bar_config *bar) { free(bar->position); free(bar->hidden_state); free(bar->status_command); + free(bar->swaybar_command); free(bar->font); free(bar->separator_symbol); for (int i = 0; i < bar->bindings->length; i++) { diff --git a/sway/config/output.c b/sway/config/output.c index 970764b03..513d03e0f 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -1,16 +1,17 @@ #define _POSIX_C_SOURCE 200809L #include +#include #include #include -#include +#include #include #include -#include #include +#include +#include "log.h" #include "sway/config.h" #include "sway/output.h" #include "sway/tree/root.h" -#include "log.h" int output_name_cmp(const void *item, const void *data) { const struct output_config *output = item; @@ -165,14 +166,71 @@ static bool set_mode(struct wlr_output *output, int width, int height, return wlr_output_set_mode(output, best); } -void terminate_swaybg(pid_t pid) { - int ret = kill(pid, SIGTERM); - if (ret != 0) { - sway_log(SWAY_ERROR, "Unable to terminate swaybg [pid: %d]", pid); - } else { - int status; - waitpid(pid, &status, 0); +static void handle_swaybg_client_destroy(struct wl_listener *listener, + void *data) { + struct sway_output *output = + wl_container_of(listener, output, swaybg_client_destroy); + wl_list_remove(&output->swaybg_client_destroy.link); + wl_list_init(&output->swaybg_client_destroy.link); + output->swaybg_client = NULL; +} + +static bool spawn_swaybg(struct sway_output *output, char *const cmd[]) { + int sockets[2]; + if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sockets) != 0) { + sway_log_errno(SWAY_ERROR, "socketpair failed"); + return false; } + + output->swaybg_client = wl_client_create(server.wl_display, sockets[0]); + if (output->swaybg_client == NULL) { + sway_log_errno(SWAY_ERROR, "wl_client_create failed"); + return false; + } + + output->swaybg_client_destroy.notify = handle_swaybg_client_destroy; + wl_client_add_destroy_listener(output->swaybg_client, + &output->swaybg_client_destroy); + + pid_t pid = fork(); + if (pid < 0) { + sway_log_errno(SWAY_ERROR, "fork failed"); + return false; + } else if (pid == 0) { + pid = fork(); + if (pid < 0) { + sway_log_errno(SWAY_ERROR, "fork failed"); + exit(EXIT_FAILURE); + } else if (pid == 0) { + // Remove the CLOEXEC flag + int flags = fcntl(sockets[1], F_GETFD); + if (flags == -1) { + sway_log_errno(SWAY_ERROR, "fcntl() failed"); + exit(EXIT_FAILURE); + } + if (fcntl(sockets[1], F_SETFD, flags & ~FD_CLOEXEC) == -1) { + sway_log_errno(SWAY_ERROR, "fcntl() failed"); + exit(EXIT_FAILURE); + } + + char wayland_socket_str[16]; + snprintf(wayland_socket_str, sizeof(wayland_socket_str), + "%d", sockets[1]); + setenv("WAYLAND_SOCKET", wayland_socket_str, true); + + execvp(cmd[0], cmd); + sway_log_errno(SWAY_ERROR, "execvp failed"); + exit(EXIT_FAILURE); + } + exit(EXIT_SUCCESS); + } + + if (waitpid(pid, NULL, 0) < 0) { + sway_log_errno(SWAY_ERROR, "waitpid failed"); + return false; + } + + return true; } bool apply_output_config(struct output_config *oc, struct sway_output *output) { @@ -199,6 +257,11 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { return true; } + if (oc && oc->dpms_state == DPMS_ON) { + sway_log(SWAY_DEBUG, "Turning on screen"); + wlr_output_enable(wlr_output, true); + } + bool modeset_success; if (oc && oc->width > 0 && oc->height > 0) { sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f GHz)", oc->name, oc->width, @@ -238,8 +301,8 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { wlr_output_layout_add_auto(root->output_layout, wlr_output); } - if (output->bg_pid != 0) { - terminate_swaybg(output->bg_pid); + if (output->swaybg_client != NULL) { + wl_client_destroy(output->swaybg_client); } if (oc && oc->background && config->swaybg_command) { sway_log(SWAY_DEBUG, "Setting background for output %s to %s", @@ -253,29 +316,14 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { oc->background_fallback ? oc->background_fallback : NULL, NULL, }; - - output->bg_pid = fork(); - if (output->bg_pid < 0) { - sway_log_errno(SWAY_ERROR, "fork failed"); - } else if (output->bg_pid == 0) { - execvp(cmd[0], cmd); - sway_log_errno(SWAY_ERROR, "Failed to execute swaybg"); + if (!spawn_swaybg(output, cmd)) { + return false; } } - if (oc) { - switch (oc->dpms_state) { - case DPMS_ON: - sway_log(SWAY_DEBUG, "Turning on screen"); - wlr_output_enable(wlr_output, true); - break; - case DPMS_OFF: - sway_log(SWAY_DEBUG, "Turning off screen"); - wlr_output_enable(wlr_output, false); - break; - case DPMS_IGNORE: - break; - } + if (oc && oc->dpms_state == DPMS_OFF) { + sway_log(SWAY_DEBUG, "Turning off screen"); + wlr_output_enable(wlr_output, false); } return true; @@ -294,6 +342,7 @@ static void default_output_config(struct output_config *oc, oc->x = oc->y = -1; oc->scale = 1; oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; + oc->dpms_state = DPMS_ON; } static struct output_config *get_output_config(char *identifier, @@ -395,6 +444,17 @@ void apply_output_config_to_outputs(struct output_config *oc) { } } +void reset_outputs(void) { + struct output_config *oc = NULL; + int i = list_seq_find(config->output_configs, output_name_cmp, "*"); + if (i >= 0) { + oc = config->output_configs->items[i]; + } else { + oc = store_output_config(new_output_config("*")); + } + apply_output_config_to_outputs(oc); +} + void free_output_config(struct output_config *oc) { if (!oc) { return; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index de8db75df..0767247c4 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -6,7 +6,9 @@ #include #include #include +#include "log.h" #include "sway/desktop/transaction.h" +#include "sway/input/cursor.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/layers.h" @@ -14,7 +16,6 @@ #include "sway/server.h" #include "sway/tree/arrange.h" #include "sway/tree/workspace.h" -#include "log.h" static void apply_exclusive(struct wlr_box *usable_area, uint32_t anchor, int32_t exclusive, @@ -302,6 +303,8 @@ static void unmap(struct sway_layer_surface *sway_layer) { if (seat->focused_layer == sway_layer->layer_surface) { seat_set_focus_layer(seat, NULL); } + + cursor_rebase_all(); } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -321,7 +324,6 @@ static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_output *output = sway_layer->layer_surface->output->data; if (output != NULL) { arrange_layers(output); - arrange_output(output); transaction_commit_dirty(); } wl_list_remove(&sway_layer->output_destroy.link); @@ -339,6 +341,7 @@ static void handle_map(struct wl_listener *listener, void *data) { // TODO: send enter to subsurfaces and popups wlr_surface_send_enter(sway_layer->layer_surface->surface, sway_layer->layer_surface->output); + cursor_rebase_all(); } static void handle_unmap(struct wl_listener *listener, void *data) { diff --git a/sway/desktop/output.c b/sway/desktop/output.c index ad75bb35a..c5461ee66 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -506,6 +506,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&output->present.link); wl_list_remove(&output->damage_destroy.link); wl_list_remove(&output->damage_frame.link); + wl_list_remove(&output->swaybg_client_destroy.link); transaction_commit_dirty(); } @@ -612,6 +613,7 @@ void handle_new_output(struct wl_listener *listener, void *data) { output->damage_frame.notify = damage_handle_frame; wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); output->damage_destroy.notify = damage_handle_destroy; + wl_list_init(&output->swaybg_client_destroy.link); struct output_config *oc = output_find_config(output); if (!oc || oc->enabled) { diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index e0c3a5d1e..4098ed22c 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -314,14 +314,7 @@ static void transaction_apply(struct sway_transaction *transaction) { node->instruction = NULL; } - if (root->outputs->length) { - struct sway_seat *seat; - wl_list_for_each(seat, &server.input->seats, link) { - if (!seat_doing_seatop(seat)) { - cursor_rebase(seat->cursor); - } - } - } + cursor_rebase_all(); } static void transaction_commit(struct sway_transaction *transaction); diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 152bd26f0..ce6fe41a1 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -236,19 +236,11 @@ static void _close(struct sway_view *view) { } } -static void close_popups_iterator(struct wlr_surface *surface, - int sx, int sy, void *data) { - struct wlr_xdg_surface *xdg_surface = - wlr_xdg_surface_from_wlr_surface(surface); - if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP - && xdg_surface->popup) { - wlr_xdg_popup_destroy(xdg_surface); - } -} - static void close_popups(struct sway_view *view) { - wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, - close_popups_iterator, NULL); + struct wlr_xdg_popup *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &view->wlr_xdg_surface->popups, link) { + wlr_xdg_popup_destroy(popup->base); + } } static void destroy(struct sway_view *view) { diff --git a/sway/input/cursor.c b/sway/input/cursor.c index c38d8d3a1..170532bea 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -283,6 +283,19 @@ void cursor_rebase(struct sway_cursor *cursor) { cursor_do_rebase(cursor, time_msec, cursor->previous.node, surface, sx, sy); } +void cursor_rebase_all(void) { + if (!root->outputs->length) { + return; + } + + struct sway_seat *seat; + wl_list_for_each(seat, &server.input->seats, link) { + if (!seat_doing_seatop(seat)) { + cursor_rebase(seat->cursor); + } + } +} + static int hide_notify(void *data) { struct sway_cursor *cursor = data; wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); @@ -362,7 +375,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, struct sway_output *focused_output = node_get_output(focus); struct sway_output *output = node_get_output(node); if (output != focused_output) { - seat_set_focus(seat, node); + seat_set_focus(seat, seat_get_focus_inactive(seat, node)); } } else if (node->type == N_CONTAINER && node->sway_container->view) { // Focus node if the following are true: @@ -408,15 +421,16 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) { wlr_relative_pointer_manager_v1_send_relative_motion( server.relative_pointer_manager, - cursor->seat->wlr_seat, event->time_msec, dx, dy, - dx_unaccel, dy_unaccel); + cursor->seat->wlr_seat, (uint64_t)event->time_msec * 1000, + dx, dy, dx_unaccel, dy_unaccel); struct wlr_surface *surface = NULL; + struct sway_node *node = NULL; double sx, sy; - struct sway_node *node = node_at_coords(cursor->seat, - cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - if (cursor->active_constraint) { + node = node_at_coords(cursor->seat, + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + if (cursor->active_constraint->surface != surface) { return; } @@ -432,8 +446,13 @@ static void handle_cursor_motion(struct wl_listener *listener, void *data) { } wlr_cursor_move(cursor->cursor, event->device, dx, dy); + + // Recalculate pointer location after layout checks + node = node_at_coords(cursor->seat, + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); + cursor_send_pointer_motion(cursor, event->time_msec, node, surface, - sx + dx, sy + dy); + sx, sy); transaction_commit_dirty(); } @@ -1459,7 +1478,11 @@ void handle_pointer_constraint(struct wl_listener *listener, void *data) { void sway_cursor_constrain(struct sway_cursor *cursor, struct wlr_pointer_constraint_v1 *constraint) { struct seat_config *config = seat_get_config(cursor->seat); - if (config->allow_constrain == CONSTRAIN_DISABLE) { + if (!config) { + config = seat_get_config_by_name("*"); + } + + if (!config || config->allow_constrain == CONSTRAIN_DISABLE) { return; } diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 8d263e06b..f99fc395b 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -31,10 +31,10 @@ struct sway_seat *input_manager_current_seat(void) { } struct sway_seat *input_manager_get_default_seat(void) { - return input_manager_get_seat(DEFAULT_SEAT); + return input_manager_get_seat(DEFAULT_SEAT, true); } -struct sway_seat *input_manager_get_seat(const char *seat_name) { +struct sway_seat *input_manager_get_seat(const char *seat_name, bool create) { struct sway_seat *seat = NULL; wl_list_for_each(seat, &server.input->seats, link) { if (strcmp(seat->wlr_seat->name, seat_name) == 0) { @@ -42,7 +42,7 @@ struct sway_seat *input_manager_get_seat(const char *seat_name) { } } - return seat_create(seat_name); + return create ? seat_create(seat_name) : NULL; } char *input_device_get_identifier(struct wlr_input_device *device) { @@ -674,7 +674,8 @@ void input_manager_apply_seat_config(struct seat_config *seat_config) { seat_apply_config(seat, sc); } } else { - struct sway_seat *seat = input_manager_get_seat(seat_config->name); + struct sway_seat *seat = + input_manager_get_seat(seat_config->name, true); if (!seat) { return; } diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 12c57366c..00fc6a13f 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -425,7 +425,8 @@ static void determine_bar_visibility(uint32_t modifiers) { for (int i = 0; i < config->bars->length; ++i) { struct bar_config *bar = config->bars->items[i]; if (strcmp(bar->mode, bar->hidden_state) == 0) { // both are "hide" - bool should_be_visible = (~modifiers & bar->modifier) == 0; + bool should_be_visible = + bar->modifier != 0 && (~modifiers & bar->modifier) == 0; if (bar->visible_by_modifier != should_be_visible) { bar->visible_by_modifier = should_be_visible; ipc_event_bar_state_update(bar); @@ -548,13 +549,17 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { wlr_keyboard_led_update(wlr_device->keyboard, leds); } - if (input_config && input_config->repeat_delay != INT_MIN - && input_config->repeat_rate != INT_MIN) { - wlr_keyboard_set_repeat_info(wlr_device->keyboard, - input_config->repeat_rate, input_config->repeat_delay); - } else { - wlr_keyboard_set_repeat_info(wlr_device->keyboard, 25, 600); + int repeat_rate = 25; + if (input_config && input_config->repeat_rate != INT_MIN) { + repeat_rate = input_config->repeat_rate; } + int repeat_delay = 600; + if (input_config && input_config->repeat_delay != INT_MIN) { + repeat_delay = input_config->repeat_delay; + } + wlr_keyboard_set_repeat_info(wlr_device->keyboard, repeat_rate, + repeat_delay); + xkb_context_unref(context); struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat; wlr_seat_set_keyboard(seat, wlr_device); diff --git a/sway/input/seat.c b/sway/input/seat.c index d159da224..df48b7518 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -525,6 +525,7 @@ static void seat_configure_touch(struct sway_seat *seat, static void seat_configure_tablet_tool(struct sway_seat *seat, struct sway_seat_device *sway_device) { + seat_configure_xcursor(seat); wlr_cursor_attach_input_device(seat->cursor->cursor, sway_device->input_device->wlr_device); seat_apply_input_config(seat, sway_device); @@ -724,6 +725,10 @@ void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node) { void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { if (seat->focused_layer) { + struct wlr_layer_surface_v1 *layer = seat->focused_layer; + seat_set_focus_layer(seat, NULL); + seat_set_focus(seat, node); + seat_set_focus_layer(seat, layer); return; } diff --git a/sway/input/seatop_move_tiling.c b/sway/input/seatop_move_tiling.c index 8b541f80d..1e548f5ae 100644 --- a/sway/input/seatop_move_tiling.c +++ b/sway/input/seatop_move_tiling.c @@ -150,6 +150,9 @@ static void handle_motion_postthreshold(struct sway_seat *seat) { } if (edge) { e->target_node = node_get_parent(&con->node); + if (e->target_node == &e->con->node) { + e->target_node = node_get_parent(e->target_node); + } e->target_edge = edge; node_get_box(e->target_node, &e->drop_box); resize_box(&e->drop_box, edge, DROP_LAYOUT_BORDER); @@ -161,7 +164,8 @@ static void handle_motion_postthreshold(struct sway_seat *seat) { // Use the hovered view - but we must be over the actual surface con = node->sway_container; - if (!con->view->surface || node == &e->con->node) { + if (!con->view->surface || node == &e->con->node + || node_has_ancestor(node, &e->con->node)) { e->target_node = NULL; e->target_edge = WLR_EDGE_NONE; return; diff --git a/sway/ipc-json.c b/sway/ipc-json.c index e10989420..23016dbd5 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -597,7 +597,7 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) { const char *layout = xkb_keymap_layout_get_name(keymap, layout_idx); json_object_object_add(object, "xkb_active_layout_name", - json_object_new_string(layout)); + layout ? json_object_new_string(layout) : NULL); break; } } diff --git a/sway/ipc-server.c b/sway/ipc-server.c index d1920cfd4..df57cba51 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -264,7 +264,7 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { static bool ipc_has_event_listeners(enum ipc_command_type event) { for (int i = 0; i < ipc_client_list->length; i++) { struct ipc_client *client = ipc_client_list->items[i]; - if ((client->subscribed_events & event_mask(event)) == 0) { + if ((client->subscribed_events & event_mask(event)) != 0) { return true; } } @@ -595,6 +595,16 @@ void ipc_client_handle_command(struct ipc_client *client) { switch (client->current_command) { case IPC_COMMAND: { + char *line = strtok(buf, "\n"); + while (line) { + size_t line_length = strlen(line); + if (line + line_length >= buf + client->payload_length) { + break; + } + line[line_length] = ';'; + line = strtok(NULL, "\n"); + } + list_t *res_list = execute_command(buf, NULL, NULL); transaction_commit_dirty(); char *json = cmd_results_to_json(res_list); diff --git a/sway/main.c b/sway/main.c index a3198af10..b118a1823 100644 --- a/sway/main.c +++ b/sway/main.c @@ -299,6 +299,14 @@ int main(int argc, char **argv) { } } + // Since wayland requires XDG_RUNTIME_DIR to be set, abort with just the + // clear error message (when not running as an IPC client). + if (!getenv("XDG_RUNTIME_DIR") && optind == argc) { + fprintf(stderr, + "XDG_RUNTIME_DIR is not set in the environment. Aborting.\n"); + exit(EXIT_FAILURE); + } + // As the 'callback' function for wlr_log is equivalent to that for // sway, we do not need to override it. if (debug) { @@ -312,9 +320,21 @@ int main(int argc, char **argv) { wlr_log_init(WLR_ERROR, NULL); } + log_kernel(); + log_distro(); + log_env(); + detect_proprietary(allow_unsupported_gpu); + detect_raspi(); + if (optind < argc) { // Behave as IPC client if (optind != 1) { - sway_log(SWAY_ERROR, "Don't use options with the IPC client"); + sway_log(SWAY_ERROR, + "Detected both options and positional arguments. If you " + "are trying to use the IPC client, options are not " + "supported. Otherwise, check the provided arguments for " + "issues. See `man 1 sway` or `sway -h` for usage. If you " + "are trying to generate a debug log, use " + "`sway -d 2>sway.log`."); exit(EXIT_FAILURE); } if (!drop_permissions()) { @@ -334,11 +354,6 @@ int main(int argc, char **argv) { return 1; } - log_kernel(); - log_distro(); - detect_proprietary(allow_unsupported_gpu); - detect_raspi(); - if (!drop_permissions()) { server_fini(&server); exit(EXIT_FAILURE); @@ -358,14 +373,14 @@ int main(int argc, char **argv) { return 1; } - ipc_init(&server); - log_env(); - if (validate) { bool valid = load_main_config(config_path, false, true); + free(config_path); return valid ? 0 : 1; } + ipc_init(&server); + setenv("WAYLAND_DISPLAY", server.socket, true); if (!load_main_config(config_path, false, false)) { sway_terminate(EXIT_FAILURE); diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index 376e18338..8c3a8225f 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd @@ -8,6 +8,13 @@ sway-input - input configuration file and commands Sway allows for configuration of devices within the sway configuration file. To obtain a list of available device identifiers, run *swaymsg -t get_inputs*. +Settings can also be applied to all input devices by using the wildcard, _\*_, +in place of _\_ in the commands below. + +Tip: If the configuration settings do not appear to be taking effect, you could +try using _\*_ instead of _\_. If it works with the wildcard, try +using a different identifier from *swaymsg -t get_inputs* until you find the +correct input device. # INPUT COMMANDS @@ -144,7 +151,13 @@ configured. While sway is running, _-_ (hyphen) can be used as an alias for the current seat. Each seat has an independent keyboard focus and a separate cursor that is controlled by the pointer devices of the seat. This is useful for multiple people using the desktop at the same time with their own devices (each -sitting in their own "seat"). +sitting in their own "seat"). The wildcard character, _\*_, can also be used in +place of _\_ to change settings for all seats. + +Tip: If the configuration settings do not appear to be taking effect, you could +try using _\*_ instead of _\_. If it works with the wildcard, try +using a different identifier from *swaymsg -t get_seats* until you find the +correct seat. *seat* attach Attach an input device to this seat by its input identifier. A special diff --git a/sway/sway.5.scd b/sway/sway.5.scd index fd0a22dc7..76467d23a 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -293,12 +293,13 @@ runtime. overwrite a binding, swaynag will give you a warning. To silence this, use the _--no-warn_ flag. - Mouse buttons can either be specified in the form _button[1-9]_ or by using - the name of the event code (ex _BTN\_LEFT_ or _BTN\_RIGHT_). For the former - option, the buttons will be mapped to their values in X11 (1=left, 2=middle, - 3=right, 4=scroll up, 5=scroll down, 6=scroll left, 7=scroll right, 8=back, - 9=forward). For the latter option, you can find the event names using - _libinput debug-events_. + Mouse bindings operate on the container under the cursor instead of the + container that has focus. Mouse buttons can either be specified in the form + _button[1-9]_ or by using the name of the event code (ex _BTN\_LEFT_ or + _BTN\_RIGHT_). For the former option, the buttons will be mapped to their + values in X11 (1=left, 2=middle, 3=right, 4=scroll up, 5=scroll down, + 6=scroll left, 7=scroll right, 8=back, 9=forward). For the latter option, + you can find the event names using _libinput debug-events_. _--whole-window_, _--border_, and _--exclude-titlebar_ are mouse-only options which affect the region in which the mouse bindings can be triggered. By @@ -413,10 +414,6 @@ The default colors are: : #0c0c0c -*debuglog* on|off|toggle - Enables, disables or toggles debug logging. _toggle_ cannot be used in the - configuration file. - *default_border* normal|none|pixel [] Set default border style for new tiled windows. diff --git a/sway/tree/container.c b/sway/tree/container.c index 0ebdc51de..9358dad76 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -251,10 +251,12 @@ static struct sway_container *container_at_stacked(struct sway_node *parent, // Title bars int title_height = container_titlebar_height(); - int child_index = (ly - box.y) / title_height; - if (child_index < children->length) { - struct sway_container *child = children->items[child_index]; - return child; + if (title_height > 0) { + int child_index = (ly - box.y) / title_height; + if (child_index < children->length) { + struct sway_container *child = children->items[child_index]; + return child; + } } // Surfaces diff --git a/sway/tree/output.c b/sway/tree/output.c index 5a992f2db..60e0af9f4 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -8,7 +8,6 @@ #include "sway/layers.h" #include "sway/output.h" #include "sway/tree/arrange.h" -#include "sway/tree/output.h" #include "sway/tree/workspace.h" #include "log.h" #include "util.h" @@ -234,9 +233,8 @@ void output_disable(struct sway_output *output) { root_for_each_container(untrack_output, output); - if (output->bg_pid) { - terminate_swaybg(output->bg_pid); - output->bg_pid = 0; + if (output->swaybg_client != NULL) { + wl_client_destroy(output->swaybg_client); } int index = list_find(root->outputs, output); diff --git a/sway/tree/view.c b/sway/tree/view.c index 612cf96ae..ca13def72 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -664,6 +664,13 @@ void view_unmap(struct sway_view *view) { struct sway_seat *seat; wl_list_for_each(seat, &server.input->seats, link) { seat->cursor->image_surface = NULL; + if (seat->cursor->active_constraint) { + struct wlr_surface *constrain_surface = + seat->cursor->active_constraint->surface; + if (view_from_wlr_surface(constrain_surface) == view) { + sway_cursor_constrain(seat->cursor, NULL); + } + } seat_consider_warp_to_focus(seat); } @@ -701,6 +708,9 @@ static void subsurface_get_root_coords(struct sway_view_child *child, while (surface && wlr_surface_is_subsurface(surface)) { struct wlr_subsurface *subsurface = wlr_subsurface_from_wlr_surface(surface); + if (subsurface == NULL) { + break; + } *root_sx += subsurface->current.x; *root_sy += subsurface->current.y; surface = subsurface->parent; diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 8b3eb2ad2..9b7c5112d 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -42,10 +42,16 @@ struct sway_output *workspace_get_initial_output(const char *name) { } } } - // Otherwise put it on the focused output + // Otherwise try to put it on the focused output struct sway_seat *seat = input_manager_current_seat(); - struct sway_workspace *focus = seat_get_focused_workspace(seat); - return focus->output; + struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); + if (focus && focus->type == N_WORKSPACE) { + return focus->sway_workspace->output; + } else if (focus && focus->type == N_CONTAINER) { + return focus->sway_container->workspace->output; + } + // Fallback to the first output or noop output for headless + return root->outputs->length ? root->outputs->items[0] : root->noop_output; } static void prevent_invalid_outer_gaps(struct sway_workspace *ws) { @@ -328,16 +334,13 @@ char *workspace_next_name(const char *output_name) { if (target != NULL) { return target; } - // As a fall back, get the current number of active workspaces - // and return that + 1 for the next workspace's name - int ws_num = root->outputs->length; - int l = snprintf(NULL, 0, "%d", ws_num); - char *name = malloc(l + 1); - if (!sway_assert(name, "Could not allocate workspace name")) { - return NULL; - } - sprintf(name, "%d", ws_num++); - return name; + // As a fall back, use the next available number + char name[12] = ""; + unsigned int ws_num = 1; + do { + snprintf(name, sizeof(name), "%u", ws_num++); + } while (workspace_by_number(name)); + return strdup(name); } static bool _workspace_by_number(struct sway_workspace *ws, void *data) { @@ -445,9 +448,15 @@ struct sway_workspace *workspace_prev(struct sway_workspace *current) { bool workspace_switch(struct sway_workspace *workspace, bool no_auto_back_and_forth) { struct sway_seat *seat = input_manager_current_seat(); - struct sway_workspace *active_ws = seat_get_focused_workspace(seat); + struct sway_workspace *active_ws = NULL; + struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); + if (focus && focus->type == N_WORKSPACE) { + active_ws = focus->sway_workspace; + } else if (focus && focus->type == N_CONTAINER) { + active_ws = focus->sway_container->workspace; + } - if (!no_auto_back_and_forth && config->auto_back_and_forth + if (!no_auto_back_and_forth && config->auto_back_and_forth && active_ws && active_ws == workspace && seat->prev_workspace_name) { struct sway_workspace *new_ws = workspace_by_name(seat->prev_workspace_name); @@ -456,9 +465,9 @@ bool workspace_switch(struct sway_workspace *workspace, workspace_create(NULL, seat->prev_workspace_name); } - if (!seat->prev_workspace_name || + if (active_ws && (!seat->prev_workspace_name || (strcmp(seat->prev_workspace_name, active_ws->name) - && active_ws != workspace)) { + && active_ws != workspace))) { free(seat->prev_workspace_name); seat->prev_workspace_name = malloc(strlen(active_ws->name) + 1); if (!seat->prev_workspace_name) { diff --git a/swaybar/bar.c b/swaybar/bar.c index a1f7bfdb9..db1c12228 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -403,8 +404,7 @@ bool bar_setup(struct swaybar *bar, const char *socket_path) { static void display_in(int fd, short mask, void *data) { struct swaybar *bar = data; if (wl_display_dispatch(bar->display) == -1) { - bar_teardown(bar); - exit(0); + bar->running = false; } } @@ -439,7 +439,7 @@ void bar_run(struct swaybar *bar) { loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar->tray->bus); } #endif - while (1) { + while (bar->running) { errno = 0; if (wl_display_flush(bar->display) == -1 && errno != EAGAIN) { break; diff --git a/swaybar/main.c b/swaybar/main.c index 4ef746290..108b16e91 100644 --- a/swaybar/main.c +++ b/swaybar/main.c @@ -11,13 +11,7 @@ static struct swaybar swaybar; void sig_handler(int signal) { - bar_teardown(&swaybar); - exit(0); -} - -void sway_terminate(int code) { - bar_teardown(&swaybar); - exit(code); + swaybar.running = false; } int main(int argc, char **argv) { @@ -93,8 +87,6 @@ int main(int argc, char **argv) { } } - signal(SIGTERM, sig_handler); - if (!bar_setup(&swaybar, socket_path)) { free(socket_path); return 1; @@ -102,6 +94,10 @@ int main(int argc, char **argv) { free(socket_path); + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + + swaybar.running = true; bar_run(&swaybar); bar_teardown(&swaybar); return 0; diff --git a/swaybar/tray/host.c b/swaybar/tray/host.c index 215e1e722..451b08967 100644 --- a/swaybar/tray/host.c +++ b/swaybar/tray/host.c @@ -189,9 +189,9 @@ bool init_host(struct swaybar_host *host, char *protocol, goto error; } - sd_bus_slot_set_floating(reg_slot, 1); - sd_bus_slot_set_floating(unreg_slot, 1); - sd_bus_slot_set_floating(watcher_slot, 1); + sd_bus_slot_set_floating(reg_slot, 0); + sd_bus_slot_set_floating(unreg_slot, 0); + sd_bus_slot_set_floating(watcher_slot, 0); sway_log(SWAY_DEBUG, "Registered %s", host->service); return true; diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 4262d6877..4fa6c97b5 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -299,6 +299,8 @@ void destroy_sni(struct swaybar_sni *sni) { return; } + cairo_surface_destroy(sni->icon); + sd_bus_slot_unref(sni->new_icon_slot); sd_bus_slot_unref(sni->new_attention_icon_slot); sd_bus_slot_unref(sni->new_status_slot); @@ -308,9 +310,11 @@ void destroy_sni(struct swaybar_sni *sni) { free(sni->path); free(sni->status); free(sni->icon_name); - free(sni->icon_pixmap); + list_free_items_and_destroy(sni->icon_pixmap); free(sni->attention_icon_name); + list_free_items_and_destroy(sni->attention_icon_pixmap); free(sni->menu); + free(sni->icon_theme_path); free(sni); } diff --git a/swaybar/tray/watcher.c b/swaybar/tray/watcher.c index 381510717..951a05890 100644 --- a/swaybar/tray/watcher.c +++ b/swaybar/tray/watcher.c @@ -18,10 +18,6 @@ static int cmp_id(const void *item, const void *cmp_to) { return strcmp(item, cmp_to); } -static int cmp_service(const void *item, const void *cmp_to) { - return strncmp(item, cmp_to, strlen(cmp_to)); -} - static int handle_lost_service(sd_bus_message *msg, void *data, sd_bus_error *error) { char *service, *old_owner, *new_owner; @@ -33,18 +29,23 @@ static int handle_lost_service(sd_bus_message *msg, if (!*new_owner) { struct swaybar_watcher *watcher = data; - int idx = list_seq_find(watcher->items, - using_standard_protocol(watcher) ? cmp_id : cmp_service, service); - if (idx != -1) { + for (int idx = 0; idx < watcher->items->length; ++idx) { char *id = watcher->items->items[idx]; - sway_log(SWAY_DEBUG, "Unregistering Status Notifier Item '%s'", id); - list_del(watcher->items, idx); - sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface, - "StatusNotifierItemUnregistered", "s", id); - free(id); + int cmp_res = using_standard_protocol(watcher) ? + cmp_id(id, service) : strncmp(id, service, strlen(service)); + if (cmp_res == 0) { + sway_log(SWAY_DEBUG, "Unregistering Status Notifier Item '%s'", id); + list_del(watcher->items, idx--); + sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface, + "StatusNotifierItemUnregistered", "s", id); + free(id); + if (using_standard_protocol(watcher)) { + break; + } + } } - idx = list_seq_find(watcher->hosts, cmp_id, service); + int idx = list_seq_find(watcher->hosts, cmp_id, service); if (idx != -1) { sway_log(SWAY_DEBUG, "Unregistering Status Notifier Host '%s'", service); free(watcher->hosts->items[idx]); @@ -185,8 +186,8 @@ struct swaybar_watcher *create_watcher(char *protocol, sd_bus *bus) { goto error; } - sd_bus_slot_set_floating(signal_slot, 1); - sd_bus_slot_set_floating(vtable_slot, 1); + sd_bus_slot_set_floating(signal_slot, 0); + sd_bus_slot_set_floating(vtable_slot, 0); watcher->bus = bus; watcher->hosts = create_list(); diff --git a/swaymsg/main.c b/swaymsg/main.c index c84f5671f..716d2d2ed 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -135,8 +135,8 @@ static void pretty_print_input(json_object *i) { json_object_get_int(vendor)); if (json_object_object_get_ex(i, "xkb_active_layout_name", &kbdlayout)) { - printf(" Active Keyboard Layout: %s\n", - json_object_get_string(kbdlayout)); + const char *layout = json_object_get_string(kbdlayout); + printf(" Active Keyboard Layout: %s\n", layout ? layout : "(unnamed)"); } if (json_object_object_get_ex(i, "libinput_send_events", &events)) { diff --git a/swaynag/config.c b/swaynag/config.c index 40f3f65e8..200611f4b 100644 --- a/swaynag/config.c +++ b/swaynag/config.c @@ -348,6 +348,10 @@ int swaynag_load_config(char *path, struct swaynag *swaynag, list_t *types) { continue; } + if (line[nread - 1] == '\n') { + line[nread - 1] = '\0'; + } + if (line[0] == '[') { char *close = strchr(line, ']'); if (!close) {