diff options
author | Ryan Dwyer <RyanDwyer@users.noreply.github.com> | 2018-07-18 09:32:03 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-07-18 09:32:03 +1000 |
commit | 8ce7e3b44eea0a270ecc35a9da2ae801aaf6bce1 (patch) | |
tree | 6badffb0c6ee33b4e23e914c4c9f9b39a625b5f3 /sway | |
parent | 621d2666b1ac214c63628bbe0ac8f5d6485cb501 (diff) | |
parent | 48b911a4596f50b585a1073d32413236d9defb60 (diff) |
Merge branch 'master' into destroy-output-destroy-empty-workspaces
Diffstat (limited to 'sway')
88 files changed, 1821 insertions, 669 deletions
diff --git a/sway/commands.c b/sway/commands.c index ef477f38..a3e6a500 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -98,8 +98,11 @@ static struct cmd_handler handlers[] = { { "client.unfocused", cmd_client_unfocused }, { "client.urgent", cmd_client_urgent }, { "default_border", cmd_default_border }, + { "default_floating_border", cmd_default_floating_border }, { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, + { "floating_maximum_size", cmd_floating_maximum_size }, + { "floating_minimum_size", cmd_floating_minimum_size }, { "focus_follows_mouse", cmd_focus_follows_mouse }, { "focus_wrapping", cmd_focus_wrapping }, { "font", cmd_font }, @@ -112,6 +115,7 @@ static struct cmd_handler handlers[] = { { "input", cmd_input }, { "mode", cmd_mode }, { "mouse_warping", cmd_mouse_warping }, + { "no_focus", cmd_no_focus }, { "output", cmd_output }, { "seat", cmd_seat }, { "set", cmd_set }, @@ -151,6 +155,7 @@ static struct cmd_handler command_handlers[] = { { "swap", cmd_swap }, { "title_format", cmd_title_format }, { "unmark", cmd_unmark }, + { "urgent", cmd_urgent }, }; static int handler_compare(const void *_a, const void *_b) { @@ -163,7 +168,7 @@ struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers, int handlers_size) { struct cmd_handler d = { .command=line }; struct cmd_handler *res = NULL; - wlr_log(L_DEBUG, "find_handler(%s)", line); + wlr_log(WLR_DEBUG, "find_handler(%s)", line); bool config_loading = config->reading || !config->active; @@ -248,10 +253,10 @@ struct cmd_results *execute_command(char *_exec, struct sway_seat *seat) { cmd = argsep(&cmdlist, ","); cmd += strspn(cmd, whitespace); if (strcmp(cmd, "") == 0) { - wlr_log(L_INFO, "Ignoring empty command."); + wlr_log(WLR_INFO, "Ignoring empty command."); continue; } - wlr_log(L_INFO, "Handling command '%s'", cmd); + wlr_log(WLR_INFO, "Handling command '%s'", cmd); //TODO better handling of argv int argc; char **argv = split_args(cmd, &argc); @@ -344,7 +349,7 @@ struct cmd_results *config_command(char *exec) { // Start block if (argc > 1 && strcmp(argv[argc - 1], "{") == 0) { - char *block = join_args(argv, argc - 1); + char *block = join_args(argv, argc - 1); results = cmd_results_new(CMD_BLOCK, block, NULL); free(block); goto cleanup; @@ -355,7 +360,7 @@ struct cmd_results *config_command(char *exec) { results = cmd_results_new(CMD_BLOCK_END, NULL, NULL); goto cleanup; } - wlr_log(L_INFO, "handling config command '%s'", exec); + wlr_log(WLR_INFO, "handling config command '%s'", exec); struct cmd_handler *handler = find_handler(argv[0], NULL, 0); if (!handler) { char *input = argv[0] ? argv[0] : "(empty)"; @@ -388,7 +393,7 @@ cleanup: struct cmd_results *config_subcommand(char **argv, int argc, struct cmd_handler *handlers, size_t handlers_size) { char *command = join_args(argv, argc); - wlr_log(L_DEBUG, "Subcommand: %s", command); + wlr_log(WLR_DEBUG, "Subcommand: %s", command); free(command); struct cmd_handler *handler = find_handler(argv[0], handlers, @@ -479,7 +484,7 @@ struct cmd_results *config_commands_command(char *exec) { } policy->context = context; - wlr_log(L_INFO, "Set command policy for %s to %d", + wlr_log(WLR_INFO, "Set command policy for %s to %d", policy->command, policy->context); results = cmd_results_new(CMD_SUCCESS, NULL, NULL); @@ -493,7 +498,7 @@ struct cmd_results *cmd_results_new(enum cmd_status status, const char *input, const char *format, ...) { struct cmd_results *results = malloc(sizeof(struct cmd_results)); if (!results) { - wlr_log(L_ERROR, "Unable to allocate command results"); + wlr_log(WLR_ERROR, "Unable to allocate command results"); return NULL; } results->status = status; diff --git a/sway/commands/assign.c b/sway/commands/assign.c index a90498ce..0bc0929a 100644 --- a/sway/commands/assign.c +++ b/sway/commands/assign.c @@ -45,7 +45,7 @@ struct cmd_results *cmd_assign(int argc, char **argv) { criteria->target = join_args(argv, target_len); list_add(config->criteria, criteria); - wlr_log(L_DEBUG, "assign: '%s' -> '%s' added", criteria->raw, + wlr_log(WLR_DEBUG, "assign: '%s' -> '%s' added", criteria->raw, criteria->target); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/bar.c b/sway/commands/bar.c index d84ce808..f6a70c17 100644 --- a/sway/commands/bar.c +++ b/sway/commands/bar.c @@ -63,13 +63,13 @@ struct cmd_results *cmd_bar(int argc, char **argv) { for (int i = 0; i < config->bars->length; ++i) { struct bar_config *item = config->bars->items[i]; if (strcmp(item->id, argv[0]) == 0) { - wlr_log(L_DEBUG, "Selecting bar: %s", argv[0]); + wlr_log(WLR_DEBUG, "Selecting bar: %s", argv[0]); bar = item; break; } } if (!bar) { - wlr_log(L_DEBUG, "Creating bar: %s", argv[0]); + wlr_log(WLR_DEBUG, "Creating bar: %s", argv[0]); bar = default_bar_config(); if (!bar) { return cmd_results_new(CMD_FAILURE, "bar", @@ -108,7 +108,7 @@ struct cmd_results *cmd_bar(int argc, char **argv) { // Set current bar config->current_bar = bar; - wlr_log(L_DEBUG, "Creating bar %s", bar->id); + wlr_log(WLR_DEBUG, "Creating bar %s", bar->id); } return config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers)); diff --git a/sway/commands/bar/binding_mode_indicator.c b/sway/commands/bar/binding_mode_indicator.c index 3ba5f33f..0c48bee9 100644 --- a/sway/commands/bar/binding_mode_indicator.c +++ b/sway/commands/bar/binding_mode_indicator.c @@ -15,11 +15,11 @@ struct cmd_results *bar_cmd_binding_mode_indicator(int argc, char **argv) { } if (strcasecmp("yes", argv[0]) == 0) { config->current_bar->binding_mode_indicator = true; - wlr_log(L_DEBUG, "Enabling binding mode indicator on bar: %s", + wlr_log(WLR_DEBUG, "Enabling binding mode indicator on bar: %s", config->current_bar->id); } else if (strcasecmp("no", argv[0]) == 0) { config->current_bar->binding_mode_indicator = false; - wlr_log(L_DEBUG, "Disabling binding mode indicator on bar: %s", + wlr_log(WLR_DEBUG, "Disabling binding mode indicator on bar: %s", config->current_bar->id); } return cmd_results_new(CMD_INVALID, "binding_mode_indicator", diff --git a/sway/commands/bar/font.c b/sway/commands/bar/font.c index f036cbc3..2aa4e895 100644 --- a/sway/commands/bar/font.c +++ b/sway/commands/bar/font.c @@ -15,7 +15,7 @@ struct cmd_results *bar_cmd_font(int argc, char **argv) { char *font = join_args(argv, argc); free(config->current_bar->font); config->current_bar->font = font; - wlr_log(L_DEBUG, "Settings font '%s' for bar: %s", + wlr_log(WLR_DEBUG, "Settings font '%s' for bar: %s", config->current_bar->font, config->current_bar->id); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/bar/height.c b/sway/commands/bar/height.c index 3160caed..18258526 100644 --- a/sway/commands/bar/height.c +++ b/sway/commands/bar/height.c @@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_height(int argc, char **argv) { "Invalid height value: %s", argv[0]); } config->current_bar->height = height; - wlr_log(L_DEBUG, "Setting bar height to %d on bar: %s", + wlr_log(WLR_DEBUG, "Setting bar height to %d on bar: %s", height, config->current_bar->id); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c index 6641f184..502ce2c4 100644 --- a/sway/commands/bar/hidden_state.c +++ b/sway/commands/bar/hidden_state.c @@ -27,7 +27,7 @@ static struct cmd_results *bar_set_hidden_state(struct bar_config *bar, if (!config->reading) { ipc_event_barconfig_update(bar); } - wlr_log(L_DEBUG, "Setting hidden_state: '%s' for bar: %s", + wlr_log(WLR_DEBUG, "Setting hidden_state: '%s' for bar: %s", bar->hidden_state, bar->id); } // free old mode diff --git a/sway/commands/bar/id.c b/sway/commands/bar/id.c index 6ce86fef..65fa69fd 100644 --- a/sway/commands/bar/id.c +++ b/sway/commands/bar/id.c @@ -24,7 +24,7 @@ struct cmd_results *bar_cmd_id(int argc, char **argv) { } } - wlr_log(L_DEBUG, "Renaming bar: '%s' to '%s'", oldname, name); + wlr_log(WLR_DEBUG, "Renaming bar: '%s' to '%s'", oldname, name); // free old bar id free(config->current_bar->id); diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c index 34bb0a4f..28e2d77b 100644 --- a/sway/commands/bar/mode.c +++ b/sway/commands/bar/mode.c @@ -28,7 +28,7 @@ static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode if (!config->reading) { ipc_event_barconfig_update(bar); } - wlr_log(L_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id); + wlr_log(WLR_DEBUG, "Setting mode: '%s' for bar: %s", bar->mode, bar->id); } // free old mode diff --git a/sway/commands/bar/modifier.c b/sway/commands/bar/modifier.c index 02f845e6..09025fff 100644 --- a/sway/commands/bar/modifier.c +++ b/sway/commands/bar/modifier.c @@ -30,7 +30,7 @@ struct cmd_results *bar_cmd_modifier(int argc, char **argv) { } free_flat_list(split); config->current_bar->modifier = mod; - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "Show/Hide the bar when pressing '%s' in hide mode.", argv[0]); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/bar/output.c b/sway/commands/bar/output.c index f7ca0aa4..72754e05 100644 --- a/sway/commands/bar/output.c +++ b/sway/commands/bar/output.c @@ -42,7 +42,7 @@ struct cmd_results *bar_cmd_output(int argc, char **argv) { if (add_output) { list_add(outputs, strdup(output)); - wlr_log(L_DEBUG, "Adding bar: '%s' to output '%s'", + wlr_log(WLR_DEBUG, "Adding bar: '%s' to output '%s'", config->current_bar->id, output); } return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/bar/pango_markup.c b/sway/commands/bar/pango_markup.c index 480af724..857571fb 100644 --- a/sway/commands/bar/pango_markup.c +++ b/sway/commands/bar/pango_markup.c @@ -13,11 +13,11 @@ struct cmd_results *bar_cmd_pango_markup(int argc, char **argv) { } if (strcasecmp("enabled", argv[0]) == 0) { config->current_bar->pango_markup = true; - wlr_log(L_DEBUG, "Enabling pango markup for bar: %s", + wlr_log(WLR_DEBUG, "Enabling pango markup for bar: %s", config->current_bar->id); } else if (strcasecmp("disabled", argv[0]) == 0) { config->current_bar->pango_markup = false; - wlr_log(L_DEBUG, "Disabling pango markup for bar: %s", + wlr_log(WLR_DEBUG, "Disabling pango markup for bar: %s", config->current_bar->id); } else { error = cmd_results_new(CMD_INVALID, "pango_markup", diff --git a/sway/commands/bar/position.c b/sway/commands/bar/position.c index 9c580483..44bb4ae3 100644 --- a/sway/commands/bar/position.c +++ b/sway/commands/bar/position.c @@ -15,8 +15,9 @@ struct cmd_results *bar_cmd_position(int argc, char **argv) { char *valid[] = { "top", "bottom", "left", "right" }; for (size_t i = 0; i < sizeof(valid) / sizeof(valid[0]); ++i) { if (strcasecmp(valid[i], argv[0]) == 0) { - wlr_log(L_DEBUG, "Setting bar position '%s' for bar: %s", + wlr_log(WLR_DEBUG, "Setting bar position '%s' for bar: %s", argv[0], config->current_bar->id); + free(config->current_bar->position); config->current_bar->position = strdup(argv[0]); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/bar/separator_symbol.c b/sway/commands/bar/separator_symbol.c index 1e08df6d..392ab730 100644 --- a/sway/commands/bar/separator_symbol.c +++ b/sway/commands/bar/separator_symbol.c @@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_separator_symbol(int argc, char **argv) { } free(config->current_bar->separator_symbol); config->current_bar->separator_symbol = strdup(argv[0]); - wlr_log(L_DEBUG, "Settings separator_symbol '%s' for bar: %s", + wlr_log(WLR_DEBUG, "Settings separator_symbol '%s' for bar: %s", config->current_bar->separator_symbol, config->current_bar->id); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/bar/status_command.c b/sway/commands/bar/status_command.c index 5e199cde..6f6f81a3 100644 --- a/sway/commands/bar/status_command.c +++ b/sway/commands/bar/status_command.c @@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_status_command(int argc, char **argv) { } free(config->current_bar->status_command); config->current_bar->status_command = join_args(argv, argc); - wlr_log(L_DEBUG, "Feeding bar with status command: %s", + wlr_log(WLR_DEBUG, "Feeding bar with status command: %s", config->current_bar->status_command); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/bar/strip_workspace_numbers.c b/sway/commands/bar/strip_workspace_numbers.c index 4f24a356..4e47d047 100644 --- a/sway/commands/bar/strip_workspace_numbers.c +++ b/sway/commands/bar/strip_workspace_numbers.c @@ -15,11 +15,11 @@ struct cmd_results *bar_cmd_strip_workspace_numbers(int argc, char **argv) { } if (strcasecmp("yes", argv[0]) == 0) { config->current_bar->strip_workspace_numbers = true; - wlr_log(L_DEBUG, "Stripping workspace numbers on bar: %s", + wlr_log(WLR_DEBUG, "Stripping workspace numbers on bar: %s", config->current_bar->id); } else if (strcasecmp("no", argv[0]) == 0) { config->current_bar->strip_workspace_numbers = false; - wlr_log(L_DEBUG, "Enabling workspace numbers on bar: %s", + wlr_log(WLR_DEBUG, "Enabling workspace numbers on bar: %s", config->current_bar->id); } else { return cmd_results_new(CMD_INVALID, diff --git a/sway/commands/bar/swaybar_command.c b/sway/commands/bar/swaybar_command.c index 520cdd11..04e78e77 100644 --- a/sway/commands/bar/swaybar_command.c +++ b/sway/commands/bar/swaybar_command.c @@ -14,7 +14,7 @@ struct cmd_results *bar_cmd_swaybar_command(int argc, char **argv) { } free(config->current_bar->swaybar_command); config->current_bar->swaybar_command = join_args(argv, argc); - wlr_log(L_DEBUG, "Using custom swaybar command: %s", + wlr_log(WLR_DEBUG, "Using custom swaybar command: %s", config->current_bar->swaybar_command); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/bar/workspace_buttons.c b/sway/commands/bar/workspace_buttons.c index 6edc3a0d..a4079b2a 100644 --- a/sway/commands/bar/workspace_buttons.c +++ b/sway/commands/bar/workspace_buttons.c @@ -14,11 +14,11 @@ struct cmd_results *bar_cmd_workspace_buttons(int argc, char **argv) { } if (strcasecmp("yes", argv[0]) == 0) { config->current_bar->workspace_buttons = true; - wlr_log(L_DEBUG, "Enabling workspace buttons on bar: %s", + wlr_log(WLR_DEBUG, "Enabling workspace buttons on bar: %s", config->current_bar->id); } else if (strcasecmp("no", argv[0]) == 0) { config->current_bar->workspace_buttons = false; - wlr_log(L_DEBUG, "Disabling workspace buttons on bar: %s", + wlr_log(WLR_DEBUG, "Disabling workspace buttons on bar: %s", config->current_bar->id); } else { return cmd_results_new(CMD_INVALID, "workspace_buttons", diff --git a/sway/commands/bar/wrap_scroll.c b/sway/commands/bar/wrap_scroll.c index 7386f82c..701de00a 100644 --- a/sway/commands/bar/wrap_scroll.c +++ b/sway/commands/bar/wrap_scroll.c @@ -13,11 +13,11 @@ struct cmd_results *bar_cmd_wrap_scroll(int argc, char **argv) { } if (strcasecmp("yes", argv[0]) == 0) { config->current_bar->wrap_scroll = true; - wlr_log(L_DEBUG, "Enabling wrap scroll on bar: %s", + wlr_log(WLR_DEBUG, "Enabling wrap scroll on bar: %s", config->current_bar->id); } else if (strcasecmp("no", argv[0]) == 0) { config->current_bar->wrap_scroll = false; - wlr_log(L_DEBUG, "Disabling wrap scroll on bar: %s", + wlr_log(WLR_DEBUG, "Disabling wrap scroll on bar: %s", config->current_bar->id); } else { return cmd_results_new(CMD_INVALID, diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 821f9cd1..83e9e432 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -184,7 +184,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, for (int i = 0; i < mode_bindings->length; ++i) { struct sway_binding *config_binding = mode_bindings->items[i]; if (binding_key_compare(binding, config_binding)) { - wlr_log(L_DEBUG, "overwriting old binding with command '%s'", + wlr_log(WLR_DEBUG, "overwriting old binding with command '%s'", config_binding->command); free_sway_binding(config_binding); mode_bindings->items[i] = binding; @@ -196,7 +196,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, list_add(mode_bindings, binding); } - wlr_log(L_DEBUG, "%s - Bound %s to command %s", + wlr_log(WLR_DEBUG, "%s - Bound %s to command %s", bindtype, argv[0], binding->command); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/border.c b/sway/commands/border.c index 6db85395..9c19e20a 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c @@ -42,7 +42,7 @@ struct cmd_results *cmd_border(int argc, char **argv) { container_set_geometry_from_floating_view(view->swayc); } - arrange_and_commit(view->swayc); + arrange_windows(view->swayc); struct sway_seat *seat = input_manager_current_seat(input_manager); if (seat->cursor) { diff --git a/sway/commands/default_floating_border.c b/sway/commands/default_floating_border.c new file mode 100644 index 00000000..1bfc24af --- /dev/null +++ b/sway/commands/default_floating_border.c @@ -0,0 +1,29 @@ +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/tree/container.h" + +struct cmd_results *cmd_default_floating_border(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "default_floating_border", + EXPECTED_AT_LEAST, 1))) { + return error; + } + + if (strcmp(argv[0], "none") == 0) { + config->floating_border = B_NONE; + } else if (strcmp(argv[0], "normal") == 0) { + config->floating_border = B_NORMAL; + } else if (strcmp(argv[0], "pixel") == 0) { + config->floating_border = B_PIXEL; + } else { + return cmd_results_new(CMD_INVALID, "default_floating_border", + "Expected 'default_floating_border <none|normal|pixel>' " + "or 'default_floating_border <normal|pixel> <px>'"); + } + if (argc == 2) { + config->floating_border_thickness = atoi(argv[1]); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/exec.c b/sway/commands/exec.c index 363d5bef..7fc54123 100644 --- a/sway/commands/exec.c +++ b/sway/commands/exec.c @@ -8,7 +8,7 @@ struct cmd_results *cmd_exec(int argc, char **argv) { if (!config->active) return cmd_results_new(CMD_DEFER, "exec", NULL); if (config->reloading) { char *args = join_args(argv, argc); - wlr_log(L_DEBUG, "Ignoring 'exec %s' due to reload", args); + wlr_log(WLR_DEBUG, "Ignoring 'exec %s' due to reload", args); free(args); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index 1c99de97..c7727857 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -20,7 +20,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) { char *tmp = NULL; if (strcmp((char*)*argv, "--no-startup-id") == 0) { - wlr_log(L_INFO, "exec switch '--no-startup-id' not supported, ignored."); + wlr_log(WLR_INFO, "exec switch '--no-startup-id' not supported, ignored."); if ((error = checkarg(argc - 1, "exec_always", EXPECTED_MORE_THAN, 0))) { return error; } @@ -35,11 +35,11 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) { strncpy(cmd, tmp, sizeof(cmd) - 1); cmd[sizeof(cmd) - 1] = 0; free(tmp); - wlr_log(L_DEBUG, "Executing %s", cmd); + wlr_log(WLR_DEBUG, "Executing %s", cmd); int fd[2]; if (pipe(fd) != 0) { - wlr_log(L_ERROR, "Unable to create pipe for fork"); + wlr_log(WLR_ERROR, "Unable to create pipe for fork"); } pid_t pid, child; @@ -73,7 +73,7 @@ struct cmd_results *cmd_exec_always(int argc, char **argv) { // cleanup child process waitpid(pid, NULL, 0); if (child > 0) { - wlr_log(L_DEBUG, "Child process created with pid %d", child); + wlr_log(WLR_DEBUG, "Child process created with pid %d", child); // TODO: add PID to active workspace } else { return cmd_results_new(CMD_FAILURE, "exec_always", diff --git a/sway/commands/floating.c b/sway/commands/floating.c index e6003521..6ab56c3b 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c @@ -37,7 +37,7 @@ struct cmd_results *cmd_floating(int argc, char **argv) { container_set_floating(container, wants_floating); struct sway_container *workspace = container_parent(container, C_WORKSPACE); - arrange_and_commit(workspace); + arrange_windows(workspace); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/floating_minmax_size.c b/sway/commands/floating_minmax_size.c new file mode 100644 index 00000000..0af78908 --- /dev/null +++ b/sway/commands/floating_minmax_size.c @@ -0,0 +1,53 @@ +#include <errno.h> +#include <math.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <wlr/util/log.h> +#include "sway/commands.h" +#include "log.h" + +static const char* min_usage = + "Expected 'floating_minimum_size <width> x <height>'"; + +static const char* max_usage = + "Expected 'floating_maximum_size <width> x <height>'"; + +static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name, + const char *usage, int *config_width, int *config_height) { + struct cmd_results *error; + if ((error = checkarg(argc, cmd_name, EXPECTED_EQUAL_TO, 3))) { + return error; + } + + char *err; + int width = (int)strtol(argv[0], &err, 10); + if (*err) { + return cmd_results_new(CMD_INVALID, cmd_name, usage); + } + + if (strcmp(argv[1], "x") != 0) { + return cmd_results_new(CMD_INVALID, cmd_name, usage); + } + + int height = (int)strtol(argv[2], &err, 10); + if (*err) { + return cmd_results_new(CMD_INVALID, cmd_name, usage); + } + + *config_width = width; + *config_height = height; + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +struct cmd_results *cmd_floating_minimum_size(int argc, char **argv) { + return handle_command(argc, argv, "floating_minimum_size", min_usage, + &config->floating_minimum_width, &config->floating_minimum_height); +} + +struct cmd_results *cmd_floating_maximum_size(int argc, char **argv) { + return handle_command(argc, argv, "floating_maximum_size", max_usage, + &config->floating_maximum_width, &config->floating_maximum_height); +} diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 74d9d535..b24d5007 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c @@ -1,10 +1,12 @@ #include <strings.h> #include <wlr/util/log.h> #include "log.h" +#include "sway/commands.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" +#include "sway/tree/arrange.h" #include "sway/tree/view.h" -#include "sway/commands.h" +#include "sway/tree/workspace.h" static bool parse_movement_direction(const char *name, enum movement_direction *out) { @@ -27,6 +29,21 @@ static bool parse_movement_direction(const char *name, return true; } +static struct cmd_results *focus_mode(struct sway_container *con, + struct sway_seat *seat, bool floating) { + struct sway_container *ws = con->type == C_WORKSPACE ? + con : container_parent(con, C_WORKSPACE); + struct sway_container *new_focus = ws; + if (floating) { + new_focus = ws->sway_workspace->floating; + if (new_focus->children->length == 0) { + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + } + seat_set_focus(seat, seat_get_active_child(seat, new_focus)); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + struct cmd_results *cmd_focus(int argc, char **argv) { struct sway_container *con = config->handler_context.current_container; struct sway_seat *seat = config->handler_context.seat; @@ -40,11 +57,20 @@ struct cmd_results *cmd_focus(int argc, char **argv) { return cmd_results_new(CMD_SUCCESS, NULL, NULL); } - // TODO mode_toggle + if (strcmp(argv[0], "floating") == 0) { + return focus_mode(con, seat, true); + } else if (strcmp(argv[0], "tiling") == 0) { + return focus_mode(con, seat, false); + } else if (strcmp(argv[0], "mode_toggle") == 0) { + return focus_mode(con, seat, !container_is_floating(con)); + } + + // TODO: focus output <direction|name> enum movement_direction direction = 0; if (!parse_movement_direction(argv[0], &direction)) { return cmd_results_new(CMD_INVALID, "focus", - "Expected 'focus <direction|parent|child|mode_toggle>' or 'focus output <direction|name>'"); + "Expected 'focus <direction|parent|child|mode_toggle|floating|tiling>' " + "or 'focus output <direction|name>'"); } struct sway_container *next_focus = container_get_in_direction( diff --git a/sway/commands/for_window.c b/sway/commands/for_window.c index 8c425a1d..ac4d6563 100644 --- a/sway/commands/for_window.c +++ b/sway/commands/for_window.c @@ -24,7 +24,7 @@ struct cmd_results *cmd_for_window(int argc, char **argv) { criteria->cmdlist = join_args(argv + 1, argc - 1); list_add(config->criteria, criteria); - wlr_log(L_DEBUG, "for_window: '%s' -> '%s' added", criteria->raw, criteria->cmdlist); + wlr_log(WLR_DEBUG, "for_window: '%s' -> '%s' added", criteria->raw, criteria->cmdlist); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index 1a4d8b41..0b5beaa2 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c @@ -34,7 +34,7 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { view_set_fullscreen(view, wants_fullscreen); struct sway_container *workspace = container_parent(container, C_WORKSPACE); - arrange_and_commit(workspace->parent); + arrange_windows(workspace->parent); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c index 801fb179..3906eb70 100644 --- a/sway/commands/gaps.c +++ b/sway/commands/gaps.c @@ -43,7 +43,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { return cmd_results_new(CMD_INVALID, "gaps", "gaps edge_gaps on|off|toggle"); } - arrange_and_commit(&root_container); + arrange_windows(&root_container); } else { int amount_idx = 0; // the current index in argv enum gaps_op op = GAPS_OP_SET; @@ -124,7 +124,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { if (amount_idx == 0) { // gaps <amount> config->gaps_inner = val; config->gaps_outer = val; - arrange_and_commit(&root_container); + arrange_windows(&root_container); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } // Other variants. The middle-length variant (gaps inner|outer <amount>) @@ -155,7 +155,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { } else { config->gaps_outer = total; } - arrange_and_commit(&root_container); + arrange_windows(&root_container); } else { struct sway_container *c = config->handler_context.current_container; @@ -169,7 +169,7 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { c->gaps_outer = total; } - arrange_and_commit(c->parent ? c->parent : &root_container); + arrange_windows(c->parent ? c->parent : &root_container); } } diff --git a/sway/commands/input.c b/sway/commands/input.c index 678c57c4..5b203ea0 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c @@ -20,8 +20,10 @@ static struct cmd_handler input_handlers[] = { { "pointer_accel", input_cmd_pointer_accel }, { "repeat_delay", input_cmd_repeat_delay }, { "repeat_rate", input_cmd_repeat_rate }, + { "scroll_button", input_cmd_scroll_button }, { "scroll_method", input_cmd_scroll_method }, { "tap", input_cmd_tap }, + { "tap_button_map", input_cmd_tap_button_map }, { "xkb_layout", input_cmd_xkb_layout }, { "xkb_model", input_cmd_xkb_model }, { "xkb_options", input_cmd_xkb_options }, @@ -35,7 +37,7 @@ struct cmd_results *cmd_input(int argc, char **argv) { return error; } - wlr_log(L_DEBUG, "entering input block: %s", argv[0]); + wlr_log(WLR_DEBUG, "entering input block: %s", argv[0]); config->handler_context.input_config = new_input_config(argv[0]); if (!config->handler_context.input_config) { diff --git a/sway/commands/input/events.c b/sway/commands/input/events.c index e2ccdc94..abfe3b12 100644 --- a/sway/commands/input/events.c +++ b/sway/commands/input/events.c @@ -16,7 +16,7 @@ struct cmd_results *input_cmd_events(int argc, char **argv) { return cmd_results_new(CMD_FAILURE, "events", "No input device defined."); } - wlr_log(L_DEBUG, "events for device: %s", + wlr_log(WLR_DEBUG, "events for device: %s", current_input_config->identifier); struct input_config *new_config = new_input_config(current_input_config->identifier); diff --git a/sway/commands/input/scroll_button.c b/sway/commands/input/scroll_button.c new file mode 100644 index 00000000..350fcca2 --- /dev/null +++ b/sway/commands/input/scroll_button.c @@ -0,0 +1,44 @@ +#include <string.h> +#include <strings.h> +#include <errno.h> +#include "sway/config.h" +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *input_cmd_scroll_button(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "scroll_button", EXPECTED_AT_LEAST, 1))) { + return error; + } + struct input_config *current_input_config = + config->handler_context.input_config; + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "scroll_button", + "No input device defined."); + } + struct input_config *new_config = + new_input_config(current_input_config->identifier); + + errno = 0; + char *endptr; + int scroll_button = strtol(*argv, &endptr, 10); + if (endptr == *argv && scroll_button == 0) { + free_input_config(new_config); + return cmd_results_new(CMD_INVALID, "scroll_button", + "Scroll button identifier must be an integer."); + } + if (errno == ERANGE) { + free_input_config(new_config); + return cmd_results_new(CMD_INVALID, "scroll_button", + "Scroll button identifier out of range."); + } + if (scroll_button < 0) { + free_input_config(new_config); + return cmd_results_new(CMD_INVALID, "scroll_button", + "Scroll button identifier cannot be negative."); + } + new_config->scroll_button = scroll_button; + + apply_input_config(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/tap.c b/sway/commands/input/tap.c index 7d027d5d..a8d1a10c 100644 --- a/sway/commands/input/tap.c +++ b/sway/commands/input/tap.c @@ -28,7 +28,7 @@ struct cmd_results *input_cmd_tap(int argc, char **argv) { "Expected 'tap <enabled|disabled>'"); } - wlr_log(L_DEBUG, "apply-tap for device: %s", + wlr_log(WLR_DEBUG, "apply-tap for device: %s", current_input_config->identifier); apply_input_config(new_config); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/input/tap_button_map.c b/sway/commands/input/tap_button_map.c new file mode 100644 index 00000000..bdbba472 --- /dev/null +++ b/sway/commands/input/tap_button_map.c @@ -0,0 +1,33 @@ +#include <string.h> +#include <strings.h> +#include "sway/config.h" +#include "sway/commands.h" +#include "sway/input/input-manager.h" + +struct cmd_results *input_cmd_tap_button_map(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "tap_button_map", EXPECTED_AT_LEAST, 1))) { + return error; + } + struct input_config *current_input_config = + config->handler_context.input_config; + if (!current_input_config) { + return cmd_results_new(CMD_FAILURE, "tap_button_map", + "No input device defined."); + } + struct input_config *new_config = + new_input_config(current_input_config->identifier); + + if (strcasecmp(argv[0], "lrm") == 0) { + new_config->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; + } else if (strcasecmp(argv[0], "lmr") == 0) { + new_config->tap_button_map = LIBINPUT_CONFIG_TAP_MAP_LMR; + } else { + free_input_config(new_config); + return cmd_results_new(CMD_INVALID, "tap_button_map", + "Expected 'tap_button_map <lrm|lmr>'"); + } + + apply_input_config(new_config); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/input/xkb_layout.c b/sway/commands/input/xkb_layout.c index 867e65d3..9fa5a344 100644 --- a/sway/commands/input/xkb_layout.c +++ b/sway/commands/input/xkb_layout.c @@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_layout(int argc, char **argv) { new_config->xkb_layout = strdup(argv[0]); - wlr_log(L_DEBUG, "apply-xkb_layout for device: %s layout: %s", + wlr_log(WLR_DEBUG, "apply-xkb_layout for device: %s layout: %s", current_input_config->identifier, new_config->xkb_layout); apply_input_config(new_config); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/input/xkb_model.c b/sway/commands/input/xkb_model.c index e8c8e04e..0d082625 100644 --- a/sway/commands/input/xkb_model.c +++ b/sway/commands/input/xkb_model.c @@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_model(int argc, char **argv) { new_config->xkb_model = strdup(argv[0]); - wlr_log(L_DEBUG, "apply-xkb_model for device: %s model: %s", + wlr_log(WLR_DEBUG, "apply-xkb_model for device: %s model: %s", current_input_config->identifier, new_config->xkb_model); apply_input_config(new_config); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/input/xkb_options.c b/sway/commands/input/xkb_options.c index e9ddd6e3..3059d941 100644 --- a/sway/commands/input/xkb_options.c +++ b/sway/commands/input/xkb_options.c @@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_options(int argc, char **argv) { new_config->xkb_options = strdup(argv[0]); - wlr_log(L_DEBUG, "apply-xkb_options for device: %s options: %s", + wlr_log(WLR_DEBUG, "apply-xkb_options for device: %s options: %s", current_input_config->identifier, new_config->xkb_options); apply_input_config(new_config); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/input/xkb_rules.c b/sway/commands/input/xkb_rules.c index 926d0ac1..560f088e 100644 --- a/sway/commands/input/xkb_rules.c +++ b/sway/commands/input/xkb_rules.c @@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_rules(int argc, char **argv) { new_config->xkb_rules = strdup(argv[0]); - wlr_log(L_DEBUG, "apply-xkb_rules for device: %s rules: %s", + wlr_log(WLR_DEBUG, "apply-xkb_rules for device: %s rules: %s", current_input_config->identifier, new_config->xkb_rules); apply_input_config(new_config); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/input/xkb_variant.c b/sway/commands/input/xkb_variant.c index 0e3ffd41..0aa03440 100644 --- a/sway/commands/input/xkb_variant.c +++ b/sway/commands/input/xkb_variant.c @@ -19,7 +19,7 @@ struct cmd_results *input_cmd_xkb_variant(int argc, char **argv) { new_config->xkb_variant = strdup(argv[0]); - wlr_log(L_DEBUG, "apply-xkb_variant for device: %s variant: %s", + wlr_log(WLR_DEBUG, "apply-xkb_variant for device: %s variant: %s", current_input_config->identifier, new_config->xkb_variant); apply_input_config(new_config); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/layout.c b/sway/commands/layout.c index 9945fa5c..c446f1f9 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c @@ -49,7 +49,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) { } container_notify_subtree_changed(parent); - arrange_and_commit(parent); + arrange_windows(parent); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/mode.c b/sway/commands/mode.c index d2c14468..b460fcb5 100644 --- a/sway/commands/mode.c +++ b/sway/commands/mode.c @@ -65,7 +65,7 @@ struct cmd_results *cmd_mode(int argc, char **argv) { return error; } if ((config->reading && argc > 1) || (!config->reading && argc == 1)) { - wlr_log(L_DEBUG, "Switching to mode `%s' (pango=%d)", + wlr_log(WLR_DEBUG, "Switching to mode `%s' (pango=%d)", mode->name, mode->pango); } // Set current mode diff --git a/sway/commands/move.c b/sway/commands/move.c index a4fae388..6ec050a8 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -1,11 +1,12 @@ #define _XOPEN_SOURCE 500 #include <string.h> #include <strings.h> +#include <wlr/types/wlr_cursor.h> #include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output_layout.h> #include <wlr/util/log.h> #include "sway/commands.h" -#include "sway/desktop/transaction.h" +#include "sway/input/cursor.h" #include "sway/input/seat.h" #include "sway/output.h" #include "sway/tree/arrange.h" @@ -103,10 +104,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, // TODO: Ideally we would arrange the surviving parent after reaping, // but container_reap_empty does not return it, so we arrange the // workspace instead. - struct sway_transaction *txn = transaction_create(); - arrange_windows(old_ws, txn); - arrange_windows(destination->parent, txn); - transaction_commit(txn); + arrange_windows(old_ws); + arrange_windows(destination->parent); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } else if (strcasecmp(argv[1], "to") == 0 @@ -142,10 +141,8 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, // TODO: Ideally we would arrange the surviving parent after reaping, // but container_reap_empty does not return it, so we arrange the // workspace instead. - struct sway_transaction *txn = transaction_create(); - arrange_windows(old_ws, txn); - arrange_windows(focus->parent, txn); - transaction_commit(txn); + arrange_windows(old_ws); + arrange_windows(focus->parent); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } @@ -175,20 +172,56 @@ static struct cmd_results *cmd_move_workspace(struct sway_container *current, } container_move_to(current, destination); - struct sway_transaction *txn = transaction_create(); - arrange_windows(source, txn); - arrange_windows(destination, txn); - transaction_commit(txn); + arrange_windows(source); + arrange_windows(destination); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } static struct cmd_results *move_in_direction(struct sway_container *container, - enum movement_direction direction, int move_amt) { + enum movement_direction direction, int argc, char **argv) { + int move_amt = 10; + if (argc > 1) { + char *inv; + move_amt = (int)strtol(argv[1], &inv, 10); + if (*inv != '\0' && strcasecmp(inv, "px") != 0) { + return cmd_results_new(CMD_FAILURE, "move", + "Invalid distance specified"); + } + } + if (container->type == C_WORKSPACE) { return cmd_results_new(CMD_FAILURE, "move", "Cannot move workspaces in a direction"); } + if (container_is_floating(container)) { + if (container->type == C_VIEW && container->sway_view->is_fullscreen) { + return cmd_results_new(CMD_FAILURE, "move", + "Cannot move fullscreen floating container"); + } + double lx = container->x; + double ly = container->y; + switch (direction) { + case MOVE_LEFT: + lx -= move_amt; + break; + case MOVE_RIGHT: + lx += move_amt; + break; + case MOVE_UP: + ly -= move_amt; + break; + case MOVE_DOWN: + ly += move_amt; + break; + case MOVE_PARENT: + case MOVE_CHILD: + return cmd_results_new(CMD_FAILURE, "move", + "Cannot move floating container to parent or child"); + } + container_floating_move_to(container, lx, ly); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } // For simplicity, we'll arrange the entire workspace. The reason for this // is moving the container might reap the old parent, and container_move // does not return a surviving parent. @@ -198,41 +231,86 @@ static struct cmd_results *move_in_direction(struct sway_container *container, container_move(container, direction, move_amt); struct sway_container *new_ws = container_parent(container, C_WORKSPACE); - struct sway_transaction *txn = transaction_create(); - arrange_windows(old_ws, txn); + arrange_windows(old_ws); if (new_ws != old_ws) { - arrange_windows(new_ws, txn); + arrange_windows(new_ws); } - transaction_commit(txn); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } +static const char* expected_position_syntax = + "Expected 'move [absolute] position <x> <y>' or " + "'move [absolute] position mouse'"; + +static struct cmd_results *move_to_position(struct sway_container *container, + int argc, char **argv) { + if (!container_is_floating(container)) { + return cmd_results_new(CMD_FAILURE, "move", + "Only floating containers " + "can be moved to an absolute position"); + } + if (!argc) { + return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); + } + if (strcmp(argv[0], "absolute") == 0) { + --argc; + ++argv; + } + if (!argc) { + return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); + } + if (strcmp(argv[0], "position") == 0) { + --argc; + ++argv; + } + if (!argc) { + return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); + } + if (strcmp(argv[0], "mouse") == 0) { + struct sway_seat *seat = config->handler_context.seat; + if (!seat->cursor) { + return cmd_results_new(CMD_FAILURE, "move", "No cursor device"); + } + double lx = seat->cursor->cursor->x - container->width / 2; + double ly = seat->cursor->cursor->y - container->height / 2; + container_floating_move_to(container, lx, ly); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); + } + if (argc != 2) { + return cmd_results_new(CMD_FAILURE, "move", expected_position_syntax); + } + double lx, ly; + char *inv; + lx = (double)strtol(argv[0], &inv, 10); + if (*inv != '\0' && strcasecmp(inv, "px") != 0) { + return cmd_results_new(CMD_FAILURE, "move", + "Invalid position specified"); + } + ly = (double)strtol(argv[1], &inv, 10); + if (*inv != '\0' && strcasecmp(inv, "px") != 0) { + return cmd_results_new(CMD_FAILURE, "move", + "Invalid position specified"); + } + container_floating_move_to(container, lx, ly); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + struct cmd_results *cmd_move(int argc, char **argv) { struct cmd_results *error = NULL; - int move_amt = 10; if ((error = checkarg(argc, "move", EXPECTED_AT_LEAST, 1))) { return error; } struct sway_container *current = config->handler_context.current_container; - if (argc == 2 || (argc == 3 && strcasecmp(argv[2], "px") == 0)) { - char *inv; - move_amt = (int)strtol(argv[1], &inv, 10); - if (*inv != '\0' && strcasecmp(inv, "px") != 0) { - return cmd_results_new(CMD_FAILURE, "move", - "Invalid distance specified"); - } - } - if (strcasecmp(argv[0], "left") == 0) { - return move_in_direction(current, MOVE_LEFT, move_amt); + return move_in_direction(current, MOVE_LEFT, argc, argv); } else if (strcasecmp(argv[0], "right") == 0) { - return move_in_direction(current, MOVE_RIGHT, move_amt); + return move_in_direction(current, MOVE_RIGHT, argc, argv); } else if (strcasecmp(argv[0], "up") == 0) { - return move_in_direction(current, MOVE_UP, move_amt); + return move_in_direction(current, MOVE_UP, argc, argv); } else if (strcasecmp(argv[0], "down") == 0) { - return move_in_direction(current, MOVE_DOWN, move_amt); + return move_in_direction(current, MOVE_DOWN, argc, argv); } else if (strcasecmp(argv[0], "container") == 0 || strcasecmp(argv[0], "window") == 0) { return cmd_move_container(current, argc, argv); @@ -244,8 +322,9 @@ struct cmd_results *cmd_move(int argc, char **argv) { // TODO: scratchpad return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); } else if (strcasecmp(argv[0], "position") == 0) { - // TODO: floating - return cmd_results_new(CMD_FAILURE, "move", "Unimplemented"); + return move_to_position(current, argc, argv); + } else if (strcasecmp(argv[0], "absolute") == 0) { + return move_to_position(current, argc, argv); } else { return cmd_results_new(CMD_INVALID, "move", expected_syntax); } diff --git a/sway/commands/no_focus.c b/sway/commands/no_focus.c new file mode 100644 index 00000000..61a8de7e --- /dev/null +++ b/sway/commands/no_focus.c @@ -0,0 +1,26 @@ +#define _XOPEN_SOURCE 500 +#include <string.h> +#include "sway/commands.h" +#include "sway/criteria.h" +#include "list.h" +#include "log.h" + +struct cmd_results *cmd_no_focus(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "no_focus", EXPECTED_AT_LEAST, 1))) { + return error; + } + + char *err_str = NULL; + struct criteria *criteria = criteria_parse(argv[0], &err_str); + if (!criteria) { + error = cmd_results_new(CMD_INVALID, "no_focus", err_str); + free(err_str); + return error; + } + + criteria->type = CT_NO_FOCUS; + list_add(config->criteria, criteria); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/output.c b/sway/commands/output.c index f955bf90..15bbd687 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c @@ -29,7 +29,7 @@ struct cmd_results *cmd_output(int argc, char **argv) { struct output_config *output = new_output_config(argv[0]); if (!output) { - wlr_log(L_ERROR, "Failed to allocate output config"); + wlr_log(WLR_ERROR, "Failed to allocate output config"); return NULL; } argc--; argv++; @@ -71,7 +71,7 @@ struct cmd_results *cmd_output(int argc, char **argv) { list_add(config->output_configs, output); } - wlr_log(L_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " + wlr_log(WLR_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " "position %d,%d scale %f transform %d) (bg %s %s) (dpms %d)", output->name, output->enabled, output->width, output->height, output->refresh_rate, output->x, output->y, output->scale, @@ -85,7 +85,7 @@ struct cmd_results *cmd_output(int argc, char **argv) { struct sway_output *sway_output; wl_list_for_each(sway_output, &root_container.sway_root->outputs, link) { output_get_identifier(identifier, sizeof(identifier), sway_output); - wlr_log(L_DEBUG, "Checking identifier %s", identifier); + wlr_log(WLR_DEBUG, "Checking identifier %s", identifier); if (all || strcmp(sway_output->wlr_output->name, output->name) == 0 || strcmp(identifier, output->name) == 0) { if (!sway_output->swayc) { diff --git a/sway/commands/output/background.c b/sway/commands/output/background.c index 65b5f902..4ed56c2a 100644 --- a/sway/commands/output/background.c +++ b/sway/commands/output/background.c @@ -72,7 +72,7 @@ struct cmd_results *output_cmd_background(int argc, char **argv) { src = strdup(p.we_wordv[0]); wordfree(&p); if (!src) { - wlr_log(L_ERROR, "Failed to duplicate string"); + wlr_log(WLR_ERROR, "Failed to duplicate string"); return cmd_results_new(CMD_FAILURE, "output", "Unable to allocate resource"); } @@ -80,9 +80,9 @@ struct cmd_results *output_cmd_background(int argc, char **argv) { if (config->reading && *src != '/') { // src file is inside configuration dir - char *conf = strdup(config->current_config); + char *conf = strdup(config->current_config_path); if (!conf) { - wlr_log(L_ERROR, "Failed to duplicate string"); + wlr_log(WLR_ERROR, "Failed to duplicate string"); free(src); return cmd_results_new(CMD_FAILURE, "output", "Unable to allocate resources"); @@ -94,7 +94,7 @@ struct cmd_results *output_cmd_background(int argc, char **argv) { if (!src) { free(rel_path); free(conf); - wlr_log(L_ERROR, "Unable to allocate memory"); + wlr_log(WLR_ERROR, "Unable to allocate memory"); return cmd_results_new(CMD_FAILURE, "output", "Unable to allocate resources"); } diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 9fc213c4..cea6a94b 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c @@ -7,11 +7,11 @@ struct cmd_results *cmd_reload(int argc, char **argv) { if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { return error; } - if (!load_main_config(config->current_config, true)) { + if (!load_main_config(config->current_config_path, true)) { return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); } load_swaybars(); - arrange_and_commit(&root_container); + arrange_windows(&root_container); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/rename.c b/sway/commands/rename.c index 104a3392..a380ff9c 100644 --- a/sway/commands/rename.c +++ b/sway/commands/rename.c @@ -68,7 +68,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) { "Workspace already exists"); } - wlr_log(L_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name); + wlr_log(WLR_DEBUG, "renaming workspace '%s' to '%s'", workspace->name, new_name); free(workspace->name); workspace->name = new_name; diff --git a/sway/commands/resize.c b/sway/commands/resize.c index 6357343e..e657864c 100644 --- a/sway/commands/resize.c +++ b/sway/commands/resize.c @@ -1,4 +1,5 @@ #include <errno.h> +#include <limits.h> #include <math.h> #include <stdbool.h> #include <stdlib.h> @@ -7,6 +8,7 @@ #include <wlr/util/log.h> #include "sway/commands.h" #include "sway/tree/arrange.h" +#include "sway/tree/view.h" #include "log.h" static const int MIN_SANE_W = 100, MIN_SANE_H = 60; @@ -21,9 +23,18 @@ enum resize_unit { enum resize_axis { RESIZE_AXIS_HORIZONTAL, RESIZE_AXIS_VERTICAL, + RESIZE_AXIS_UP, + RESIZE_AXIS_DOWN, + RESIZE_AXIS_LEFT, + RESIZE_AXIS_RIGHT, RESIZE_AXIS_INVALID, }; +struct resize_amount { + int amount; + enum resize_unit unit; +}; + static enum resize_unit parse_resize_unit(const char *unit) { if (strcasecmp(unit, "px") == 0) { return RESIZE_UNIT_PX; @@ -37,6 +48,69 @@ static enum resize_unit parse_resize_unit(const char *unit) { return RESIZE_UNIT_INVALID; } +// Parse arguments such as "10", "10px" or "10 px". +// Returns the number of arguments consumed. +static int parse_resize_amount(int argc, char **argv, + struct resize_amount *amount) { + char *err; + amount->amount = (int)strtol(argv[0], &err, 10); + if (*err) { + // e.g. 10px + amount->unit = parse_resize_unit(err); + return 1; + } + if (argc == 1) { + amount->unit = RESIZE_UNIT_DEFAULT; + return 1; + } + // Try the second argument + amount->unit = parse_resize_unit(argv[1]); + if (amount->unit == RESIZE_UNIT_INVALID) { + amount->unit = RESIZE_UNIT_DEFAULT; + return 1; + } + return 2; +} + +static void calculate_constraints(int *min_width, int *max_width, + int *min_height, int *max_height) { + struct sway_container *con = config->handler_context.current_container; + + if (config->floating_minimum_width == -1) { // no minimum + *min_width = 0; + } else if (config->floating_minimum_width == 0) { // automatic + *min_width = 75; + } else { + *min_width = config->floating_minimum_width; + } + + if (config->floating_minimum_height == -1) { // no minimum + *min_height = 0; + } else if (config->floating_minimum_height == 0) { // automatic + *min_height = 50; + } else { + *min_height = config->floating_minimum_height; + } + + if (config->floating_maximum_width == -1) { // no maximum + *max_width = INT_MAX; + } else if (config->floating_maximum_width == 0) { // automatic + struct sway_container *ws = container_parent(con, C_WORKSPACE); + *max_width = ws->width; + } else { + *max_width = config->floating_maximum_width; + } + + if (config->floating_maximum_height == -1) { // no maximum + *max_height = INT_MAX; + } else if (config->floating_maximum_height == 0) { // automatic + struct sway_container *ws = container_parent(con, C_WORKSPACE); + *max_height = ws->height; + } else { + *max_height = config->floating_maximum_height; + } +} + static enum resize_axis parse_resize_axis(const char *axis) { if (strcasecmp(axis, "width") == 0 || strcasecmp(axis, "horizontal") == 0) { return RESIZE_AXIS_HORIZONTAL; @@ -44,6 +118,18 @@ static enum resize_axis parse_resize_axis(const char *axis) { if (strcasecmp(axis, "height") == 0 || strcasecmp(axis, "vertical") == 0) { return RESIZE_AXIS_VERTICAL; } + if (strcasecmp(axis, "up") == 0) { + return RESIZE_AXIS_UP; + } + if (strcasecmp(axis, "down") == 0) { + return RESIZE_AXIS_DOWN; + } + if (strcasecmp(axis, "left") == 0) { + return RESIZE_AXIS_LEFT; + } + if (strcasecmp(axis, "right") == 0) { + return RESIZE_AXIS_RIGHT; + } return RESIZE_AXIS_INVALID; } @@ -95,7 +181,7 @@ static void resize_tiled(int amount, enum resize_axis axis) { return; } - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "Found the proper parent: %p. It has %d l conts, and %d r conts", parent->parent, minor_weight, major_weight); @@ -182,105 +268,315 @@ static void resize_tiled(int amount, enum resize_axis axis) { } } - arrange_and_commit(parent->parent); + arrange_windows(parent->parent); } -static void resize(int amount, enum resize_axis axis, enum resize_unit unit) { - struct sway_container *current = config->handler_context.current_container; - if (unit == RESIZE_UNIT_DEFAULT) { - // Default for tiling; TODO floating should be px - unit = RESIZE_UNIT_PPT; +/** + * Implement `resize <grow|shrink>` for a floating container. + */ +static struct cmd_results *resize_adjust_floating(enum resize_axis axis, + struct resize_amount *amount) { + struct sway_container *con = config->handler_context.current_container; + int grow_width = 0, grow_height = 0; + switch (axis) { + case RESIZE_AXIS_HORIZONTAL: + case RESIZE_AXIS_LEFT: + case RESIZE_AXIS_RIGHT: + grow_width = amount->amount; + break; + case RESIZE_AXIS_VERTICAL: + case RESIZE_AXIS_UP: + case RESIZE_AXIS_DOWN: + grow_height = amount->amount; + break; + case RESIZE_AXIS_INVALID: + return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction"); + } + // Make sure we're not adjusting beyond floating min/max size + int min_width, max_width, min_height, max_height; + calculate_constraints(&min_width, &max_width, &min_height, &max_height); + if (con->width + grow_width < min_width) { + grow_width = min_width - con->width; + } else if (con->width + grow_width > max_width) { + grow_width = max_width - con->width; } + if (con->height + grow_height < min_height) { + grow_height = min_height - con->height; + } else if (con->height + grow_height > max_height) { + grow_height = max_height - con->height; + } + int grow_x = 0, grow_y = 0; + switch (axis) { + case RESIZE_AXIS_HORIZONTAL: + grow_x = -grow_width / 2; + break; + case RESIZE_AXIS_VERTICAL: + grow_y = -grow_height / 2; + break; + case RESIZE_AXIS_UP: + grow_y = -grow_height; + break; + case RESIZE_AXIS_LEFT: + grow_x = -grow_width; + break; + case RESIZE_AXIS_DOWN: + case RESIZE_AXIS_RIGHT: + break; + case RESIZE_AXIS_INVALID: + return cmd_results_new(CMD_INVALID, "resize", "Invalid axis/direction"); + } + con->x += grow_x; + con->y += grow_y; + con->width += grow_width; + con->height += grow_height; + + if (con->type == C_VIEW) { + struct sway_view *view = con->sway_view; + view->x += grow_x; + view->y += grow_y; + view->width += grow_width; + view->height += grow_height; + } + + arrange_windows(con); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} - if (unit == RESIZE_UNIT_PPT) { - float pct = amount / 100.0f; +/** + * Implement `resize <grow|shrink>` for a tiled container. + */ +static struct cmd_results *resize_adjust_tiled(enum resize_axis axis, + struct resize_amount *amount) { + struct sway_container *current = config->handler_context.current_container; + + if (amount->unit == RESIZE_UNIT_DEFAULT) { + amount->unit = RESIZE_UNIT_PPT; + } + if (amount->unit == RESIZE_UNIT_PPT) { + float pct = amount->amount / 100.0f; + // TODO: Make left/right/up/down resize in that direction? switch (axis) { + case RESIZE_AXIS_LEFT: + case RESIZE_AXIS_RIGHT: case RESIZE_AXIS_HORIZONTAL: - amount = (float)current->width * pct; + amount->amount = (float)current->width * pct; break; + case RESIZE_AXIS_UP: + case RESIZE_AXIS_DOWN: case RESIZE_AXIS_VERTICAL: - amount = (float)current->height * pct; + amount->amount = (float)current->height * pct; break; - default: - sway_assert(0, "invalid resize axis"); - return; + case RESIZE_AXIS_INVALID: + return cmd_results_new(CMD_INVALID, "resize", + "Invalid resize axis/direction"); } } - return resize_tiled(amount, axis); + resize_tiled(amount->amount, axis); + return cmd_results_new(CMD_SUCCESS, NULL, NULL); } -struct cmd_results *cmd_resize(int argc, char **argv) { - struct sway_container *current = config->handler_context.current_container; - if (!current) { - return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); - } - if (current->type != C_VIEW && current->type != C_CONTAINER) { - return cmd_results_new(CMD_INVALID, "resize", - "Can only resize views/containers"); +/** + * Implement `resize set` for a tiled container. + */ +static struct cmd_results *resize_set_tiled(struct sway_container *con, + struct resize_amount *width, struct resize_amount *height) { + return cmd_results_new(CMD_INVALID, "resize", + "'resize set' is not implemented for tiled views"); +} + +/** + * Implement `resize set` for a floating container. + */ +static struct cmd_results *resize_set_floating(struct sway_container *con, + struct resize_amount *width, struct resize_amount *height) { + int min_width, max_width, min_height, max_height; + calculate_constraints(&min_width, &max_width, &min_height, &max_height); + width->amount = fmax(min_width, fmin(width->amount, max_width)); + height->amount = fmax(min_height, fmin(height->amount, max_height)); + int grow_width = width->amount - con->width; + int grow_height = height->amount - con->height; + con->x -= grow_width / 2; + con->y -= grow_height / 2; + con->width = width->amount; + con->height = height->amount; + + if (con->type == C_VIEW) { + struct sway_view *view = con->sway_view; + view->x -= grow_width / 2; + view->y -= grow_height / 2; + view->width += grow_width; + view->height += grow_height; } + arrange_windows(con); + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} + +/** + * resize set <args> + * + * args: <width> [px|ppt] <height> [px|ppt] + */ +static struct cmd_results *cmd_resize_set(int argc, char **argv) { struct cmd_results *error; if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { return error; } - - if (strcasecmp(argv[0], "set") == 0) { - // TODO - //return cmd_resize_set(argc - 1, &argv[1]); - return cmd_results_new(CMD_INVALID, "resize", "resize set unimplemented"); + const char *usage = "Expected 'resize set <width> <height>'"; + + // Width + struct resize_amount width; + int num_consumed_args = parse_resize_amount(argc, argv, &width); + argc -= num_consumed_args; + argv += num_consumed_args; + if (width.unit == RESIZE_UNIT_INVALID) { + return cmd_results_new(CMD_INVALID, "resize", usage); + } + if (!argc) { + return cmd_results_new(CMD_INVALID, "resize", usage); } - // TODO: resize grow|shrink left|right|up|down + // Height + struct resize_amount height; + num_consumed_args = parse_resize_amount(argc, argv, &height); + argc -= num_consumed_args; + argv += num_consumed_args; + if (height.unit == RESIZE_UNIT_INVALID) { + return cmd_results_new(CMD_INVALID, "resize", usage); + } - const char *usage = "Expected 'resize <shrink|grow> " - "<width|height> [<amount>] [px|ppt]'"; + // If 0, don't resize that dimension + struct sway_container *con = config->handler_context.current_container; + if (width.amount <= 0) { + width.amount = con->width; + } + if (height.amount <= 0) { + height.amount = con->height; + } - int multiplier = 0; - if (strcasecmp(*argv, "grow") == 0) { - multiplier = 1; - } else if (strcasecmp(*argv, "shrink") == 0) { - multiplier = -1; - } else { - return cmd_results_new(CMD_INVALID, "resize", usage); + if (container_is_floating(con)) { + return resize_set_floating(con, &width, &height); } - --argc; ++argv; + return resize_set_tiled(con, &width, &height); +} +/** + * resize <grow|shrink> <args> + * + * args: <direction> + * args: <direction> <amount> <unit> + * args: <direction> <amount> <unit> or <amount> <other_unit> + */ +static struct cmd_results *cmd_resize_adjust(int argc, char **argv, + int multiplier) { + const char *usage = "Expected 'resize grow|shrink <direction> " + "[<amount> px|ppt [or <amount> px|ppt]]'"; enum resize_axis axis = parse_resize_axis(*argv); if (axis == RESIZE_AXIS_INVALID) { return cmd_results_new(CMD_INVALID, "resize", usage); } --argc; ++argv; - int amount = 10; // Default amount - enum resize_unit unit = RESIZE_UNIT_DEFAULT; - + // First amount + struct resize_amount first_amount; if (argc) { - char *err; - amount = (int)strtol(*argv, &err, 10); - if (*err) { - // e.g. `resize grow width 10px` - unit = parse_resize_unit(err); - if (unit == RESIZE_UNIT_INVALID) { - return cmd_results_new(CMD_INVALID, "resize", usage); - } + int num_consumed_args = parse_resize_amount(argc, argv, &first_amount); + argc -= num_consumed_args; + argv += num_consumed_args; + if (first_amount.unit == RESIZE_UNIT_INVALID) { + return cmd_results_new(CMD_INVALID, "resize", usage); } - --argc; ++argv; + } else { + first_amount.amount = 10; + first_amount.unit = RESIZE_UNIT_DEFAULT; } + // "or" if (argc) { - unit = parse_resize_unit(*argv); - if (unit == RESIZE_UNIT_INVALID) { + if (strcmp(*argv, "or") != 0) { return cmd_results_new(CMD_INVALID, "resize", usage); } --argc; ++argv; } + // Second amount + struct resize_amount second_amount; if (argc) { - // Provied too many args, the bastard - return cmd_results_new(CMD_INVALID, "resize", usage); + int num_consumed_args = parse_resize_amount(argc, argv, &second_amount); + argc -= num_consumed_args; + argv += num_consumed_args; + if (second_amount.unit == RESIZE_UNIT_INVALID) { + return cmd_results_new(CMD_INVALID, "resize", usage); + } + } else { + second_amount.unit = RESIZE_UNIT_INVALID; } - resize(amount * multiplier, axis, unit); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); + first_amount.amount *= multiplier; + second_amount.amount *= multiplier; + + struct sway_container *con = config->handler_context.current_container; + if (container_is_floating(con)) { + // Floating containers can only resize in px. Choose an amount which + // uses px, with fallback to an amount that specified no unit. + if (first_amount.unit == RESIZE_UNIT_PX) { + return resize_adjust_floating(axis, &first_amount); + } else if (second_amount.unit == RESIZE_UNIT_PX) { + return resize_adjust_floating(axis, &second_amount); + } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) { + return resize_adjust_floating(axis, &first_amount); + } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) { + return resize_adjust_floating(axis, &second_amount); + } else { + return cmd_results_new(CMD_INVALID, "resize", + "Floating containers cannot use ppt measurements"); + } + } + + // For tiling, prefer ppt -> default -> px + if (first_amount.unit == RESIZE_UNIT_PPT) { + return resize_adjust_tiled(axis, &first_amount); + } else if (second_amount.unit == RESIZE_UNIT_PPT) { + return resize_adjust_tiled(axis, &second_amount); + } else if (first_amount.unit == RESIZE_UNIT_DEFAULT) { + return resize_adjust_tiled(axis, &first_amount); + } else if (second_amount.unit == RESIZE_UNIT_DEFAULT) { + return resize_adjust_tiled(axis, &second_amount); + } else { + return resize_adjust_tiled(axis, &first_amount); + } +} + +struct cmd_results *cmd_resize(int argc, char **argv) { + struct sway_container *current = config->handler_context.current_container; + if (!current) { + return cmd_results_new(CMD_INVALID, "resize", "Cannot resize nothing"); + } + if (current->type != C_VIEW && current->type != C_CONTAINER) { + return cmd_results_new(CMD_INVALID, "resize", + "Can only resize views/containers"); + } + + struct cmd_results *error; + if ((error = checkarg(argc, "resize", EXPECTED_AT_LEAST, 2))) { + return error; + } + + if (strcasecmp(argv[0], "set") == 0) { + return cmd_resize_set(argc - 1, &argv[1]); + } + if (strcasecmp(argv[0], "grow") == 0) { + return cmd_resize_adjust(argc - 1, &argv[1], 1); + } + if (strcasecmp(argv[0], "shrink") == 0) { + return cmd_resize_adjust(argc - 1, &argv[1], -1); + } + + const char *usage = "Expected 'resize <shrink|grow> " + "<width|height|up|down|left|right> [<amount>] [px|ppt]'"; + + return cmd_results_new(CMD_INVALID, "resize", usage); } diff --git a/sway/commands/set.c b/sway/commands/set.c index 84e9b792..ea388d3b 100644 --- a/sway/commands/set.c +++ b/sway/commands/set.c @@ -32,7 +32,7 @@ struct cmd_results *cmd_set(int argc, char **argv) { } if (argv[0][0] != '$') { - wlr_log(L_INFO, "Warning: variable '%s' doesn't start with $", argv[0]); + wlr_log(WLR_INFO, "Warning: variable '%s' doesn't start with $", argv[0]); size_t size = snprintf(NULL, 0, "$%s", argv[0]); tmp = malloc(size + 1); diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c index f687e78e..7d27e571 100644 --- a/sway/commands/smart_gaps.c +++ b/sway/commands/smart_gaps.c @@ -23,7 +23,7 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) { "Expected 'smart_gaps <on|off>' "); } - arrange_and_commit(&root_container); + arrange_windows(&root_container); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/split.c b/sway/commands/split.c index c40f4d9f..313799da 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c @@ -16,7 +16,7 @@ static struct cmd_results *do_split(int layout) { } struct sway_container *parent = container_split(con, layout); container_create_notify(parent); - arrange_and_commit(parent->parent); + arrange_windows(parent->parent); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/swap.c b/sway/commands/swap.c index e052058f..2fc88308 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c @@ -1,7 +1,6 @@ #include <strings.h> #include <wlr/util/log.h> #include "sway/commands.h" -#include "sway/desktop/transaction.h" #include "sway/tree/arrange.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" @@ -79,14 +78,10 @@ struct cmd_results *cmd_swap(int argc, char **argv) { container_swap(current, other); - struct sway_transaction *txn = transaction_create(); - arrange_windows(current->parent, txn); - + arrange_windows(current->parent); if (other->parent != current->parent) { - arrange_windows(other->parent, txn); + arrange_windows(other->parent); } - transaction_commit(txn); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); } diff --git a/sway/commands/swaybg_command.c b/sway/commands/swaybg_command.c index 770d4821..36f7fdcd 100644 --- a/sway/commands/swaybg_command.c +++ b/sway/commands/swaybg_command.c @@ -13,7 +13,7 @@ struct cmd_results *cmd_swaybg_command(int argc, char **argv) { free(config->swaybg_command); } config->swaybg_command = join_args(argv, argc); - wlr_log(L_DEBUG, "Using custom swaybg command: %s", + wlr_log(WLR_DEBUG, "Using custom swaybg command: %s", config->swaybg_command); return cmd_results_new(CMD_SUCCESS, NULL, NULL); diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c new file mode 100644 index 00000000..d199858a --- /dev/null +++ b/sway/commands/urgent.c @@ -0,0 +1,36 @@ +#include "log.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/tree/arrange.h" +#include "sway/tree/container.h" +#include "sway/tree/view.h" +#include "sway/tree/layout.h" + +struct cmd_results *cmd_urgent(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = checkarg(argc, "urgent", EXPECTED_EQUAL_TO, 1))) { + return error; + } + struct sway_container *container = + config->handler_context.current_container; + if (container->type != C_VIEW) { + return cmd_results_new(CMD_INVALID, "urgent", + "Only views can be urgent"); + } + struct sway_view *view = container->sway_view; + + if (strcmp(argv[0], "enable") == 0) { + view_set_urgent(view, true); + } else if (strcmp(argv[0], "disable") == 0) { + view_set_urgent(view, false); + } else if (strcmp(argv[0], "allow") == 0) { + view->allow_request_urgent = true; + } else if (strcmp(argv[0], "deny") == 0) { + view->allow_request_urgent = false; + } else { + return cmd_results_new(CMD_INVALID, "urgent", + "Expected 'urgent <enable|disable|allow|deny>'"); + } + + return cmd_results_new(CMD_SUCCESS, NULL, NULL); +} diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index d15be571..e8b37182 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c @@ -51,7 +51,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { free(old); // workspaces can only be assigned to a single output list_del(config->workspace_outputs, i); } - wlr_log(L_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output); + wlr_log(WLR_DEBUG, "Assigning workspace %s to output %s", wso->workspace, wso->output); list_add(config->workspace_outputs, wso); } else { if (config->reading || !config->active) { diff --git a/sway/config.c b/sway/config.c index 89b7d349..c620e4c7 100644 --- a/sway/config.c +++ b/sway/config.c @@ -24,6 +24,7 @@ #include "sway/input/seat.h" #include "sway/commands.h" #include "sway/config.h" +#include "sway/criteria.h" #include "sway/tree/arrange.h" #include "sway/tree/layout.h" #include "sway/tree/workspace.h" @@ -105,7 +106,12 @@ void free_config(struct sway_config *config) { } list_free(config->seat_configs); } - list_free(config->criteria); + if (config->criteria) { + for (int i = 0; i < config->criteria->length; ++i) { + criteria_destroy(config->criteria->items[i]); + } + list_free(config->criteria); + } list_free(config->no_focus); list_free(config->active_bar_modifiers); list_free(config->config_chain); @@ -117,6 +123,7 @@ void free_config(struct sway_config *config) { free(config->floating_scroll_left_cmd); free(config->floating_scroll_right_cmd); free(config->font); + free((char *)config->current_config_path); free((char *)config->current_config); free(config); } @@ -205,6 +212,7 @@ static void config_defaults(struct sway_config *config) { if (!(config->active_bar_modifiers = create_list())) goto cleanup; if (!(config->config_chain = create_list())) goto cleanup; + config->current_config_path = NULL; config->current_config = NULL; // borders @@ -276,12 +284,12 @@ static char *get_config_path(void) { char *home = getenv("HOME"); char *config_home = malloc(strlen(home) + strlen("/.config") + 1); if (!config_home) { - wlr_log(L_ERROR, "Unable to allocate $HOME/.config"); + wlr_log(WLR_ERROR, "Unable to allocate $HOME/.config"); } else { strcpy(config_home, home); strcat(config_home, "/.config"); setenv("XDG_CONFIG_HOME", config_home, 1); - wlr_log(L_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home); + wlr_log(WLR_DEBUG, "Set XDG_CONFIG_HOME to %s", config_home); free(config_home); } } @@ -304,16 +312,13 @@ static char *get_config_path(void) { return NULL; // Not reached } -const char *current_config_path; - static bool load_config(const char *path, struct sway_config *config) { if (path == NULL) { - wlr_log(L_ERROR, "Unable to find a config file!"); + wlr_log(WLR_ERROR, "Unable to find a config file!"); return false; } - wlr_log(L_INFO, "Loading config from %s", path); - current_config_path = path; + wlr_log(WLR_INFO, "Loading config from %s", path); struct stat sb; if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { @@ -322,7 +327,7 @@ static bool load_config(const char *path, struct sway_config *config) { FILE *f = fopen(path, "r"); if (!f) { - wlr_log(L_ERROR, "Unable to open %s for reading", path); + wlr_log(WLR_ERROR, "Unable to open %s for reading", path); return false; } @@ -330,10 +335,9 @@ static bool load_config(const char *path, struct sway_config *config) { fclose(f); if (!config_load_success) { - wlr_log(L_ERROR, "Error(s) loading config!"); + wlr_log(WLR_ERROR, "Error(s) loading config!"); } - current_config_path = NULL; return true; } @@ -353,12 +357,12 @@ bool load_main_config(const char *file, bool is_active) { config_defaults(config); if (is_active) { - wlr_log(L_DEBUG, "Performing configuration file reload"); + wlr_log(WLR_DEBUG, "Performing configuration file reload"); config->reloading = true; config->active = true; } - config->current_config = path; + config->current_config_path = path; list_add(config->config_chain, path); config->reading = true; @@ -369,7 +373,7 @@ bool load_main_config(const char *file, bool is_active) { /* DIR *dir = opendir(SYSCONFDIR "/sway/security.d"); if (!dir) { - wlr_log(L_ERROR, + wlr_log(WLR_ERROR, "%s does not exist, sway will have no security configuration" " and will probably be broken", SYSCONFDIR "/sway/security.d"); } else { @@ -398,7 +402,7 @@ bool load_main_config(const char *file, bool is_active) { if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || (((s.st_mode & 0777) != 0644) && (s.st_mode & 0777) != 0444)) { - wlr_log(L_ERROR, + wlr_log(WLR_ERROR, "Refusing to load %s - it must be owned by root " "and mode 644 or 444", _path); success = false; @@ -428,7 +432,7 @@ bool load_main_config(const char *file, bool is_active) { static bool load_include_config(const char *path, const char *parent_dir, struct sway_config *config) { // save parent config - const char *parent_config = config->current_config; + const char *parent_config = config->current_config_path; char *full_path; int len = strlen(path); @@ -436,7 +440,7 @@ static bool load_include_config(const char *path, const char *parent_dir, len = len + strlen(parent_dir) + 2; full_path = malloc(len * sizeof(char)); if (!full_path) { - wlr_log(L_ERROR, + wlr_log(WLR_ERROR, "Unable to allocate full path to included config"); return false; } @@ -449,7 +453,7 @@ static bool load_include_config(const char *path, const char *parent_dir, free(full_path); if (real_path == NULL) { - wlr_log(L_DEBUG, "%s not found.", path); + wlr_log(WLR_DEBUG, "%s not found.", path); return false; } @@ -458,7 +462,7 @@ static bool load_include_config(const char *path, const char *parent_dir, for (j = 0; j < config->config_chain->length; ++j) { char *old_path = config->config_chain->items[j]; if (strcmp(real_path, old_path) == 0) { - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "%s already included once, won't be included again.", real_path); free(real_path); @@ -466,25 +470,25 @@ static bool load_include_config(const char *path, const char *parent_dir, } } - config->current_config = real_path; + config->current_config_path = real_path; list_add(config->config_chain, real_path); int index = config->config_chain->length - 1; if (!load_config(real_path, config)) { free(real_path); - config->current_config = parent_config; + config->current_config_path = parent_config; list_del(config->config_chain, index); return false; } - // restore current_config - config->current_config = parent_config; + // restore current_config_path + config->current_config_path = parent_config; return true; } bool load_include_configs(const char *path, struct sway_config *config) { char *wd = getcwd(NULL, 0); - char *parent_path = strdup(config->current_config); + char *parent_path = strdup(config->current_config_path); const char *parent_dir = dirname(parent_path); if (chdir(parent_dir) < 0) { @@ -512,7 +516,7 @@ bool load_include_configs(const char *path, struct sway_config *config) { // restore wd if (chdir(wd) < 0) { free(wd); - wlr_log(L_ERROR, "failed to restore working directory"); + wlr_log(WLR_ERROR, "failed to restore working directory"); return false; } @@ -527,13 +531,13 @@ static int detect_brace_on_following_line(FILE *file, char *line, char *peeked = NULL; long position = 0; do { - wlr_log(L_DEBUG, "Peeking line %d", line_number + lines + 1); + wlr_log(WLR_DEBUG, "Peeking line %d", line_number + lines + 1); free(peeked); peeked = peek_line(file, lines, &position); if (peeked) { peeked = strip_whitespace(peeked); } - wlr_log(L_DEBUG, "Peeked line: `%s`", peeked); + wlr_log(WLR_DEBUG, "Peeked line: `%s`", peeked); lines++; } while (peeked && strlen(peeked) == 0); @@ -552,7 +556,7 @@ static char *expand_line(const char *block, const char *line, bool add_brace) { + (add_brace ? 2 : 0) + 1; char *expanded = calloc(1, size); if (!expanded) { - wlr_log(L_ERROR, "Cannot allocate expanded line buffer"); + wlr_log(WLR_ERROR, "Cannot allocate expanded line buffer"); return NULL; } snprintf(expanded, size, "%s%s%s%s", block ? block : "", @@ -561,10 +565,33 @@ static char *expand_line(const char *block, const char *line, bool add_brace) { } bool read_config(FILE *file, struct sway_config *config) { + bool reading_main_config = false; + char *this_config = NULL; + size_t config_size = 0; + if (config->current_config == NULL) { + reading_main_config = true; + + int ret_seek = fseek(file, 0, SEEK_END); + long ret_tell = ftell(file); + if (ret_seek == -1 || ret_tell == -1) { + wlr_log(WLR_ERROR, "Unable to get size of config file"); + return false; + } + config_size = ret_tell; + rewind(file); + + config->current_config = this_config = calloc(1, config_size + 1); + if (this_config == NULL) { + wlr_log(WLR_ERROR, "Unable to allocate buffer for config contents"); + return false; + } + } + bool success = true; int line_number = 0; char *line; list_t *stack = create_list(); + size_t read = 0; while (!feof(file)) { char *block = stack->length ? stack->items[0] : NULL; line = read_line(file); @@ -572,7 +599,26 @@ bool read_config(FILE *file, struct sway_config *config) { continue; } line_number++; - wlr_log(L_DEBUG, "Read line %d: %s", line_number, line); + wlr_log(WLR_DEBUG, "Read line %d: %s", line_number, line); + + if (reading_main_config) { + size_t length = strlen(line); + + if (read + length > config_size) { + wlr_log(WLR_ERROR, "Config file changed during reading"); + list_foreach(stack, free); + list_free(stack); + free(line); + return false; + } + + strcpy(this_config + read, line); + if (line_number != 1) { + this_config[read - 1] = '\n'; + } + read += length + 1; + } + line = strip_whitespace(line); if (line[0] == '#') { free(line); @@ -586,15 +632,16 @@ bool read_config(FILE *file, struct sway_config *config) { line_number); if (brace_detected > 0) { line_number += brace_detected; - wlr_log(L_DEBUG, "Detected open brace on line %d", line_number); + wlr_log(WLR_DEBUG, "Detected open brace on line %d", line_number); } char *expanded = expand_line(block, line, brace_detected > 0); if (!expanded) { list_foreach(stack, free); list_free(stack); + free(line); return false; } - wlr_log(L_DEBUG, "Expanded line: %s", expanded); + wlr_log(WLR_DEBUG, "Expanded line: %s", expanded); struct cmd_results *res; if (block && strcmp(block, "<commands>") == 0) { // Special case @@ -606,23 +653,23 @@ bool read_config(FILE *file, struct sway_config *config) { switch(res->status) { case CMD_FAILURE: case CMD_INVALID: - wlr_log(L_ERROR, "Error on line %i '%s': %s (%s)", line_number, - line, res->error, config->current_config); + wlr_log(WLR_ERROR, "Error on line %i '%s': %s (%s)", line_number, + line, res->error, config->current_config_path); success = false; break; case CMD_DEFER: - wlr_log(L_DEBUG, "Deferring command `%s'", line); + wlr_log(WLR_DEBUG, "Deferring command `%s'", line); list_add(config->cmd_queue, strdup(line)); break; case CMD_BLOCK_COMMANDS: - wlr_log(L_DEBUG, "Entering commands block"); + wlr_log(WLR_DEBUG, "Entering commands block"); list_insert(stack, 0, "<commands>"); break; case CMD_BLOCK: - wlr_log(L_DEBUG, "Entering block '%s'", res->input); + wlr_log(WLR_DEBUG, "Entering block '%s'", res->input); list_insert(stack, 0, strdup(res->input)); if (strcmp(res->input, "bar") == 0) { config->current_bar = NULL; @@ -631,7 +678,7 @@ bool read_config(FILE *file, struct sway_config *config) { case CMD_BLOCK_END: if (!block) { - wlr_log(L_DEBUG, "Unmatched '}' on line %i", line_number); + wlr_log(WLR_DEBUG, "Unmatched '}' on line %i", line_number); success = false; break; } @@ -639,7 +686,7 @@ bool read_config(FILE *file, struct sway_config *config) { config->current_bar = NULL; } - wlr_log(L_DEBUG, "Exiting block '%s'", block); + wlr_log(WLR_DEBUG, "Exiting block '%s'", block); list_del(stack, 0); free(block); memset(&config->handler_context, 0, @@ -682,7 +729,7 @@ char *do_var_replacement(char *str) { int vvlen = strlen(var->value); char *newstr = malloc(strlen(str) - vnlen + vvlen + 1); if (!newstr) { - wlr_log(L_ERROR, + wlr_log(WLR_ERROR, "Unable to allocate replacement " "during variable expansion"); break; @@ -744,6 +791,6 @@ void config_update_font_height(bool recalculate) { } if (config->font_height != prev_max_height) { - arrange_and_commit(&root_container); + arrange_windows(&root_container); } } diff --git a/sway/config/bar.c b/sway/config/bar.c index ee062c6a..3a74331e 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -16,10 +16,10 @@ #include "log.h" static void terminate_swaybar(pid_t pid) { - wlr_log(L_DEBUG, "Terminating swaybar %d", pid); + wlr_log(WLR_DEBUG, "Terminating swaybar %d", pid); int ret = kill(-pid, SIGTERM); if (ret != 0) { - wlr_log_errno(L_ERROR, "Unable to terminate swaybar %d", pid); + wlr_log_errno(WLR_ERROR, "Unable to terminate swaybar %d", pid); } else { int status; waitpid(pid, &status, 0); @@ -167,7 +167,7 @@ void invoke_swaybar(struct bar_config *bar) { // Pipe to communicate errors int filedes[2]; if (pipe(filedes) == -1) { - wlr_log(L_ERROR, "Pipe setup failed! Cannot fork into bar"); + wlr_log(WLR_ERROR, "Pipe setup failed! Cannot fork into bar"); return; } @@ -197,17 +197,17 @@ void invoke_swaybar(struct bar_config *bar) { execvp(cmd[0], cmd); exit(1); } - wlr_log(L_DEBUG, "Spawned swaybar %d", bar->pid); + wlr_log(WLR_DEBUG, "Spawned swaybar %d", bar->pid); close(filedes[0]); size_t len; if (read(filedes[1], &len, sizeof(size_t)) == sizeof(size_t)) { char *buf = malloc(len); if(!buf) { - wlr_log(L_ERROR, "Cannot allocate error string"); + wlr_log(WLR_ERROR, "Cannot allocate error string"); return; } if (read(filedes[1], buf, len)) { - wlr_log(L_ERROR, "%s", buf); + wlr_log(WLR_ERROR, "%s", buf); } free(buf); } @@ -244,7 +244,7 @@ void load_swaybars() { if (bar->pid != 0) { terminate_swaybar(bar->pid); } - wlr_log(L_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); + wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); invoke_swaybar(bar); } } diff --git a/sway/config/input.c b/sway/config/input.c index 17303ccc..8d687a6d 100644 --- a/sway/config/input.c +++ b/sway/config/input.c @@ -8,17 +8,18 @@ struct input_config *new_input_config(const char* identifier) { struct input_config *input = calloc(1, sizeof(struct input_config)); if (!input) { - wlr_log(L_DEBUG, "Unable to allocate input config"); + wlr_log(WLR_DEBUG, "Unable to allocate input config"); return NULL; } - wlr_log(L_DEBUG, "new_input_config(%s)", identifier); + wlr_log(WLR_DEBUG, "new_input_config(%s)", identifier); if (!(input->identifier = strdup(identifier))) { free(input); - wlr_log(L_DEBUG, "Unable to allocate input config"); + wlr_log(WLR_DEBUG, "Unable to allocate input config"); return NULL; } input->tap = INT_MIN; + input->tap_button_map = INT_MIN; input->drag_lock = INT_MIN; input->dwt = INT_MIN; input->send_events = INT_MIN; @@ -27,6 +28,7 @@ struct input_config *new_input_config(const char* identifier) { input->natural_scroll = INT_MIN; input->accel_profile = INT_MIN; input->pointer_accel = FLT_MIN; + input->scroll_button = INT_MIN; input->scroll_method = INT_MIN; input->left_handed = INT_MIN; input->repeat_delay = INT_MIN; @@ -70,12 +72,18 @@ void merge_input_config(struct input_config *dst, struct input_config *src) { if (src->scroll_method != INT_MIN) { dst->scroll_method = src->scroll_method; } + if (src->scroll_button != INT_MIN) { + dst->scroll_button = src->scroll_button; + } if (src->send_events != INT_MIN) { dst->send_events = src->send_events; } if (src->tap != INT_MIN) { dst->tap = src->tap; } + if (src->tap_button_map != INT_MIN) { + dst->tap_button_map = src->tap_button_map; + } if (src->xkb_layout) { free(dst->xkb_layout); dst->xkb_layout = strdup(src->xkb_layout); @@ -112,7 +120,7 @@ void merge_input_config(struct input_config *dst, struct input_config *src) { struct input_config *copy_input_config(struct input_config *ic) { struct input_config *copy = calloc(1, sizeof(struct input_config)); if (copy == NULL) { - wlr_log(L_ERROR, "could not allocate input config"); + wlr_log(WLR_ERROR, "could not allocate input config"); return NULL; } merge_input_config(copy, ic); diff --git a/sway/config/output.c b/sway/config/output.c index 648ded27..1bf9e5f1 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -90,7 +90,7 @@ static void set_mode(struct wlr_output *output, int width, int height, float refresh_rate) { int mhz = (int)(refresh_rate * 1000); if (wl_list_empty(&output->modes)) { - wlr_log(L_DEBUG, "Assigning custom mode to %s", output->name); + wlr_log(WLR_DEBUG, "Assigning custom mode to %s", output->name); wlr_output_set_custom_mode(output, width, height, mhz); return; } @@ -106,9 +106,9 @@ static void set_mode(struct wlr_output *output, int width, int height, } } if (!best) { - wlr_log(L_ERROR, "Configured mode for %s not available", output->name); + wlr_log(WLR_ERROR, "Configured mode for %s not available", output->name); } else { - wlr_log(L_DEBUG, "Assigning configured mode to %s", output->name); + wlr_log(WLR_DEBUG, "Assigning configured mode to %s", output->name); wlr_output_set_mode(output, best); } } @@ -116,7 +116,7 @@ static void set_mode(struct wlr_output *output, int width, int height, void terminate_swaybg(pid_t pid) { int ret = kill(pid, SIGTERM); if (ret != 0) { - wlr_log(L_ERROR, "Unable to terminate swaybg [pid: %d]", pid); + wlr_log(WLR_ERROR, "Unable to terminate swaybg [pid: %d]", pid); } else { int status; waitpid(pid, &status, 0); @@ -144,22 +144,22 @@ void apply_output_config(struct output_config *oc, struct sway_container *output } if (oc && oc->width > 0 && oc->height > 0) { - wlr_log(L_DEBUG, "Set %s mode to %dx%d (%f GHz)", oc->name, oc->width, + wlr_log(WLR_DEBUG, "Set %s mode to %dx%d (%f GHz)", oc->name, oc->width, oc->height, oc->refresh_rate); set_mode(wlr_output, oc->width, oc->height, oc->refresh_rate); } if (oc && oc->scale > 0) { - wlr_log(L_DEBUG, "Set %s scale to %f", oc->name, oc->scale); + wlr_log(WLR_DEBUG, "Set %s scale to %f", oc->name, oc->scale); wlr_output_set_scale(wlr_output, oc->scale); } if (oc && oc->transform >= 0) { - wlr_log(L_DEBUG, "Set %s transform to %d", oc->name, oc->transform); + wlr_log(WLR_DEBUG, "Set %s transform to %d", oc->name, oc->transform); wlr_output_set_transform(wlr_output, oc->transform); } // Find position for it if (oc && (oc->x != -1 || oc->y != -1)) { - wlr_log(L_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y); + wlr_log(WLR_DEBUG, "Set %s position to %d, %d", oc->name, oc->x, oc->y); wlr_output_layout_add(output_layout, wlr_output, oc->x, oc->y); } else { wlr_output_layout_add_auto(output_layout, wlr_output); @@ -187,7 +187,7 @@ void apply_output_config(struct output_config *oc, struct sway_container *output terminate_swaybg(output->sway_output->bg_pid); } - wlr_log(L_DEBUG, "Setting background for output %d to %s", + wlr_log(WLR_DEBUG, "Setting background for output %d to %s", output_i, oc->background); size_t len = snprintf(NULL, 0, "%s %d %s %s", @@ -195,28 +195,30 @@ void apply_output_config(struct output_config *oc, struct sway_container *output output_i, oc->background, oc->background_option); char *command = malloc(len + 1); if (!command) { - wlr_log(L_DEBUG, "Unable to allocate swaybg command"); + wlr_log(WLR_DEBUG, "Unable to allocate swaybg command"); return; } snprintf(command, len + 1, "%s %d %s %s", config->swaybg_command ? config->swaybg_command : "swaybg", output_i, oc->background, oc->background_option); - wlr_log(L_DEBUG, "-> %s", command); + wlr_log(WLR_DEBUG, "-> %s", command); char *const cmd[] = { "sh", "-c", command, NULL }; output->sway_output->bg_pid = fork(); if (output->sway_output->bg_pid == 0) { execvp(cmd[0], cmd); + } else { + free(command); } } if (oc && oc->dpms_state != DPMS_IGNORE) { switch (oc->dpms_state) { case DPMS_ON: - wlr_log(L_DEBUG, "Turning on screen"); + wlr_log(WLR_DEBUG, "Turning on screen"); wlr_output_enable(wlr_output, true); break; case DPMS_OFF: - wlr_log(L_DEBUG, "Turning off screen"); + wlr_log(WLR_DEBUG, "Turning off screen"); wlr_output_enable(wlr_output, false); break; case DPMS_IGNORE: diff --git a/sway/config/seat.c b/sway/config/seat.c index bd8b45c8..83dac4c0 100644 --- a/sway/config/seat.c +++ b/sway/config/seat.c @@ -7,11 +7,11 @@ struct seat_config *new_seat_config(const char* name) { struct seat_config *seat = calloc(1, sizeof(struct seat_config)); if (!seat) { - wlr_log(L_DEBUG, "Unable to allocate seat config"); + wlr_log(WLR_DEBUG, "Unable to allocate seat config"); return NULL; } - wlr_log(L_DEBUG, "new_seat_config(%s)", name); + wlr_log(WLR_DEBUG, "new_seat_config(%s)", name); seat->name = strdup(name); if (!sway_assert(seat->name, "could not allocate name for seat")) { free(seat); @@ -34,7 +34,7 @@ struct seat_attachment_config *seat_attachment_config_new() { struct seat_attachment_config *attachment = calloc(1, sizeof(struct seat_attachment_config)); if (!attachment) { - wlr_log(L_DEBUG, "cannot allocate attachment config"); + wlr_log(WLR_DEBUG, "cannot allocate attachment config"); return NULL; } return attachment; diff --git a/sway/criteria.c b/sway/criteria.c index d9f09ecc..e2b248de 100644 --- a/sway/criteria.c +++ b/sway/criteria.c @@ -37,7 +37,7 @@ void criteria_destroy(struct criteria *criteria) { pcre_free(criteria->con_mark); pcre_free(criteria->window_role); free(criteria->workspace); - + free(criteria->cmdlist); free(criteria->raw); free(criteria); } @@ -46,6 +46,31 @@ static int regex_cmp(const char *item, const pcre *regex) { return pcre_exec(regex, NULL, item, strlen(item), 0, 0, NULL, 0); } +static int cmp_urgent(const void *_a, const void *_b) { + struct sway_view *a = *(void **)_a; + struct sway_view *b = *(void **)_b; + + if (a->urgent.tv_sec < b->urgent.tv_sec) { + return -1; + } else if (a->urgent.tv_sec > b->urgent.tv_sec) { + return 1; + } + if (a->urgent.tv_nsec < b->urgent.tv_nsec) { + return -1; + } else if (a->urgent.tv_nsec > b->urgent.tv_nsec) { + return 1; + } + return 0; +} + +static void find_urgent_iterator(struct sway_container *swayc, void *data) { + if (swayc->type != C_VIEW || !view_is_urgent(swayc->sway_view)) { + return; + } + list_t *urgent_views = data; + list_add(urgent_views, swayc->sway_view); +} + static bool criteria_matches_view(struct criteria *criteria, struct sway_view *view) { if (criteria->title) { @@ -133,8 +158,23 @@ static bool criteria_matches_view(struct criteria *criteria, } if (criteria->urgent) { - // TODO - return false; + if (!view_is_urgent(view)) { + return false; + } + list_t *urgent_views = create_list(); + container_for_each_descendant_dfs(&root_container, + find_urgent_iterator, urgent_views); + list_stable_sort(urgent_views, cmp_urgent); + struct sway_view *target; + if (criteria->urgent == 'o') { // oldest + target = urgent_views->items[0]; + } else { // latest + target = urgent_views->items[urgent_views->length - 1]; + } + list_free(urgent_views); + if (view != target) { + return false; + } } if (criteria->workspace) { @@ -507,7 +547,7 @@ struct criteria *criteria_parse(char *raw, char **error_arg) { } unescape(value); } - wlr_log(L_DEBUG, "Found pair: %s=%s", name, value); + wlr_log(WLR_DEBUG, "Found pair: %s=%s", name, value); if (!parse_token(criteria, name, value)) { *error_arg = error; goto cleanup; diff --git a/sway/desktop/desktop.c b/sway/desktop/desktop.c index e495790c..6575519d 100644 --- a/sway/desktop/desktop.c +++ b/sway/desktop/desktop.c @@ -13,3 +13,12 @@ void desktop_damage_surface(struct wlr_surface *surface, double lx, double ly, } } } + +void desktop_damage_whole_container(struct sway_container *con) { + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *cont = root_container.children->items[i]; + if (cont->type == C_OUTPUT) { + output_damage_whole_container(cont->sway_output, con); + } + } +} diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index c02ca26e..da17d0f2 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -9,7 +9,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_idle_inhibitor_v1 *inhibitor = wl_container_of(listener, inhibitor, destroy); - wlr_log(L_DEBUG, "Sway idle inhibitor destroyed"); + wlr_log(WLR_DEBUG, "Sway idle inhibitor destroyed"); wl_list_remove(&inhibitor->link); wl_list_remove(&inhibitor->destroy.link); idle_inhibit_v1_check_active(inhibitor->manager); @@ -20,7 +20,7 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { struct wlr_idle_inhibitor_v1 *wlr_inhibitor = data; struct sway_idle_inhibit_manager_v1 *manager = wl_container_of(listener, manager, new_idle_inhibitor_v1); - wlr_log(L_DEBUG, "New sway idle inhibitor"); + wlr_log(WLR_DEBUG, "New sway idle inhibitor"); struct sway_idle_inhibitor_v1 *inhibitor = calloc(1, sizeof(struct sway_idle_inhibitor_v1)); @@ -67,6 +67,7 @@ struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create( manager->wlr_manager = wlr_idle_inhibit_v1_create(wl_display); if (!manager->wlr_manager) { + free(manager); return NULL; } manager->idle = idle; diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index de1fe349..a7d96717 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c @@ -12,7 +12,6 @@ #include "sway/layers.h" #include "sway/output.h" #include "sway/server.h" -#include "sway/tree/arrange.h" #include "sway/tree/layout.h" #include "log.h" @@ -174,9 +173,9 @@ void arrange_layers(struct sway_output *output) { if (memcmp(&usable_area, &output->usable_area, sizeof(struct wlr_box)) != 0) { - wlr_log(L_DEBUG, "Usable area changed, rearranging output"); + wlr_log(WLR_DEBUG, "Usable area changed, rearranging output"); memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); - arrange_and_commit(output->swayc); + container_set_dirty(output->swayc); } // Arrange non-exlusive surfaces from top->bottom @@ -269,7 +268,7 @@ static void unmap(struct sway_layer_surface *sway_layer) { static void handle_destroy(struct wl_listener *listener, void *data) { struct sway_layer_surface *sway_layer = wl_container_of(listener, sway_layer, destroy); - wlr_log(L_DEBUG, "Layer surface destroyed (%s)", + wlr_log(WLR_DEBUG, "Layer surface destroyed (%s)", sway_layer->layer_surface->namespace); if (sway_layer->layer_surface->mapped) { unmap(sway_layer); @@ -316,7 +315,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { struct wlr_layer_surface *layer_surface = data; struct sway_server *server = wl_container_of(listener, server, layer_shell_surface); - wlr_log(L_DEBUG, "new layer surface: namespace %s layer %d anchor %d " + wlr_log(WLR_DEBUG, "new layer surface: namespace %s layer %d anchor %d " "size %dx%d margin %d,%d,%d,%d", layer_surface->namespace, layer_surface->layer, layer_surface->layer, layer_surface->client_pending.desired_width, @@ -326,12 +325,6 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { layer_surface->client_pending.margin.bottom, layer_surface->client_pending.margin.left); - struct sway_layer_surface *sway_layer = - calloc(1, sizeof(struct sway_layer_surface)); - if (!sway_layer) { - return; - } - if (!layer_surface->output) { // Assign last active output struct sway_container *output = NULL; @@ -353,6 +346,12 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { layer_surface->output = output->sway_output->wlr_output; } + struct sway_layer_surface *sway_layer = + calloc(1, sizeof(struct sway_layer_surface)); + if (!sway_layer) { + return; + } + sway_layer->surface_commit.notify = handle_surface_commit; wl_signal_add(&layer_surface->surface->events.commit, &sway_layer->surface_commit); diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 8b50bc44..a9808406 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -204,11 +204,11 @@ bool output_has_opaque_lockscreen(struct sway_output *output, }; pixman_region32_t surface_opaque_box; pixman_region32_init(&surface_opaque_box); - pixman_region32_copy(&surface_opaque_box, &wlr_surface->current.opaque); + pixman_region32_copy(&surface_opaque_box, &wlr_surface->opaque_region); pixman_region32_translate(&surface_opaque_box, - sway_layer_surface->geo.x, sway_layer_surface->geo.y); - bool contains = pixman_region32_contains_rectangle( - &wlr_surface->current.opaque, &output_box); + sway_layer_surface->geo.x, sway_layer_surface->geo.y); + bool contains = pixman_region32_contains_rectangle(&surface_opaque_box, + &output_box); pixman_region32_fini(&surface_opaque_box); if (contains) { return true; @@ -492,19 +492,21 @@ static void handle_destroy(struct wl_listener *listener, void *data) { output->wlr_output->data = NULL; free(output); - arrange_and_commit(&root_container); + arrange_windows(&root_container); } static void handle_mode(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, mode); arrange_layers(output); - arrange_and_commit(output->swayc); + arrange_windows(output->swayc); + transaction_commit_dirty(); } static void handle_transform(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, transform); arrange_layers(output); - arrange_and_commit(output->swayc); + arrange_windows(output->swayc); + transaction_commit_dirty(); } static void handle_scale_iterator(struct sway_container *view, void *data) { @@ -515,7 +517,8 @@ static void handle_scale(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, scale); arrange_layers(output); container_descendants(output->swayc, C_VIEW, handle_scale_iterator, NULL); - arrange_and_commit(output->swayc); + arrange_windows(output->swayc); + transaction_commit_dirty(); } struct sway_output *output_from_wlr_output(struct wlr_output *wlr_output) { @@ -525,7 +528,7 @@ struct sway_output *output_from_wlr_output(struct wlr_output *wlr_output) { void handle_new_output(struct wl_listener *listener, void *data) { struct sway_server *server = wl_container_of(listener, server, new_output); struct wlr_output *wlr_output = data; - wlr_log(L_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); + wlr_log(WLR_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); struct sway_output *output = calloc(1, sizeof(struct sway_output)); if (!output) { @@ -584,5 +587,6 @@ void output_enable(struct sway_output *output) { output->damage_destroy.notify = damage_handle_destroy; arrange_layers(output); - arrange_and_commit(&root_container); + arrange_windows(&root_container); + transaction_commit_dirty(); } diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 43948f29..4c85e516 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -15,6 +15,7 @@ #include <wlr/util/region.h> #include "log.h" #include "sway/config.h" +#include "sway/debug.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/layers.h" @@ -255,6 +256,10 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, render_view_surfaces(view, output, damage, view->swayc->alpha); } + if (view->using_csd) { + return; + } + struct wlr_box box; float output_scale = output->wlr_output->scale; float color[4]; @@ -542,9 +547,6 @@ static void render_container(struct sway_output *output, static void render_container_simple(struct sway_output *output, pixman_region32_t *damage, struct sway_container *con, bool parent_focused) { - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - for (int i = 0; i < con->current.children->length; ++i) { struct sway_container *child = con->current.children->items[i]; @@ -555,11 +557,15 @@ static void render_container_simple(struct sway_output *output, struct wlr_texture *marks_texture; struct sway_container_state *state = &child->current; - if (focus == child || parent_focused) { + if (view_is_urgent(view)) { + colors = &config->border_colors.urgent; + title_texture = child->title_urgent; + marks_texture = view->marks_urgent; + } else if (state->focused || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view->marks_focused; - } else if (seat_get_focus_inactive(seat, con) == child) { + } else if (con->current.focused_inactive_child == child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = view->marks_focused_inactive; @@ -569,17 +575,19 @@ static void render_container_simple(struct sway_output *output, marks_texture = view->marks_unfocused; } - if (state->border == B_NORMAL) { - render_titlebar(output, damage, child, state->swayc_x, - state->swayc_y, state->swayc_width, colors, - title_texture, marks_texture); - } else { - render_top_border(output, damage, child, colors); + if (!view->using_csd) { + if (state->border == B_NORMAL) { + render_titlebar(output, damage, child, state->swayc_x, + state->swayc_y, state->swayc_width, colors, + title_texture, marks_texture); + } else { + render_top_border(output, damage, child, colors); + } } render_view(output, damage, child, colors); } else { render_container(output, damage, child, - parent_focused || focus == child); + parent_focused || child->current.focused); } } } @@ -593,26 +601,34 @@ static void render_container_tabbed(struct sway_output *output, if (!con->current.children->length) { return; } - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *current = seat_get_active_current_child(seat, con); - struct border_colors *current_colors = &config->border_colors.unfocused; struct sway_container_state *pstate = &con->current; + struct sway_container *current = pstate->focused_inactive_child; + struct border_colors *current_colors = &config->border_colors.unfocused; + + double width_gap_adjustment = 2 * pstate->current_gaps; + int tab_width = + (pstate->swayc_width - width_gap_adjustment) / pstate->children->length; // Render tabs - for (int i = 0; i < con->current.children->length; ++i) { - struct sway_container *child = con->current.children->items[i]; + for (int i = 0; i < pstate->children->length; ++i) { + struct sway_container *child = pstate->children->items[i]; struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; struct sway_container_state *cstate = &child->current; struct border_colors *colors; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; - - if (focus == child || parent_focused) { + bool urgent = view ? + view_is_urgent(view) : container_has_urgent_child(child); + + if (urgent) { + colors = &config->border_colors.urgent; + title_texture = child->title_urgent; + marks_texture = view ? view->marks_urgent : NULL; + } else if (cstate->focused || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view ? view->marks_focused : NULL; - } else if (child == current) { + } else if (child == pstate->focused_inactive_child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = view ? view->marks_focused_inactive : NULL; @@ -622,11 +638,12 @@ static void render_container_tabbed(struct sway_output *output, marks_texture = view ? view->marks_unfocused : NULL; } - int tab_width = pstate->swayc_width / pstate->children->length; - int x = pstate->swayc_x + tab_width * i; + int x = cstate->swayc_x + tab_width * i; + // Make last tab use the remaining width of the parent if (i == pstate->children->length - 1) { - tab_width = pstate->swayc_width - tab_width * i; + tab_width = + pstate->swayc_width - width_gap_adjustment - tab_width * i; } render_titlebar(output, damage, child, x, cstate->swayc_y, tab_width, @@ -638,13 +655,11 @@ static void render_container_tabbed(struct sway_output *output, } // Render surface and left/right/bottom borders - if (current) { - if (current->type == C_VIEW) { - render_view(output, damage, current, current_colors); - } else { - render_container(output, damage, current, - parent_focused || current == focus); - } + if (current->type == C_VIEW) { + render_view(output, damage, current, current_colors); + } else { + render_container(output, damage, current, + parent_focused || current->current.focused); } } @@ -657,26 +672,32 @@ static void render_container_stacked(struct sway_output *output, if (!con->current.children->length) { return; } - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - struct sway_container *current = seat_get_active_current_child(seat, con); - struct border_colors *current_colors = &config->border_colors.unfocused; struct sway_container_state *pstate = &con->current; + struct sway_container *current = pstate->focused_inactive_child; + struct border_colors *current_colors = &config->border_colors.unfocused; + + size_t titlebar_height = container_titlebar_height(); // Render titles - for (int i = 0; i < con->current.children->length; ++i) { - struct sway_container *child = con->current.children->items[i]; + for (int i = 0; i < pstate->children->length; ++i) { + struct sway_container *child = pstate->children->items[i]; struct sway_view *view = child->type == C_VIEW ? child->sway_view : NULL; struct sway_container_state *cstate = &child->current; struct border_colors *colors; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; - - if (focus == child || parent_focused) { + bool urgent = view ? + view_is_urgent(view) : container_has_urgent_child(child); + + if (urgent) { + colors = &config->border_colors.urgent; + title_texture = child->title_urgent; + marks_texture = view ? view->marks_urgent : NULL; + } else if (cstate->focused || parent_focused) { colors = &config->border_colors.focused; title_texture = child->title_focused; marks_texture = view ? view->marks_focused : NULL; - } else if (child == current) { + } else if (child == pstate->focused_inactive_child) { colors = &config->border_colors.focused_inactive; title_texture = child->title_focused_inactive; marks_texture = view ? view->marks_focused_inactive : NULL; @@ -686,7 +707,7 @@ static void render_container_stacked(struct sway_output *output, marks_texture = view ? view->marks_unfocused : NULL; } - int y = pstate->swayc_y + container_titlebar_height() * i; + int y = cstate->swayc_y + titlebar_height * i; render_titlebar(output, damage, child, cstate->swayc_x, y, cstate->swayc_width, colors, title_texture, marks_texture); @@ -696,13 +717,11 @@ static void render_container_stacked(struct sway_output *output, } // Render surface and left/right/bottom borders - if (current) { - if (current->type == C_VIEW) { - render_view(output, damage, current, current_colors); - } else { - render_container(output, damage, current, - parent_focused || current == focus); - } + if (current->type == C_VIEW) { + render_view(output, damage, current, current_colors); + } else { + render_container(output, damage, current, + parent_focused || current->current.focused); } } @@ -730,13 +749,15 @@ static void render_floating_container(struct sway_output *soutput, pixman_region32_t *damage, struct sway_container *con) { if (con->type == C_VIEW) { struct sway_view *view = con->sway_view; - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); struct border_colors *colors; struct wlr_texture *title_texture; struct wlr_texture *marks_texture; - if (focus == con) { + if (view_is_urgent(view)) { + colors = &config->border_colors.urgent; + title_texture = con->title_urgent; + marks_texture = view->marks_urgent; + } else if (con->current.focused) { colors = &config->border_colors.focused; title_texture = con->title_focused; marks_texture = view->marks_focused; @@ -746,12 +767,14 @@ static void render_floating_container(struct sway_output *soutput, marks_texture = view->marks_unfocused; } - if (con->current.border == B_NORMAL) { - render_titlebar(soutput, damage, con, con->current.swayc_x, - con->current.swayc_y, con->current.swayc_width, colors, - title_texture, marks_texture); - } else if (con->current.border != B_NONE) { - render_top_border(soutput, damage, con, colors); + if (!view->using_csd) { + if (con->current.border == B_NORMAL) { + render_titlebar(soutput, damage, con, con->current.swayc_x, + con->current.swayc_y, con->current.swayc_width, colors, + title_texture, marks_texture); + } else if (con->current.border != B_NONE) { + render_top_border(soutput, damage, con, colors); + } } render_view(soutput, damage, con, colors); } else { @@ -779,6 +802,8 @@ static void render_floating(struct sway_output *soutput, } } +const char *damage_debug = NULL; + void output_render(struct sway_output *output, struct timespec *when, pixman_region32_t *damage) { struct wlr_output *wlr_output = output->wlr_output; @@ -798,7 +823,6 @@ void output_render(struct sway_output *output, struct timespec *when, goto renderer_end; } - const char *damage_debug = getenv("SWAY_DAMAGE_DEBUG"); if (damage_debug != NULL) { if (strcmp(damage_debug, "highlight") == 0) { wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); @@ -837,7 +861,11 @@ void output_render(struct sway_output *output, struct timespec *when, } // TODO: handle views smaller than the output - render_view_surfaces(fullscreen_view, output, damage, 1.0f); + if (fullscreen_view->swayc->instructions->length) { + render_saved_view(fullscreen_view, output, damage, 1.0f); + } else { + render_view_surfaces(fullscreen_view, output, damage, 1.0f); + } if (fullscreen_view->type == SWAY_VIEW_XWAYLAND) { render_unmanaged(output, damage, @@ -858,9 +886,7 @@ void output_render(struct sway_output *output, struct timespec *when, render_layer(output, damage, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - struct sway_seat *seat = input_manager_current_seat(input_manager); - struct sway_container *focus = seat_get_focus(seat); - render_container(output, damage, workspace, focus == workspace); + render_container(output, damage, workspace, workspace->current.focused); render_floating(output, damage); render_unmanaged(output, damage, diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index 179af617..fcfb0b51 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -19,14 +19,14 @@ * How long we should wait for views to respond to the configure before giving * up and applying the transaction anyway. */ -#define TIMEOUT_MS 200 +int txn_timeout_ms = 200; /** * If enabled, sway will always wait for the transaction timeout before * applying it, rather than applying it when the views are ready. This allows us * to observe the rendered state while a transaction is in progress. */ -#define TRANSACTION_DEBUG false +bool txn_debug = false; struct sway_transaction { struct wl_event_source *timer; @@ -47,7 +47,7 @@ struct sway_transaction_instruction { bool ready; }; -struct sway_transaction *transaction_create() { +static struct sway_transaction *transaction_create() { struct sway_transaction *transaction = calloc(1, sizeof(struct sway_transaction)); transaction->instructions = create_list(); @@ -139,25 +139,18 @@ static void copy_pending_state(struct sway_container *container, state->children = create_list(); list_cat(state->children, container->children); } -} -static bool transaction_has_container(struct sway_transaction *transaction, - struct sway_container *container) { - for (int i = 0; i < transaction->instructions->length; ++i) { - struct sway_transaction_instruction *instruction = - transaction->instructions->items[i]; - if (instruction->container == container) { - return true; - } + struct sway_seat *seat = input_manager_current_seat(input_manager); + state->focused = seat_get_focus(seat) == container; + + if (container->type != C_VIEW) { + state->focused_inactive_child = + seat_get_active_child(seat, container); } - return false; } -void transaction_add_container(struct sway_transaction *transaction, +static void transaction_add_container(struct sway_transaction *transaction, struct sway_container *container) { - if (transaction_has_container(transaction, container)) { - return; - } struct sway_transaction_instruction *instruction = calloc(1, sizeof(struct sway_transaction_instruction)); instruction->transaction = transaction; @@ -175,7 +168,7 @@ void transaction_add_container(struct sway_transaction *transaction, * Apply a transaction to the "current" state of the tree. */ static void transaction_apply(struct sway_transaction *transaction) { - wlr_log(L_DEBUG, "Applying transaction %p", transaction); + wlr_log(WLR_DEBUG, "Applying transaction %p", transaction); if (server.debug_txn_timings) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -186,7 +179,7 @@ static void transaction_apply(struct sway_transaction *transaction) { float ms_waiting = (now.tv_sec - commit->tv_sec) * 1000 + (now.tv_nsec - commit->tv_nsec) / 1000000.0; float ms_total = ms_arranging + ms_waiting; - wlr_log(L_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, " + wlr_log(WLR_DEBUG, "Transaction %p: %.1fms arranging, %.1fms waiting, " "%.1fms total (%.1f frames if 60Hz)", transaction, ms_arranging, ms_waiting, ms_total, ms_total / (1000.0f / 60)); } @@ -210,10 +203,12 @@ static void transaction_apply(struct sway_transaction *transaction) { .width = instruction->state.swayc_width, .height = instruction->state.swayc_height, }; - for (int j = 0; j < root_container.children->length; ++j) { - struct sway_container *output = root_container.children->items[j]; - output_damage_box(output->sway_output, &old_box); - output_damage_box(output->sway_output, &new_box); + for (int j = 0; j < root_container.current.children->length; ++j) { + struct sway_container *output = root_container.current.children->items[j]; + if (output->sway_output) { + output_damage_box(output->sway_output, &old_box); + output_damage_box(output->sway_output, &new_box); + } } // There are separate children lists for each instruction state, the @@ -251,7 +246,7 @@ static void transaction_progress_queue() { static int handle_timeout(void *data) { struct sway_transaction *transaction = data; - wlr_log(L_DEBUG, "Transaction %p timed out (%li waiting)", + wlr_log(WLR_DEBUG, "Transaction %p timed out (%li waiting)", transaction, transaction->num_waiting); transaction->num_waiting = 0; transaction_progress_queue(); @@ -285,8 +280,8 @@ static bool should_configure(struct sway_container *con, return true; } -void transaction_commit(struct sway_transaction *transaction) { - wlr_log(L_DEBUG, "Transaction %p committing with %i instructions", +static void transaction_commit(struct sway_transaction *transaction) { + wlr_log(WLR_DEBUG, "Transaction %p committing with %i instructions", transaction, transaction->instructions->length); transaction->num_waiting = 0; for (int i = 0; i < transaction->instructions->length; ++i) { @@ -319,7 +314,7 @@ void transaction_commit(struct sway_transaction *transaction) { } else { // There are no other transactions in progress, and this one has nothing // to wait for, so we can skip the queue. - wlr_log(L_DEBUG, "Transaction %p has nothing to wait for", transaction); + wlr_log(WLR_DEBUG, "Transaction %p has nothing to wait for", transaction); transaction_apply(transaction); transaction_destroy(transaction); idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); @@ -330,7 +325,7 @@ void transaction_commit(struct sway_transaction *transaction) { // Set up a timer which the views must respond within transaction->timer = wl_event_loop_add_timer(server.wl_event_loop, handle_timeout, transaction); - wl_event_source_timer_update(transaction->timer, TIMEOUT_MS); + wl_event_source_timer_update(transaction->timer, txn_timeout_ms); } // The debug tree shows the pending/live tree. Here is a good place to @@ -350,7 +345,7 @@ static void set_instruction_ready( struct timespec *start = &transaction->commit_time; float ms = (now.tv_sec - start->tv_sec) * 1000 + (now.tv_nsec - start->tv_nsec) / 1000000.0; - wlr_log(L_DEBUG, "Transaction %p: %li/%li ready in %.1fms (%s)", + wlr_log(WLR_DEBUG, "Transaction %p: %li/%li ready in %.1fms (%s)", transaction, transaction->num_configures - transaction->num_waiting + 1, transaction->num_configures, ms, @@ -361,11 +356,11 @@ static void set_instruction_ready( // If all views are ready, apply the transaction. // If the transaction has timed out then its num_waiting will be 0 already. if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { -#if !TRANSACTION_DEBUG - wlr_log(L_DEBUG, "Transaction %p is ready", transaction); - wl_event_source_timer_update(transaction->timer, 0); - transaction_progress_queue(); -#endif + if (!txn_debug) { + wlr_log(WLR_DEBUG, "Transaction %p is ready", transaction); + wl_event_source_timer_update(transaction->timer, 0); + transaction_progress_queue(); + } } } @@ -418,3 +413,17 @@ struct wlr_texture *transaction_get_saved_texture(struct sway_view *view, *height = instruction->saved_buffer_height; return instruction->saved_buffer->texture; } + +void transaction_commit_dirty(void) { + if (!server.dirty_containers->length) { + return; + } + struct sway_transaction *transaction = transaction_create(); + for (int i = 0; i < server.dirty_containers->length; ++i) { + struct sway_container *container = server.dirty_containers->items[i]; + transaction_add_container(transaction, container); + container->dirty = false; + } + server.dirty_containers->length = 0; + transaction_commit(transaction); +} diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index ac35a8d1..98c16faf 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c @@ -45,6 +45,24 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { view_child_destroy(&popup->child); } +static void popup_unconstrain(struct sway_xdg_popup *popup) { + struct sway_view *view = popup->child.view; + struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; + + struct sway_container *output = container_parent(view->swayc, C_OUTPUT); + + // the output box expressed in the coordinate system of the toplevel parent + // of the popup + struct wlr_box output_toplevel_sx_box = { + .x = output->x - view->x, + .y = output->y - view->y, + .width = output->width, + .height = output->height, + }; + + wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); +} + static struct sway_xdg_popup *popup_create( struct wlr_xdg_popup *wlr_popup, struct sway_view *view) { struct wlr_xdg_surface *xdg_surface = wlr_popup->base; @@ -55,12 +73,15 @@ static struct sway_xdg_popup *popup_create( return NULL; } view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); + popup->wlr_xdg_surface = xdg_surface; wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); popup->new_popup.notify = popup_handle_new_popup; wl_signal_add(&xdg_surface->events.destroy, &popup->destroy); popup->destroy.notify = popup_handle_destroy; + popup_unconstrain(popup); + return popup; } @@ -223,7 +244,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, e->fullscreen); struct sway_container *output = container_parent(view->swayc, C_OUTPUT); - arrange_and_commit(output); + arrange_windows(output); + transaction_commit_dirty(); } static void handle_unmap(struct wl_listener *listener, void *data) { @@ -260,10 +282,11 @@ static void handle_map(struct wl_listener *listener, void *data) { if (xdg_surface->toplevel->client_pending.fullscreen) { view_set_fullscreen(view, true); struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_and_commit(ws); + arrange_windows(ws); } else { - arrange_and_commit(view->swayc->parent); + arrange_windows(view->swayc->parent); } + transaction_commit_dirty(); xdg_shell_view->commit.notify = handle_commit; wl_signal_add(&xdg_surface->surface->events.commit, @@ -304,11 +327,11 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { struct wlr_xdg_surface *xdg_surface = data; if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - wlr_log(L_DEBUG, "New xdg_shell popup"); + wlr_log(WLR_DEBUG, "New xdg_shell popup"); return; } - wlr_log(L_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'", + wlr_log(WLR_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'", xdg_surface->toplevel->title, xdg_surface->toplevel->app_id); wlr_xdg_surface_ping(xdg_surface); diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index 56bbb244..4d76f0a7 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c @@ -44,6 +44,24 @@ static void popup_handle_destroy(struct wl_listener *listener, void *data) { view_child_destroy(&popup->child); } +static void popup_unconstrain(struct sway_xdg_popup_v6 *popup) { + struct sway_view *view = popup->child.view; + struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_xdg_surface_v6->popup; + + struct sway_container *output = container_parent(view->swayc, C_OUTPUT); + + // the output box expressed in the coordinate system of the toplevel parent + // of the popup + struct wlr_box output_toplevel_sx_box = { + .x = output->x - view->x, + .y = output->y - view->y, + .width = output->width, + .height = output->height, + }; + + wlr_xdg_popup_v6_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); +} + static struct sway_xdg_popup_v6 *popup_create( struct wlr_xdg_popup_v6 *wlr_popup, struct sway_view *view) { struct wlr_xdg_surface_v6 *xdg_surface = wlr_popup->base; @@ -54,12 +72,15 @@ static struct sway_xdg_popup_v6 *popup_create( return NULL; } view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface); + popup->wlr_xdg_surface_v6 = xdg_surface; wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup); popup->new_popup.notify = popup_handle_new_popup; wl_signal_add(&xdg_surface->events.destroy, &popup->destroy); popup->destroy.notify = popup_handle_destroy; + popup_unconstrain(popup); + return popup; } @@ -218,7 +239,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, e->fullscreen); struct sway_container *output = container_parent(view->swayc, C_OUTPUT); - arrange_and_commit(output); + arrange_windows(output); + transaction_commit_dirty(); } static void handle_unmap(struct wl_listener *listener, void *data) { @@ -255,10 +277,11 @@ static void handle_map(struct wl_listener *listener, void *data) { if (xdg_surface->toplevel->client_pending.fullscreen) { view_set_fullscreen(view, true); struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_and_commit(ws); + arrange_windows(ws); } else { - arrange_and_commit(view->swayc->parent); + arrange_windows(view->swayc->parent); } + transaction_commit_dirty(); xdg_shell_v6_view->commit.notify = handle_commit; wl_signal_add(&xdg_surface->surface->events.commit, @@ -295,11 +318,11 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { struct wlr_xdg_surface_v6 *xdg_surface = data; if (xdg_surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { - wlr_log(L_DEBUG, "New xdg_shell_v6 popup"); + wlr_log(WLR_DEBUG, "New xdg_shell_v6 popup"); return; } - wlr_log(L_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'", + wlr_log(WLR_DEBUG, "New xdg_shell_v6 toplevel title='%s' app_id='%s'", xdg_surface->toplevel->title, xdg_surface->toplevel->app_id); wlr_xdg_surface_v6_ping(xdg_surface); diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index b2874cfe..9df7977d 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c @@ -119,7 +119,7 @@ static struct sway_xwayland_unmanaged *create_unmanaged( struct sway_xwayland_unmanaged *surface = calloc(1, sizeof(struct sway_xwayland_unmanaged)); if (surface == NULL) { - wlr_log(L_ERROR, "Allocation failed"); + wlr_log(WLR_ERROR, "Allocation failed"); return NULL; } @@ -246,6 +246,14 @@ static bool wants_floating(struct sway_view *view) { return false; } +static bool has_client_side_decorations(struct sway_view *view) { + if (xwayland_view_from_view(view) == NULL) { + return false; + } + struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface; + return surface->decorations != WLR_XWAYLAND_SURFACE_DECORATIONS_ALL; +} + static void _close(struct sway_view *view) { if (xwayland_view_from_view(view) == NULL) { return; @@ -269,6 +277,7 @@ static const struct sway_view_impl view_impl = { .set_tiled = set_tiled, .set_fullscreen = set_fullscreen, .wants_floating = wants_floating, + .has_client_side_decorations = has_client_side_decorations, .close = _close, .destroy = destroy, }; @@ -288,6 +297,10 @@ static void handle_commit(struct wl_listener *listener, void *data) { } view_damage_from(view); + + if (view->allow_request_urgent) { + view_set_urgent(view, (bool)xsurface->hints_urgency); + } } static void handle_unmap(struct wl_listener *listener, void *data) { @@ -324,10 +337,11 @@ static void handle_map(struct wl_listener *listener, void *data) { if (xsurface->fullscreen) { view_set_fullscreen(view, true); struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - arrange_and_commit(ws); + arrange_windows(ws); } else { - arrange_and_commit(view->swayc->parent); + arrange_windows(view->swayc->parent); } + transaction_commit_dirty(); } static void handle_destroy(struct wl_listener *listener, void *data) { @@ -383,7 +397,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) view_set_fullscreen(view, xsurface->fullscreen); struct sway_container *output = container_parent(view->swayc, C_OUTPUT); - arrange_and_commit(output); + arrange_windows(output); + transaction_commit_dirty(); } static void handle_set_title(struct wl_listener *listener, void *data) { @@ -432,12 +447,12 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { if (wlr_xwayland_surface_is_unmanaged(xsurface) || xsurface->override_redirect) { - wlr_log(L_DEBUG, "New xwayland unmanaged surface"); + wlr_log(WLR_DEBUG, "New xwayland unmanaged surface"); create_unmanaged(xsurface); return; } - wlr_log(L_DEBUG, "New xwayland surface title='%s' class='%s'", + wlr_log(WLR_DEBUG, "New xwayland surface title='%s' class='%s'", xsurface->title, xsurface->class); struct sway_xwayland_view *xwayland_view = @@ -490,7 +505,7 @@ void handle_xwayland_ready(struct wl_listener *listener, void *data) { xcb_connection_t *xcb_conn = xcb_connect(NULL, NULL); int err = xcb_connection_has_error(xcb_conn); if (err) { - wlr_log(L_ERROR, "XCB connect failed: %d", err); + wlr_log(WLR_ERROR, "XCB connect failed: %d", err); return; } @@ -509,7 +524,7 @@ void handle_xwayland_ready(struct wl_listener *listener, void *data) { free(reply); if (error != NULL) { - wlr_log(L_ERROR, "could not resolve atom %s, X11 error code %d", + wlr_log(WLR_ERROR, "could not resolve atom %s, X11 error code %d", atom_map[i], error->error_code); free(error); break; diff --git a/sway/input/cursor.c b/sway/input/cursor.c index a2f11557..7a9f3ed7 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -10,6 +10,7 @@ #include <wlr/types/wlr_idle.h> #include "list.h" #include "log.h" +#include "sway/desktop/transaction.h" #include "sway/input/cursor.h" #include "sway/layers.h" #include "sway/output.h" @@ -219,6 +220,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, struct sway_drag_icon *drag_icon = wlr_drag_icon->data; drag_icon_update_position(drag_icon); } + transaction_commit_dirty(); } static void handle_cursor_motion(struct wl_listener *listener, void *data) { @@ -278,6 +280,7 @@ void dispatch_cursor_button(struct sway_cursor *cursor, wlr_seat_pointer_notify_button(cursor->seat->wlr_seat, time_msec, button, state); + transaction_commit_dirty(); } static void handle_cursor_button(struct wl_listener *listener, void *data) { @@ -474,7 +477,7 @@ static void handle_request_set_cursor(struct wl_listener *listener, // TODO: check cursor mode if (focused_client == NULL || event->seat_client->client != focused_client) { - wlr_log(L_DEBUG, "denying request to set cursor from unfocused client"); + wlr_log(WLR_DEBUG, "denying request to set cursor from unfocused client"); return; } diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 98f7d7cf..0b7cb766 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -61,7 +61,7 @@ static char *get_device_identifier(struct wlr_input_device *device) { int len = snprintf(NULL, 0, fmt, vendor, product, name) + 1; char *identifier = malloc(len); if (!identifier) { - wlr_log(L_ERROR, "Unable to allocate unique input device name"); + wlr_log(WLR_ERROR, "Unable to allocate unique input device name"); return NULL; } @@ -104,77 +104,89 @@ static void input_manager_libinput_config_pointer( } libinput_device = wlr_libinput_get_device_handle(wlr_device); - wlr_log(L_DEBUG, "input_manager_libinput_config_pointer(%s)", + wlr_log(WLR_DEBUG, "input_manager_libinput_config_pointer(%s)", ic->identifier); if (ic->accel_profile != INT_MIN) { - wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)", + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) accel_set_profile(%d)", ic->identifier, ic->accel_profile); libinput_device_config_accel_set_profile(libinput_device, ic->accel_profile); } if (ic->click_method != INT_MIN) { - wlr_log(L_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)", + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) click_set_method(%d)", ic->identifier, ic->click_method); libinput_device_config_click_set_method(libinput_device, ic->click_method); } if (ic->drag_lock != INT_MIN) { - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) tap_set_drag_lock_enabled(%d)", ic->identifier, ic->click_method); libinput_device_config_tap_set_drag_lock_enabled(libinput_device, ic->drag_lock); } if (ic->dwt != INT_MIN) { - wlr_log(L_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)", + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) dwt_set_enabled(%d)", ic->identifier, ic->dwt); libinput_device_config_dwt_set_enabled(libinput_device, ic->dwt); } if (ic->left_handed != INT_MIN) { - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) left_handed_set_enabled(%d)", ic->identifier, ic->left_handed); libinput_device_config_left_handed_set(libinput_device, ic->left_handed); } if (ic->middle_emulation != INT_MIN) { - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) middle_emulation_set_enabled(%d)", ic->identifier, ic->middle_emulation); libinput_device_config_middle_emulation_set_enabled(libinput_device, ic->middle_emulation); } if (ic->natural_scroll != INT_MIN) { - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) natural_scroll_set_enabled(%d)", ic->identifier, ic->natural_scroll); libinput_device_config_scroll_set_natural_scroll_enabled( libinput_device, ic->natural_scroll); } if (ic->pointer_accel != FLT_MIN) { - wlr_log(L_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)", + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) accel_set_speed(%f)", ic->identifier, ic->pointer_accel); libinput_device_config_accel_set_speed(libinput_device, ic->pointer_accel); } + if (ic->scroll_button != INT_MIN) { + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) scroll_set_button(%d)", + ic->identifier, ic->scroll_button); + libinput_device_config_scroll_set_button(libinput_device, + ic->scroll_button); + } if (ic->scroll_method != INT_MIN) { - wlr_log(L_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)", + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) scroll_set_method(%d)", ic->identifier, ic->scroll_method); libinput_device_config_scroll_set_method(libinput_device, ic->scroll_method); } if (ic->send_events != INT_MIN) { - wlr_log(L_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)", + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) send_events_set_mode(%d)", ic->identifier, ic->send_events); libinput_device_config_send_events_set_mode(libinput_device, ic->send_events); } if (ic->tap != INT_MIN) { - wlr_log(L_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)", + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) tap_set_enabled(%d)", ic->identifier, ic->tap); libinput_device_config_tap_set_enabled(libinput_device, ic->tap); } + if (ic->tap_button_map != INT_MIN) { + wlr_log(WLR_DEBUG, "libinput_config_pointer(%s) tap_set_button_map(%d)", + ic->identifier, ic->tap); + libinput_device_config_tap_set_button_map(libinput_device, + ic->tap_button_map); + } } static void handle_device_destroy(struct wl_listener *listener, void *data) { @@ -187,7 +199,7 @@ static void handle_device_destroy(struct wl_listener *listener, void *data) { return; } - wlr_log(L_DEBUG, "removing device: '%s'", + wlr_log(WLR_DEBUG, "removing device: '%s'", input_device->identifier); struct sway_seat *seat = NULL; @@ -217,7 +229,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) { input_device->identifier = get_device_identifier(device); wl_list_insert(&input->devices, &input_device->link); - wlr_log(L_DEBUG, "adding device: '%s'", + wlr_log(WLR_DEBUG, "adding device: '%s'", input_device->identifier); if (input_device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) { @@ -229,7 +241,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) { struct sway_seat *seat = NULL; if (!input_has_seat_configuration(input)) { - wlr_log(L_DEBUG, "no seat configuration, using default seat"); + wlr_log(WLR_DEBUG, "no seat configuration, using default seat"); seat = input_manager_get_seat(input, default_seat); seat_add_device(seat, input_device); return; @@ -259,7 +271,7 @@ static void handle_new_input(struct wl_listener *listener, void *data) { } if (!added) { - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "device '%s' is not configured on any seats", input_device->identifier); } @@ -282,7 +294,7 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data) seat_set_exclusive_client(seat, NULL); struct sway_container *previous = seat_get_focus(seat); if (previous) { - wlr_log(L_DEBUG, "Returning focus to %p %s '%s'", previous, + wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous, container_type_to_str(previous->type), previous->name); // Hack to get seat to re-focus the return value of get_focus seat_set_focus(seat, previous->parent); @@ -359,7 +371,7 @@ void input_manager_apply_input_config(struct sway_input_manager *input, void input_manager_apply_seat_config(struct sway_input_manager *input, struct seat_config *seat_config) { - wlr_log(L_DEBUG, "applying new seat config for seat %s", + wlr_log(WLR_DEBUG, "applying new seat config for seat %s", seat_config->name); struct sway_seat *seat = input_manager_get_seat(input, seat_config->name); if (!seat) { diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 182536de..ede38519 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -3,6 +3,7 @@ #include <wlr/backend/multi.h> #include <wlr/backend/session.h> #include <wlr/types/wlr_idle.h> +#include "sway/desktop/transaction.h" #include "sway/input/seat.h" #include "sway/input/keyboard.h" #include "sway/input/input-manager.h" @@ -108,7 +109,7 @@ static void get_active_binding(const struct sway_shortcut_state *state, } if (*current_binding && *current_binding != binding) { - wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d", + wlr_log(WLR_DEBUG, "encountered duplicate bindings %d and %d", (*current_binding)->order, binding->order); } else { *current_binding = binding; @@ -122,12 +123,13 @@ static void get_active_binding(const struct sway_shortcut_state *state, */ static void keyboard_execute_command(struct sway_keyboard *keyboard, struct sway_binding *binding) { - wlr_log(L_DEBUG, "running command for binding: %s", + wlr_log(WLR_DEBUG, "running command for binding: %s", binding->command); config->handler_context.seat = keyboard->seat_device->sway_seat; struct cmd_results *results = execute_command(binding->command, NULL); + transaction_commit_dirty(); if (results->status != CMD_SUCCESS) { - wlr_log(L_DEBUG, "could not run command for binding: %s (%s)", + wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", binding->command, results->error); } free_cmd_results(results); @@ -386,7 +388,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); if (!keymap) { - wlr_log(L_DEBUG, "cannot configure keyboard: keymap does not exist"); + wlr_log(WLR_DEBUG, "cannot configure keyboard: keymap does not exist"); xkb_context_unref(context); return; } diff --git a/sway/input/seat.c b/sway/input/seat.c index 6c5abcd8..12b1fab5 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -75,7 +75,7 @@ static void seat_send_activate(struct sway_container *con, struct sway_seat *seat) { if (con->type == C_VIEW) { if (!seat_is_input_allowed(seat, con->sway_view->surface)) { - wlr_log(L_DEBUG, "Refusing to set focus, input is inhibited"); + wlr_log(WLR_DEBUG, "Refusing to set focus, input is inhibited"); return; } view_set_activated(con->sway_view, true); @@ -219,7 +219,7 @@ static struct sway_seat_container *seat_container_from_container( seat_con = calloc(1, sizeof(struct sway_seat_container)); if (seat_con == NULL) { - wlr_log(L_ERROR, "could not allocate seat container"); + wlr_log(WLR_ERROR, "could not allocate seat container"); return NULL; } @@ -301,7 +301,7 @@ static void handle_new_drag_icon(struct wl_listener *listener, void *data) { struct sway_drag_icon *icon = calloc(1, sizeof(struct sway_drag_icon)); if (icon == NULL) { - wlr_log(L_ERROR, "Allocation failed"); + wlr_log(WLR_ERROR, "Allocation failed"); return; } icon->seat = seat; @@ -391,7 +391,7 @@ static void seat_apply_input_config(struct sway_seat *seat, struct input_config *ic = input_device_get_config( sway_device->input_device); if (ic != NULL) { - wlr_log(L_DEBUG, "Applying input config to %s", + wlr_log(WLR_DEBUG, "Applying input config to %s", sway_device->input_device->identifier); mapped_to_output = ic->mapped_to_output; @@ -401,7 +401,7 @@ static void seat_apply_input_config(struct sway_seat *seat, mapped_to_output = sway_device->input_device->wlr_device->output_name; } if (mapped_to_output != NULL) { - wlr_log(L_DEBUG, "Mapping input device %s to output %s", + wlr_log(WLR_DEBUG, "Mapping input device %s to output %s", sway_device->input_device->identifier, mapped_to_output); struct sway_container *output = NULL; for (int i = 0; i < root_container.children->length; ++i) { @@ -415,7 +415,7 @@ static void seat_apply_input_config(struct sway_seat *seat, wlr_cursor_map_input_to_output(seat->cursor->cursor, sway_device->input_device->wlr_device, output->sway_output->wlr_output); - wlr_log(L_DEBUG, "Mapped to output %s", output->name); + wlr_log(WLR_DEBUG, "Mapped to output %s", output->name); } } } @@ -495,7 +495,7 @@ void seat_configure_device(struct sway_seat *seat, seat_configure_tablet_tool(seat, seat_device); break; case WLR_INPUT_DEVICE_TABLET_PAD: - wlr_log(L_DEBUG, "TODO: configure tablet pad"); + wlr_log(WLR_DEBUG, "TODO: configure tablet pad"); break; } } @@ -510,11 +510,11 @@ void seat_add_device(struct sway_seat *seat, struct sway_seat_device *seat_device = calloc(1, sizeof(struct sway_seat_device)); if (!seat_device) { - wlr_log(L_DEBUG, "could not allocate seat device"); + wlr_log(WLR_DEBUG, "could not allocate seat device"); return; } - wlr_log(L_DEBUG, "adding device %s to seat %s", + wlr_log(WLR_DEBUG, "adding device %s to seat %s", input_device->identifier, seat->wlr_seat->name); seat_device->sway_seat = seat; @@ -533,7 +533,7 @@ void seat_remove_device(struct sway_seat *seat, return; } - wlr_log(L_DEBUG, "removing device %s from seat %s", + wlr_log(WLR_DEBUG, "removing device %s from seat %s", input_device->identifier, seat->wlr_seat->name); seat_device_destroy(seat_device); @@ -594,6 +594,12 @@ static void seat_send_unfocus(struct sway_container *container, } } +static int handle_urgent_timeout(void *data) { + struct sway_view *view = data; + view_set_urgent(view, false); + return 0; +} + void seat_set_focus_warp(struct sway_seat *seat, struct sway_container *container, bool warp) { if (seat->focused_layer) { @@ -649,6 +655,7 @@ void seat_set_focus_warp(struct sway_seat *seat, while (parent) { wl_list_remove(&parent->link); wl_list_insert(&seat->focus_stack, &parent->link); + container_set_dirty(parent->container); parent = seat_container_from_container(seat, @@ -661,9 +668,33 @@ void seat_set_focus_warp(struct sway_seat *seat, if (last_focus) { seat_send_unfocus(last_focus, seat); } - seat_send_focus(container, seat); - container_damage_whole(container->parent); + + container_set_dirty(container); + container_set_dirty(container->parent); // for focused_inactive_child + if (last_focus) { + container_set_dirty(last_focus); + } + } + + // If urgent, start a timer to unset it + if (container && container->type == C_VIEW && + view_is_urgent(container->sway_view) && + !container->sway_view->urgent_timer) { + struct sway_view *view = container->sway_view; + view->urgent_timer = wl_event_loop_add_timer(server.wl_event_loop, + handle_urgent_timeout, view); + wl_event_source_timer_update(view->urgent_timer, 1000); + } + + // If we've focused a floating container, bring it to the front. + // We do this by putting it at the end of the floating list. + // This must happen for both the pending and current children lists. + if (container && container_is_floating(container)) { + list_move_to_end(container->parent->children, container); + if (container_has_ancestor(container, container->current.parent)) { + list_move_to_end(container->parent->current.children, container); + } } // clean up unfocused empty workspace on new output @@ -707,10 +738,6 @@ void seat_set_focus_warp(struct sway_seat *seat, } } - if (last_focus) { - container_damage_whole(last_focus); - } - if (last_workspace && last_workspace != new_workspace) { cursor_send_pointer_motion(seat->cursor, 0, true); } @@ -752,7 +779,7 @@ void seat_set_focus_layer(struct sway_seat *seat, struct sway_container *previous = seat_get_focus_inactive(seat, &root_container); if (previous) { - wlr_log(L_DEBUG, "Returning focus to %p %s '%s'", previous, + wlr_log(WLR_DEBUG, "Returning focus to %p %s '%s'", previous, container_type_to_str(previous->type), previous->name); // Hack to get seat to re-focus the return value of get_focus seat_set_focus(seat, previous->parent); @@ -830,18 +857,6 @@ struct sway_container *seat_get_active_child(struct sway_seat *seat, return NULL; } -struct sway_container *seat_get_active_current_child(struct sway_seat *seat, - struct sway_container *container) { - struct sway_seat_container *current = NULL; - wl_list_for_each(current, &seat->focus_stack, link) { - if (current->container->current.parent == container && - current->container->current.layout != L_FLOATING) { - return current->container; - } - } - return NULL; -} - struct sway_container *seat_get_focus(struct sway_seat *seat) { if (!seat->has_focus) { return NULL; diff --git a/sway/ipc-json.c b/sway/ipc-json.c index b9289e25..c49ea47e 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -2,6 +2,7 @@ #include <stdio.h> #include <ctype.h> #include "log.h" +#include "sway/config.h" #include "sway/ipc-json.h" #include "sway/tree/container.h" #include "sway/tree/workspace.h" @@ -41,6 +42,7 @@ json_object *ipc_json_get_version() { json_object_object_add(version, "major", json_object_new_int(major)); json_object_object_add(version, "minor", json_object_new_int(minor)); json_object_object_add(version, "patch", json_object_new_int(patch)); + json_object_object_add(version, "loaded_config_file_name", json_object_new_string(config->current_config_path)); return version; } @@ -168,7 +170,8 @@ static void ipc_json_describe_workspace(struct sway_container *workspace, json_object_object_add(object, "output", workspace->parent ? json_object_new_string(workspace->parent->name) : NULL); json_object_object_add(object, "type", json_object_new_string("workspace")); - json_object_object_add(object, "urgent", json_object_new_boolean(false)); + json_object_object_add(object, "urgent", + json_object_new_boolean(workspace->sway_workspace->urgent)); json_object_object_add(object, "representation", workspace->formatted_title ? json_object_new_string(workspace->formatted_title) : NULL); @@ -194,6 +197,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object json_object_object_add(object, "layout", json_object_new_string(ipc_json_layout_description(c->layout))); } + + bool urgent = c->type == C_VIEW ? + view_is_urgent(c->sway_view) : container_has_urgent_child(c); + json_object_object_add(object, "urgent", json_object_new_boolean(urgent)); } static void focus_inactive_children_iterator(struct sway_container *c, void *data) { diff --git a/sway/ipc-server.c b/sway/ipc-server.c index abdaa237..be703915 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -17,6 +17,8 @@ #include <unistd.h> #include <wayland-server.h> #include "sway/commands.h" +#include "sway/config.h" +#include "sway/desktop/transaction.h" #include "sway/ipc-json.h" #include "sway/ipc-server.h" #include "sway/output.h" @@ -138,32 +140,32 @@ struct sockaddr_un *ipc_user_sockaddr(void) { int ipc_handle_connection(int fd, uint32_t mask, void *data) { (void) fd; struct sway_server *server = data; - wlr_log(L_DEBUG, "Event on IPC listening socket"); + wlr_log(WLR_DEBUG, "Event on IPC listening socket"); assert(mask == WL_EVENT_READABLE); int client_fd = accept(ipc_socket, NULL, NULL); if (client_fd == -1) { - wlr_log_errno(L_ERROR, "Unable to accept IPC client connection"); + wlr_log_errno(WLR_ERROR, "Unable to accept IPC client connection"); return 0; } int flags; if ((flags = fcntl(client_fd, F_GETFD)) == -1 || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) { - wlr_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket"); + wlr_log_errno(WLR_ERROR, "Unable to set CLOEXEC on IPC client socket"); close(client_fd); return 0; } if ((flags = fcntl(client_fd, F_GETFL)) == -1 || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) { - wlr_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket"); + wlr_log_errno(WLR_ERROR, "Unable to set NONBLOCK on IPC client socket"); close(client_fd); return 0; } struct ipc_client *client = malloc(sizeof(struct ipc_client)); if (!client) { - wlr_log(L_ERROR, "Unable to allocate ipc client"); + wlr_log(WLR_ERROR, "Unable to allocate ipc client"); close(client_fd); return 0; } @@ -179,12 +181,12 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { client->write_buffer_len = 0; client->write_buffer = malloc(client->write_buffer_size); if (!client->write_buffer) { - wlr_log(L_ERROR, "Unable to allocate ipc client write buffer"); + wlr_log(WLR_ERROR, "Unable to allocate ipc client write buffer"); close(client_fd); return 0; } - wlr_log(L_DEBUG, "New client: fd %d", client_fd); + wlr_log(WLR_DEBUG, "New client: fd %d", client_fd); list_add(ipc_client_list, client); return 0; } @@ -195,22 +197,22 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { struct ipc_client *client = data; if (mask & WL_EVENT_ERROR) { - wlr_log(L_ERROR, "IPC Client socket error, removing client"); + wlr_log(WLR_ERROR, "IPC Client socket error, removing client"); ipc_client_disconnect(client); return 0; } if (mask & WL_EVENT_HANGUP) { - wlr_log(L_DEBUG, "Client %d hung up", client->fd); + wlr_log(WLR_DEBUG, "Client %d hung up", client->fd); ipc_client_disconnect(client); return 0; } - wlr_log(L_DEBUG, "Client %d readable", client->fd); + wlr_log(WLR_DEBUG, "Client %d readable", client->fd); int read_available; if (ioctl(client_fd, FIONREAD, &read_available) == -1) { - wlr_log_errno(L_INFO, "Unable to read IPC socket buffer size"); + wlr_log_errno(WLR_INFO, "Unable to read IPC socket buffer size"); ipc_client_disconnect(client); return 0; } @@ -232,13 +234,13 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { // Should be fully available, because read_available >= ipc_header_size ssize_t received = recv(client_fd, buf, ipc_header_size, 0); if (received == -1) { - wlr_log_errno(L_INFO, "Unable to receive header from IPC client"); + wlr_log_errno(WLR_INFO, "Unable to receive header from IPC client"); ipc_client_disconnect(client); return 0; } if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) { - wlr_log(L_DEBUG, "IPC header check failed"); + wlr_log(WLR_DEBUG, "IPC header check failed"); ipc_client_disconnect(client); return 0; } @@ -272,7 +274,7 @@ static void ipc_send_event(const char *json_string, enum ipc_command_type event) } client->current_command = event; if (!ipc_send_reply(client, json_string, (uint32_t) strlen(json_string))) { - wlr_log_errno(L_INFO, "Unable to send reply to IPC client"); + wlr_log_errno(WLR_INFO, "Unable to send reply to IPC client"); /* ipc_send_reply destroys client on error, which also * removes it from the list, so we need to process * current index again */ @@ -286,7 +288,7 @@ void ipc_event_workspace(struct sway_container *old, if (!ipc_has_event_listeners(IPC_EVENT_WORKSPACE)) { return; } - wlr_log(L_DEBUG, "Sending workspace::%s event", change); + wlr_log(WLR_DEBUG, "Sending workspace::%s event", change); json_object *obj = json_object_new_object(); json_object_object_add(obj, "change", json_object_new_string(change)); if (strcmp("focus", change) == 0) { @@ -314,7 +316,7 @@ void ipc_event_window(struct sway_container *window, const char *change) { if (!ipc_has_event_listeners(IPC_EVENT_WINDOW)) { return; } - wlr_log(L_DEBUG, "Sending window::%s event", change); + wlr_log(WLR_DEBUG, "Sending window::%s event", change); json_object *obj = json_object_new_object(); json_object_object_add(obj, "change", json_object_new_string(change)); json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window)); @@ -328,7 +330,7 @@ void ipc_event_barconfig_update(struct bar_config *bar) { if (!ipc_has_event_listeners(IPC_EVENT_BARCONFIG_UPDATE)) { return; } - wlr_log(L_DEBUG, "Sending barconfig_update event"); + wlr_log(WLR_DEBUG, "Sending barconfig_update event"); json_object *json = ipc_json_describe_bar_config(bar); const char *json_string = json_object_to_json_string(json); @@ -340,7 +342,7 @@ void ipc_event_mode(const char *mode, bool pango) { if (!ipc_has_event_listeners(IPC_EVENT_MODE)) { return; } - wlr_log(L_DEBUG, "Sending mode::%s event", mode); + wlr_log(WLR_DEBUG, "Sending mode::%s event", mode); json_object *obj = json_object_new_object(); json_object_object_add(obj, "change", json_object_new_string(mode)); json_object_object_add(obj, "pango_markup", @@ -355,13 +357,13 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { struct ipc_client *client = data; if (mask & WL_EVENT_ERROR) { - wlr_log(L_ERROR, "IPC Client socket error, removing client"); + wlr_log(WLR_ERROR, "IPC Client socket error, removing client"); ipc_client_disconnect(client); return 0; } if (mask & WL_EVENT_HANGUP) { - wlr_log(L_DEBUG, "Client %d hung up", client->fd); + wlr_log(WLR_DEBUG, "Client %d hung up", client->fd); ipc_client_disconnect(client); return 0; } @@ -370,14 +372,14 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { return 0; } - wlr_log(L_DEBUG, "Client %d writable", client->fd); + wlr_log(WLR_DEBUG, "Client %d writable", client->fd); ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len); if (written == -1 && errno == EAGAIN) { return 0; } else if (written == -1) { - wlr_log_errno(L_INFO, "Unable to send data from queue to IPC client"); + wlr_log_errno(WLR_INFO, "Unable to send data from queue to IPC client"); ipc_client_disconnect(client); return 0; } @@ -400,7 +402,7 @@ void ipc_client_disconnect(struct ipc_client *client) { shutdown(client->fd, SHUT_RDWR); - wlr_log(L_INFO, "IPC Client %d disconnected", client->fd); + wlr_log(WLR_INFO, "IPC Client %d disconnected", client->fd); wl_event_source_remove(client->event_source); if (client->writable_event_source) { wl_event_source_remove(client->writable_event_source); @@ -461,7 +463,7 @@ void ipc_client_handle_command(struct ipc_client *client) { char *buf = malloc(client->payload_length + 1); if (!buf) { - wlr_log_errno(L_INFO, "Unable to allocate IPC payload"); + wlr_log_errno(WLR_INFO, "Unable to allocate IPC payload"); ipc_client_disconnect(client); return; } @@ -470,7 +472,7 @@ void ipc_client_handle_command(struct ipc_client *client) { ssize_t received = recv(client->fd, buf, client->payload_length, 0); if (received == -1) { - wlr_log_errno(L_INFO, "Unable to receive payload from IPC client"); + wlr_log_errno(WLR_INFO, "Unable to receive payload from IPC client"); ipc_client_disconnect(client); free(buf); return; @@ -483,6 +485,7 @@ void ipc_client_handle_command(struct ipc_client *client) { case IPC_COMMAND: { struct cmd_results *results = execute_command(buf, NULL); + transaction_commit_dirty(); char *json = cmd_results_to_json(results); int length = strlen(json); client_valid = ipc_send_reply(client, json, (uint32_t)length); @@ -533,7 +536,7 @@ void ipc_client_handle_command(struct ipc_client *client) { struct json_object *request = json_tokener_parse(buf); if (request == NULL) { client_valid = ipc_send_reply(client, "{\"success\": false}", 18); - wlr_log_errno(L_INFO, "Failed to read request"); + wlr_log_errno(WLR_INFO, "Failed to read request"); goto exit_cleanup; } @@ -556,7 +559,7 @@ void ipc_client_handle_command(struct ipc_client *client) { client_valid = ipc_send_reply(client, "{\"success\": false}", 18); json_object_put(request); - wlr_log_errno(L_INFO, "Failed to parse request"); + wlr_log_errno(WLR_INFO, "Failed to parse request"); goto exit_cleanup; } } @@ -667,8 +670,33 @@ void ipc_client_handle_command(struct ipc_client *client) { goto exit_cleanup; } + case IPC_GET_BINDING_MODES: + { + json_object *modes = json_object_new_array(); + for (int i = 0; i < config->modes->length; i++) { + struct sway_mode *mode = config->modes->items[i]; + json_object_array_add(modes, json_object_new_string(mode->name)); + } + const char *json_string = json_object_to_json_string(modes); + client_valid = + ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); + json_object_put(modes); // free + goto exit_cleanup; + } + + case IPC_GET_CONFIG: + { + json_object *json = json_object_new_object(); + json_object_object_add(json, "config", json_object_new_string(config->current_config)); + const char *json_string = json_object_to_json_string(json); + client_valid = + ipc_send_reply(client, json_string, (uint32_t)strlen(json_string)); + json_object_put(json); // free + goto exit_cleanup; + } + default: - wlr_log(L_INFO, "Unknown IPC command type %i", client->current_command); + wlr_log(WLR_INFO, "Unknown IPC command type %i", client->current_command); goto exit_cleanup; } @@ -696,14 +724,14 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay } if (client->write_buffer_size > 4e6) { // 4 MB - wlr_log(L_ERROR, "Client write buffer too big, disconnecting client"); + wlr_log(WLR_ERROR, "Client write buffer too big, disconnecting client"); ipc_client_disconnect(client); return false; } char *new_buffer = realloc(client->write_buffer, client->write_buffer_size); if (!new_buffer) { - wlr_log(L_ERROR, "Unable to reallocate ipc client write buffer"); + wlr_log(WLR_ERROR, "Unable to reallocate ipc client write buffer"); ipc_client_disconnect(client); return false; } @@ -720,6 +748,6 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay ipc_client_handle_writable, client); } - wlr_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload); + wlr_log(WLR_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload); return true; } diff --git a/sway/main.c b/sway/main.c index ec7353be..1a55b519 100644 --- a/sway/main.c +++ b/sway/main.c @@ -20,6 +20,7 @@ #include "sway/commands.h" #include "sway/config.h" #include "sway/debug.h" +#include "sway/desktop/transaction.h" #include "sway/server.h" #include "sway/tree/layout.h" #include "sway/ipc-server.h" @@ -129,7 +130,7 @@ static void log_env() { "SWAYSOCK" }; for (size_t i = 0; i < sizeof(log_vars) / sizeof(char *); ++i) { - wlr_log(L_INFO, "%s=%s", log_vars[i], getenv(log_vars[i])); + wlr_log(WLR_INFO, "%s=%s", log_vars[i], getenv(log_vars[i])); } } @@ -144,14 +145,14 @@ static void log_distro() { for (size_t i = 0; i < sizeof(paths) / sizeof(char *); ++i) { FILE *f = fopen(paths[i], "r"); if (f) { - wlr_log(L_INFO, "Contents of %s:", paths[i]); + wlr_log(WLR_INFO, "Contents of %s:", paths[i]); while (!feof(f)) { char *line; if (!(line = read_line(f))) { break; } if (*line) { - wlr_log(L_INFO, "%s", line); + wlr_log(WLR_INFO, "%s", line); } free(line); } @@ -163,7 +164,7 @@ static void log_distro() { static void log_kernel() { FILE *f = popen("uname -a", "r"); if (!f) { - wlr_log(L_INFO, "Unable to determine kernel version"); + wlr_log(WLR_INFO, "Unable to determine kernel version"); return; } while (!feof(f)) { @@ -172,7 +173,7 @@ static void log_kernel() { break; } if (*line) { - wlr_log(L_INFO, "%s", line); + wlr_log(WLR_INFO, "%s", line); } free(line); } @@ -183,14 +184,14 @@ static void security_sanity_check() { // TODO: Notify users visually if this has issues struct stat s; if (stat("/proc", &s)) { - wlr_log(L_ERROR, + wlr_log(WLR_ERROR, "!! DANGER !! /proc is not available - sway CANNOT enforce security rules!"); } #ifdef __linux__ cap_flag_value_t v; cap_t cap = cap_get_proc(); if (!cap || cap_get_flag(cap, CAP_SYS_PTRACE, CAP_PERMITTED, &v) != 0 || v != CAP_SET) { - wlr_log(L_ERROR, + wlr_log(WLR_ERROR, "!! DANGER !! Sway does not have CAP_SYS_PTRACE and cannot enforce security rules for processes running as other users."); } if (cap) { @@ -206,13 +207,13 @@ static void executable_sanity_check() { stat(exe, &sb); // We assume that cap_get_file returning NULL implies ENODATA if (sb.st_mode & (S_ISUID|S_ISGID) && cap_get_file(exe)) { - wlr_log(L_ERROR, + wlr_log(WLR_ERROR, "sway executable has both the s(g)uid bit AND file caps set."); - wlr_log(L_ERROR, + wlr_log(WLR_ERROR, "This is strongly discouraged (and completely broken)."); - wlr_log(L_ERROR, + wlr_log(WLR_ERROR, "Please clear one of them (either the suid bit, or the file caps)."); - wlr_log(L_ERROR, + wlr_log(WLR_ERROR, "If unsure, strip the file caps."); exit(EXIT_FAILURE); } @@ -223,16 +224,16 @@ static void executable_sanity_check() { static void drop_permissions(bool keep_caps) { if (getuid() != geteuid() || getgid() != getegid()) { if (setgid(getgid()) != 0) { - wlr_log(L_ERROR, "Unable to drop root"); + wlr_log(WLR_ERROR, "Unable to drop root"); exit(EXIT_FAILURE); } if (setuid(getuid()) != 0) { - wlr_log(L_ERROR, "Unable to drop root"); + wlr_log(WLR_ERROR, "Unable to drop root"); exit(EXIT_FAILURE); } } if (setuid(0) != -1) { - wlr_log(L_ERROR, "Root privileges can be restored."); + wlr_log(WLR_ERROR, "Root privileges can be restored."); exit(EXIT_FAILURE); } #ifdef __linux__ @@ -240,17 +241,29 @@ static void drop_permissions(bool keep_caps) { // Drop every cap except CAP_SYS_PTRACE cap_t caps = cap_init(); cap_value_t keep = CAP_SYS_PTRACE; - wlr_log(L_INFO, "Dropping extra capabilities"); + wlr_log(WLR_INFO, "Dropping extra capabilities"); if (cap_set_flag(caps, CAP_PERMITTED, 1, &keep, CAP_SET) || cap_set_flag(caps, CAP_EFFECTIVE, 1, &keep, CAP_SET) || cap_set_proc(caps)) { - wlr_log(L_ERROR, "Failed to drop extra capabilities"); + wlr_log(WLR_ERROR, "Failed to drop extra capabilities"); exit(EXIT_FAILURE); } } #endif } +void enable_debug_flag(const char *flag) { + if (strcmp(flag, "render-tree") == 0) { + enable_debug_tree = true; + } else if (strncmp(flag, "damage=", 7) == 0) { + damage_debug = &flag[7]; + } else if (strcmp(flag, "txn-debug") == 0) { + txn_debug = true; + } else if (strncmp(flag, "txn-timeout=", 12) == 0) { + txn_timeout_ms = atoi(&flag[12]); + } +} + int main(int argc, char **argv) { static int verbose = 0, debug = 0, validate = 0; @@ -290,7 +303,7 @@ int main(int argc, char **argv) { int c; while (1) { int option_index = 0; - c = getopt_long(argc, argv, "hCdDvVc:", long_options, &option_index); + c = getopt_long(argc, argv, "hCdD:vVc:", long_options, &option_index); if (c == -1) { break; } @@ -309,7 +322,7 @@ int main(int argc, char **argv) { debug = 1; break; case 'D': // extended debug options - enable_debug_tree = true; + enable_debug_flag(optarg); break; case 'v': // version fprintf(stdout, "sway version " SWAY_VERSION "\n"); @@ -335,22 +348,22 @@ int main(int argc, char **argv) { // TODO: switch logging over to wlroots? if (debug) { - wlr_log_init(L_DEBUG, NULL); + wlr_log_init(WLR_DEBUG, NULL); } else if (verbose || validate) { - wlr_log_init(L_INFO, NULL); + wlr_log_init(WLR_INFO, NULL); } else { - wlr_log_init(L_ERROR, NULL); + wlr_log_init(WLR_ERROR, NULL); } if (optind < argc) { // Behave as IPC client if(optind != 1) { - wlr_log(L_ERROR, "Don't use options with the IPC client"); + wlr_log(WLR_ERROR, "Don't use options with the IPC client"); exit(EXIT_FAILURE); } drop_permissions(false); char *socket_path = getenv("SWAYSOCK"); if (!socket_path) { - wlr_log(L_ERROR, "Unable to retrieve socket path"); + wlr_log(WLR_ERROR, "Unable to retrieve socket path"); exit(EXIT_FAILURE); } char *command = join_args(argv + optind, argc - optind); @@ -369,7 +382,7 @@ int main(int argc, char **argv) { if (getuid() != geteuid() || getgid() != getegid()) { // Retain capabilities after setuid() if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0)) { - wlr_log(L_ERROR, "Cannot keep caps after setuid()"); + wlr_log(WLR_ERROR, "Cannot keep caps after setuid()"); exit(EXIT_FAILURE); } suid = true; @@ -390,7 +403,7 @@ int main(int argc, char **argv) { // prevent ipc from crashing sway signal(SIGPIPE, SIG_IGN); - wlr_log(L_INFO, "Starting sway version " SWAY_VERSION); + wlr_log(WLR_INFO, "Starting sway version " SWAY_VERSION); layout_init(); @@ -423,18 +436,19 @@ int main(int argc, char **argv) { char *line = config->cmd_queue->items[0]; struct cmd_results *res = execute_command(line, NULL); if (res->status != CMD_SUCCESS) { - wlr_log(L_ERROR, "Error on line '%s': %s", line, res->error); + wlr_log(WLR_ERROR, "Error on line '%s': %s", line, res->error); } free_cmd_results(res); free(line); list_del(config->cmd_queue, 0); } + transaction_commit_dirty(); if (!terminate_request) { server_run(&server); } - wlr_log(L_INFO, "Shutting down sway"); + wlr_log(WLR_INFO, "Shutting down sway"); server_fini(&server); diff --git a/sway/meson.build b/sway/meson.build index e492aeee..c58d3470 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -35,11 +35,13 @@ sway_sources = files( 'commands/border.c', 'commands/client.c', 'commands/default_border.c', + 'commands/default_floating_border.c', 'commands/default_orientation.c', 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', 'commands/floating.c', + 'commands/floating_minmax_size.c', 'commands/focus.c', 'commands/focus_follows_mouse.c', 'commands/focus_wrapping.c', @@ -58,6 +60,7 @@ sway_sources = files( 'commands/mode.c', 'commands/mouse_warping.c', 'commands/move.c', + 'commands/no_focus.c', 'commands/output.c', 'commands/reload.c', 'commands/rename.c', @@ -75,6 +78,7 @@ sway_sources = files( 'commands/swap.c', 'commands/title_format.c', 'commands/unmark.c', + 'commands/urgent.c', 'commands/workspace.c', 'commands/workspace_layout.c', 'commands/ws_auto_back_and_forth.c', @@ -117,8 +121,10 @@ sway_sources = files( 'commands/input/pointer_accel.c', 'commands/input/repeat_delay.c', 'commands/input/repeat_rate.c', + 'commands/input/scroll_button.c', 'commands/input/scroll_method.c', 'commands/input/tap.c', + 'commands/input/tap_button_map.c', 'commands/input/xkb_layout.c', 'commands/input/xkb_model.c', 'commands/input/xkb_options.c', diff --git a/sway/server.c b/sway/server.c index cd15f454..f904b177 100644 --- a/sway/server.c +++ b/sway/server.c @@ -14,7 +14,6 @@ #include <wlr/types/wlr_linux_dmabuf.h> #include <wlr/types/wlr_primary_selection.h> #include <wlr/types/wlr_screencopy_v1.h> -#include <wlr/types/wlr_screenshooter.h> #include <wlr/types/wlr_server_decoration.h> #include <wlr/types/wlr_xcursor_manager.h> #include <wlr/types/wlr_xdg_output.h> @@ -29,20 +28,20 @@ #include "sway/xwayland.h" bool server_privileged_prepare(struct sway_server *server) { - wlr_log(L_DEBUG, "Preparing Wayland server initialization"); + wlr_log(WLR_DEBUG, "Preparing Wayland server initialization"); server->wl_display = wl_display_create(); server->wl_event_loop = wl_display_get_event_loop(server->wl_display); server->backend = wlr_backend_autocreate(server->wl_display, NULL); if (!server->backend) { - wlr_log(L_ERROR, "Unable to create backend"); + wlr_log(WLR_ERROR, "Unable to create backend"); return false; } return true; } bool server_init(struct sway_server *server) { - wlr_log(L_DEBUG, "Initializing Wayland server"); + wlr_log(WLR_DEBUG, "Initializing Wayland server"); struct wlr_renderer *renderer = wlr_backend_get_renderer(server->backend); assert(renderer); @@ -53,7 +52,6 @@ bool server_init(struct sway_server *server) { server->data_device_manager = wlr_data_device_manager_create(server->wl_display); - wlr_screenshooter_create(server->wl_display); wlr_gamma_control_manager_create(server->wl_display); wlr_primary_selection_device_manager_create(server->wl_display); @@ -116,7 +114,7 @@ bool server_init(struct sway_server *server) { server->socket = wl_display_add_socket_auto(server->wl_display); if (!server->socket) { - wlr_log(L_ERROR, "Unable to open wayland socket"); + wlr_log(WLR_ERROR, "Unable to open wayland socket"); wlr_backend_destroy(server->backend); return false; } @@ -125,8 +123,7 @@ bool server_init(struct sway_server *server) { if (debug != NULL && strcmp(debug, "txn_timings") == 0) { server->debug_txn_timings = true; } - server->destroying_containers = create_list(); - + server->dirty_containers = create_list(); server->transactions = create_list(); input_manager = input_manager_create(server); @@ -136,15 +133,15 @@ bool server_init(struct sway_server *server) { void server_fini(struct sway_server *server) { // TODO: free sway-specific resources wl_display_destroy(server->wl_display); - list_free(server->destroying_containers); + list_free(server->dirty_containers); list_free(server->transactions); } void server_run(struct sway_server *server) { - wlr_log(L_INFO, "Running compositor on wayland display '%s'", + wlr_log(WLR_INFO, "Running compositor on wayland display '%s'", server->socket); if (!wlr_backend_start(server->backend)) { - wlr_log(L_ERROR, "Failed to start backend"); + wlr_log(WLR_ERROR, "Failed to start backend"); wlr_backend_destroy(server->backend); return; } diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index cf7a6385..b6391431 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd @@ -92,9 +92,20 @@ For more information on these xkb configuration options, see *input* <identifier> scroll\_method none|two\_finger|edge|on\_button\_down Changes the scroll method for the specified input device. +*input* <identifier> scroll\_button <button\_identifier> + Sets button used for scroll\_method on\_button\_down. The button identifier + can be obtained from `libinput debug-events`. + If set to 0, it disables the scroll\_button on\_button\_down. + *input* <identifier> tap enabled|disabled Enables or disables tap for specified input device. +*input* <identifier> tap_button_map lrm|lmr + Specifies which button mapping to use for tapping. _lrm_ treats 1 finger as + left click, 2 fingers as right click, and 3 fingers as middle click. _lmr_ + treats 1 finger as left click, 2 fingers as middle click, and 3 fingers as + right click. + ## SEAT CONFIGURATION Configure options for multiseat mode. sway-seat commands must be used inside a diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 7c553d3f..d369d7b6 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd @@ -92,6 +92,12 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). *focus* output <name> Moves focus to the named output. +*focus tiling* + Sets focus to the last focused tiling container. + +*focus floating* + Sets focus to the last focused floating container. + *focus* mode\_toggle Moves focus between the floating and tiled layers. @@ -493,6 +499,11 @@ config after the others, or it will be matched instead of the others. *unmark* will remove _identifier_ from the list of current marks on a window. If _identifier_ is omitted, all marks are removed. +*urgent* enable|disable|allow|deny + Using _enable_ or _disable_ manually sets or unsets the window's urgent + state. Using _allow_ or _deny_ controls the window's ability to set itself + as urgent. By default, windows are allowed to set their own urgency. + *workspace* [number] <name> Switches to the specified workspace. The string "number" is optional and is used to sort workspaces. diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 582b2891..533cf71c 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c @@ -47,11 +47,11 @@ static void apply_horiz_layout(struct sway_container *parent) { double scale = parent->width / total_width; // Resize windows - wlr_log(L_DEBUG, "Arranging %p horizontally", parent); + wlr_log(WLR_DEBUG, "Arranging %p horizontally", parent); double child_x = parent->x; for (size_t i = 0; i < num_children; ++i) { struct sway_container *child = parent->children->items[i]; - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, child->width, scale); child->x = child_x; @@ -99,11 +99,11 @@ static void apply_vert_layout(struct sway_container *parent) { double scale = parent_height / total_height; // Resize - wlr_log(L_DEBUG, "Arranging %p vertically", parent); + wlr_log(WLR_DEBUG, "Arranging %p vertically", parent); double child_y = parent->y + parent_offset; for (size_t i = 0; i < num_children; ++i) { struct sway_container *child = parent->children->items[i]; - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "Calculating arrangement for %p:%d (will scale %f by %f)", child, child->type, child->height, scale); child->x = parent->x; @@ -144,42 +144,26 @@ static void apply_tabbed_or_stacked_layout(struct sway_container *parent) { } } -/** - * If a container has been deleted from the pending tree state, we must add it - * to the transaction so it can be freed afterwards. To do this, we iterate the - * server's destroying_containers list and add all of them. We may add more than - * what we need to, but this is easy and has no negative consequences. - */ -static void add_deleted_containers(struct sway_transaction *transaction) { - for (int i = 0; i < server.destroying_containers->length; ++i) { - struct sway_container *child = server.destroying_containers->items[i]; - transaction_add_container(transaction, child); - } -} - -static void arrange_children_of(struct sway_container *parent, - struct sway_transaction *transaction); +static void arrange_children_of(struct sway_container *parent); -static void arrange_floating(struct sway_container *floating, - struct sway_transaction *transaction) { +static void arrange_floating(struct sway_container *floating) { for (int i = 0; i < floating->children->length; ++i) { struct sway_container *floater = floating->children->items[i]; if (floater->type == C_VIEW) { view_autoconfigure(floater->sway_view); } else { - arrange_children_of(floater, transaction); + arrange_children_of(floater); } - transaction_add_container(transaction, floater); + container_set_dirty(floater); } - transaction_add_container(transaction, floating); + container_set_dirty(floating); } -static void arrange_children_of(struct sway_container *parent, - struct sway_transaction *transaction) { +static void arrange_children_of(struct sway_container *parent) { if (config->reloading) { return; } - wlr_log(L_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent, + wlr_log(WLR_DEBUG, "Arranging layout for %p %s %fx%f+%f,%f", parent, parent->name, parent->width, parent->height, parent->x, parent->y); // Calculate x, y, width and height of children @@ -198,7 +182,7 @@ static void arrange_children_of(struct sway_container *parent, apply_horiz_layout(parent); break; case L_FLOATING: - arrange_floating(parent, transaction); + arrange_floating(parent); break; } @@ -213,20 +197,19 @@ static void arrange_children_of(struct sway_container *parent, if (child->type == C_VIEW) { view_autoconfigure(child->sway_view); } else { - arrange_children_of(child, transaction); + arrange_children_of(child); } - transaction_add_container(transaction, child); + container_set_dirty(child); } } -static void arrange_workspace(struct sway_container *workspace, - struct sway_transaction *transaction) { +static void arrange_workspace(struct sway_container *workspace) { if (config->reloading) { return; } struct sway_container *output = workspace->parent; struct wlr_box *area = &output->sway_output->usable_area; - wlr_log(L_DEBUG, "Usable area for ws: %dx%d@%d,%d", + wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", area->width, area->height, area->x, area->y); remove_gaps(workspace); workspace->width = area->width; @@ -234,15 +217,14 @@ static void arrange_workspace(struct sway_container *workspace, workspace->x = output->x + area->x; workspace->y = output->y + area->y; add_gaps(workspace); - transaction_add_container(transaction, workspace); - wlr_log(L_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, + container_set_dirty(workspace); + wlr_log(WLR_DEBUG, "Arranging workspace '%s' at %f, %f", workspace->name, workspace->x, workspace->y); - arrange_floating(workspace->sway_workspace->floating, transaction); - arrange_children_of(workspace, transaction); + arrange_floating(workspace->sway_workspace->floating); + arrange_children_of(workspace); } -static void arrange_output(struct sway_container *output, - struct sway_transaction *transaction) { +static void arrange_output(struct sway_container *output) { if (config->reloading) { return; } @@ -253,16 +235,16 @@ static void arrange_output(struct sway_container *output, output->y = output_box->y; output->width = output_box->width; output->height = output_box->height; - transaction_add_container(transaction, output); - wlr_log(L_DEBUG, "Arranging output '%s' at %f,%f", + container_set_dirty(output); + wlr_log(WLR_DEBUG, "Arranging output '%s' at %f,%f", output->name, output->x, output->y); for (int i = 0; i < output->children->length; ++i) { struct sway_container *workspace = output->children->items[i]; - arrange_workspace(workspace, transaction); + arrange_workspace(workspace); } } -static void arrange_root(struct sway_transaction *transaction) { +static void arrange_root() { if (config->reloading) { return; } @@ -274,48 +256,40 @@ static void arrange_root(struct sway_transaction *transaction) { root_container.y = layout_box->y; root_container.width = layout_box->width; root_container.height = layout_box->height; - transaction_add_container(transaction, &root_container); + container_set_dirty(&root_container); for (int i = 0; i < root_container.children->length; ++i) { struct sway_container *output = root_container.children->items[i]; - arrange_output(output, transaction); + arrange_output(output); } } -void arrange_windows(struct sway_container *container, - struct sway_transaction *transaction) { +void arrange_windows(struct sway_container *container) { switch (container->type) { case C_ROOT: - arrange_root(transaction); + arrange_root(); break; case C_OUTPUT: - arrange_output(container, transaction); + arrange_output(container); break; case C_WORKSPACE: - arrange_workspace(container, transaction); + arrange_workspace(container); break; case C_CONTAINER: - arrange_children_of(container, transaction); - transaction_add_container(transaction, container); + arrange_children_of(container); + container_set_dirty(container); break; case C_VIEW: view_autoconfigure(container->sway_view); - transaction_add_container(transaction, container); + container_set_dirty(container); break; case C_TYPES: break; } - add_deleted_containers(transaction); -} - -void arrange_and_commit(struct sway_container *container) { - struct sway_transaction *transaction = transaction_create(); - arrange_windows(container, transaction); - transaction_commit(transaction); } void remove_gaps(struct sway_container *c) { if (c->current_gaps == 0) { - wlr_log(L_DEBUG, "Removing gaps: not gapped: %p", c); + wlr_log(WLR_DEBUG, "Removing gaps: not gapped: %p", c); return; } @@ -326,12 +300,12 @@ void remove_gaps(struct sway_container *c) { c->current_gaps = 0; - wlr_log(L_DEBUG, "Removing gaps %p", c); + wlr_log(WLR_DEBUG, "Removing gaps %p", c); } void add_gaps(struct sway_container *c) { if (c->current_gaps > 0 || c->type == C_CONTAINER) { - wlr_log(L_DEBUG, "Not adding gaps: %p", c); + wlr_log(WLR_DEBUG, "Not adding gaps: %p", c); return; } @@ -348,5 +322,5 @@ void add_gaps(struct sway_container *c) { c->height -= 2 * gaps; c->current_gaps = gaps; - wlr_log(L_DEBUG, "Adding gaps: %p", c); + wlr_log(WLR_DEBUG, "Adding gaps: %p", c); } diff --git a/sway/tree/container.c b/sway/tree/container.c index 7cea43fa..02384199 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -11,11 +11,14 @@ #include "cairo.h" #include "pango.h" #include "sway/config.h" +#include "sway/desktop.h" +#include "sway/desktop/transaction.h" #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/ipc-server.h" #include "sway/output.h" #include "sway/server.h" +#include "sway/tree/arrange.h" #include "sway/tree/layout.h" #include "sway/tree/view.h" #include "sway/tree/workspace.h" @@ -28,7 +31,7 @@ static list_t *get_bfs_queue() { if (!bfs_queue) { bfs_queue = create_list(); if (!bfs_queue) { - wlr_log(L_ERROR, "could not allocate list for bfs queue"); + wlr_log(WLR_ERROR, "could not allocate list for bfs queue"); return NULL; } } @@ -156,14 +159,6 @@ void container_free(struct sway_container *cont) { wlr_texture_destroy(cont->title_focused_inactive); wlr_texture_destroy(cont->title_unfocused); wlr_texture_destroy(cont->title_urgent); - - for (int i = 0; i < server.destroying_containers->length; ++i) { - if (server.destroying_containers->items[i] == cont) { - list_del(server.destroying_containers, i); - break; - } - } - list_free(cont->instructions); list_free(cont->children); list_free(cont->current.children); @@ -218,7 +213,7 @@ static struct sway_container *container_workspace_destroy( return NULL; } - wlr_log(L_DEBUG, "destroying workspace '%s'", workspace->name); + wlr_log(WLR_DEBUG, "destroying workspace '%s'", workspace->name); if (!workspace_is_empty(workspace)) { // Move children to a different workspace on this output @@ -230,7 +225,7 @@ static struct sway_container *container_workspace_destroy( } } - wlr_log(L_DEBUG, "moving children to different workspace '%s' -> '%s'", + wlr_log(WLR_DEBUG, "moving children to different workspace '%s' -> '%s'", workspace->name, new_workspace->name); for (int i = 0; i < workspace->children->length; i++) { container_move_to(workspace->children->items[i], new_workspace); @@ -296,7 +291,7 @@ static struct sway_container *container_output_destroy( output->sway_output->swayc = NULL; output->sway_output = NULL; - wlr_log(L_DEBUG, "OUTPUT: Destroying output '%s'", output->name); + wlr_log(WLR_DEBUG, "OUTPUT: Destroying output '%s'", output->name); return &root_container; } @@ -323,13 +318,13 @@ static struct sway_container *container_destroy_noreaping( // Workspaces will refuse to be destroyed if they're the last workspace // on their output. if (!container_workspace_destroy(con)) { - wlr_log(L_ERROR, "workspace doesn't want to destroy"); + wlr_log(WLR_ERROR, "workspace doesn't want to destroy"); return NULL; } } con->destroying = true; - list_add(server.destroying_containers, con); + container_set_dirty(con); if (!con->parent) { return NULL; @@ -350,7 +345,7 @@ bool container_reap_empty(struct sway_container *con) { break; case C_WORKSPACE: if (!workspace_is_visible(con) && workspace_is_empty(con)) { - wlr_log(L_DEBUG, "Destroying workspace via reaper"); + wlr_log(WLR_DEBUG, "Destroying workspace via reaper"); container_destroy_noreaping(con); return true; } @@ -443,7 +438,7 @@ struct sway_container *container_view_create(struct sway_container *sibling, } const char *title = view_get_title(sway_view); struct sway_container *swayc = container_create(C_VIEW); - wlr_log(L_DEBUG, "Adding new view %p:%s to container %p %d %s", + wlr_log(WLR_DEBUG, "Adding new view %p:%s to container %p %d %s", swayc, title, sibling, sibling ? sibling->type : 0, sibling->name); // Setup values swayc->sway_view = sway_view; @@ -686,16 +681,23 @@ struct sway_container *floating_container_at(double lx, double ly, void container_for_each_descendant_dfs(struct sway_container *container, void (*f)(struct sway_container *container, void *data), void *data) { - if (container) { - if (container->children) { - for (int i = 0; i < container->children->length; ++i) { - struct sway_container *child = - container->children->items[i]; - container_for_each_descendant_dfs(child, f, data); - } + if (!container) { + return; + } + if (container->children) { + for (int i = 0; i < container->children->length; ++i) { + struct sway_container *child = container->children->items[i]; + container_for_each_descendant_dfs(child, f, data); + } + } + if (container->type == C_WORKSPACE) { + struct sway_container *floating = container->sway_workspace->floating; + for (int i = 0; i < floating->children->length; ++i) { + struct sway_container *child = floating->children->items[i]; + container_for_each_descendant_dfs(child, f, data); } - f(container, data); } + f(container, data); } void container_for_each_descendant_bfs(struct sway_container *con, @@ -706,7 +708,7 @@ void container_for_each_descendant_bfs(struct sway_container *con, } if (queue == NULL) { - wlr_log(L_ERROR, "could not allocate list"); + wlr_log(WLR_ERROR, "could not allocate list"); return; } @@ -972,9 +974,14 @@ void container_set_geometry_from_floating_view(struct sway_container *con) { return; } struct sway_view *view = con->sway_view; - size_t border_width = view->border_thickness * (view->border != B_NONE); - size_t top = - view->border == B_NORMAL ? container_titlebar_height() : border_width; + size_t border_width = 0; + size_t top = 0; + + if (!view->using_csd) { + border_width = view->border_thickness * (view->border != B_NONE); + top = view->border == B_NORMAL ? + container_titlebar_height() : border_width; + } con->x = view->x - border_width; con->y = view->y - top; @@ -996,3 +1003,103 @@ void container_get_box(struct sway_container *container, struct wlr_box *box) { box->width = container->width; box->height = container->height; } + +/** + * Translate the container's position as well as all children. + */ +static void container_floating_translate(struct sway_container *con, + double x_amount, double y_amount) { + con->x += x_amount; + con->y += y_amount; + con->current.swayc_x += x_amount; + con->current.swayc_y += y_amount; + if (con->type == C_VIEW) { + con->sway_view->x += x_amount; + con->sway_view->y += y_amount; + con->current.view_x += x_amount; + con->current.view_y += y_amount; + } else { + for (int i = 0; i < con->children->length; ++i) { + struct sway_container *child = con->children->items[i]; + container_floating_translate(child, x_amount, y_amount); + } + } +} + +/** + * Choose an output for the floating container's new position. + * + * If the center of the container intersects an output then we'll choose that + * one, otherwise we'll choose whichever output is closest to the container's + * center. + */ +static struct sway_container *container_floating_find_output( + struct sway_container *con) { + double center_x = con->x + con->width / 2; + double center_y = con->y + con->height / 2; + struct sway_container *closest_output = NULL; + double closest_distance = DBL_MAX; + for (int i = 0; i < root_container.children->length; ++i) { + struct sway_container *output = root_container.children->items[i]; + struct wlr_box output_box; + double closest_x, closest_y; + container_get_box(output, &output_box); + wlr_box_closest_point(&output_box, center_x, center_y, + &closest_x, &closest_y); + if (center_x == closest_x && center_y == closest_y) { + // The center of the floating container is on this output + return output; + } + double x_dist = closest_x - center_x; + double y_dist = closest_y - center_y; + double distance = x_dist * x_dist + y_dist * y_dist; + if (distance < closest_distance) { + closest_output = output; + closest_distance = distance; + } + } + return closest_output; +} + +void container_floating_move_to(struct sway_container *con, + double lx, double ly) { + if (!sway_assert(container_is_floating(con), + "Expected a floating container")) { + return; + } + desktop_damage_whole_container(con); + container_floating_translate(con, lx - con->x, ly - con->y); + desktop_damage_whole_container(con); + struct sway_container *old_workspace = container_parent(con, C_WORKSPACE); + struct sway_container *new_output = container_floating_find_output(con); + if (!sway_assert(new_output, "Unable to find any output")) { + return; + } + struct sway_container *new_workspace = + output_get_active_workspace(new_output->sway_output); + if (old_workspace != new_workspace) { + container_remove_child(con); + container_add_child(new_workspace->sway_workspace->floating, con); + arrange_windows(old_workspace); + arrange_windows(new_workspace); + workspace_detect_urgent(old_workspace); + workspace_detect_urgent(new_workspace); + } +} + +void container_set_dirty(struct sway_container *container) { + if (container->dirty) { + return; + } + container->dirty = true; + list_add(server.dirty_containers, container); +} + +static bool find_urgent_iterator(struct sway_container *con, + void *data) { + return con->type == C_VIEW && view_is_urgent(con->sway_view); +} + +bool container_has_urgent_child(struct sway_container *container) { + return container_find(container, find_urgent_iterator, NULL); +} diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 14631ad4..197a2fc8 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -22,7 +22,8 @@ struct sway_container root_container; static void output_layout_handle_change(struct wl_listener *listener, void *data) { - arrange_and_commit(&root_container); + arrange_windows(&root_container); + transaction_commit_dirty(); } void layout_init(void) { @@ -101,7 +102,7 @@ void container_insert_child(struct sway_container *parent, if (old_parent) { container_remove_child(child); } - wlr_log(L_DEBUG, "Inserting id:%zd at index %d", child->id, i); + wlr_log(WLR_DEBUG, "Inserting id:%zd at index %d", child->id, i); list_insert(parent->children, i, child); child->parent = parent; container_handle_fullscreen_reparent(child, old_parent); @@ -127,7 +128,7 @@ struct sway_container *container_add_sibling(struct sway_container *fixed, void container_add_child(struct sway_container *parent, struct sway_container *child) { - wlr_log(L_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", + wlr_log(WLR_DEBUG, "Adding %p (%d, %fx%f) to %p (%d, %fx%f)", child, child->type, child->width, child->height, parent, parent->type, parent->width, parent->height); struct sway_container *old_parent = child->parent; @@ -168,7 +169,12 @@ void container_move_to(struct sway_container *container, struct sway_container *old_parent = container_remove_child(container); container->width = container->height = 0; container->saved_width = container->saved_height = 0; - struct sway_container *new_parent; + + struct sway_container *new_parent, *new_parent_focus; + struct sway_seat *seat = input_manager_get_default_seat(input_manager); + + // Get the focus of the destination before we change it. + new_parent_focus = seat_get_focus_inactive(seat, destination); if (destination->type == C_VIEW) { new_parent = container_add_sibling(destination, container); } else { @@ -176,17 +182,20 @@ void container_move_to(struct sway_container *container, container_add_child(destination, container); } wl_signal_emit(&container->events.reparent, old_parent); + if (container->type == C_WORKSPACE) { // If moving a workspace to a new output, maybe create a new workspace // on the previous output - struct sway_seat *seat = input_manager_get_default_seat(input_manager); if (old_parent->children->length == 0) { char *ws_name = workspace_next_name(old_parent->name); - struct sway_container *ws = - workspace_create(old_parent, ws_name); + struct sway_container *ws = workspace_create(old_parent, ws_name); free(ws_name); seat_set_focus(seat, ws); } + + // Try to remove an empty workspace from the destination output. + container_reap_empty_recursive(new_parent_focus); + container_sort_workspaces(new_parent); seat_set_focus(seat, new_parent); workspace_output_raise_priority(container, old_parent, new_parent); @@ -216,6 +225,15 @@ void container_move_to(struct sway_container *container, } } } + // Update workspace urgent state + struct sway_container *old_workspace = old_parent; + if (old_workspace->type != C_WORKSPACE) { + old_workspace = container_parent(old_workspace, C_WORKSPACE); + } + if (new_workspace != old_workspace) { + workspace_detect_urgent(new_workspace); + workspace_detect_urgent(old_workspace); + } } static bool sway_dir_to_wlr(enum movement_direction dir, @@ -311,13 +329,13 @@ static void move_out_of_tabs_stacks(struct sway_container *container, int offs) { if (container->parent == current->parent && current->parent->children->length == 1) { - wlr_log(L_DEBUG, "Changing layout of %zd", current->parent->id); + wlr_log(WLR_DEBUG, "Changing layout of %zd", current->parent->id); current->parent->layout = move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT; return; } - wlr_log(L_DEBUG, "Moving out of tab/stack into a split"); + wlr_log(WLR_DEBUG, "Moving out of tab/stack into a split"); bool is_workspace = current->parent->type == C_WORKSPACE; struct sway_container *new_parent = container_split(current->parent, move_dir == MOVE_LEFT || move_dir == MOVE_RIGHT ? L_HORIZ : L_VERT); @@ -362,7 +380,7 @@ void container_move(struct sway_container *container, } parent = current->parent; - wlr_log(L_DEBUG, "Visiting %p %s '%s'", current, + wlr_log(WLR_DEBUG, "Visiting %p %s '%s'", current, container_type_to_str(current->type), current->name); int index = index_child(current); @@ -380,12 +398,12 @@ void container_move(struct sway_container *container, root_container.sway_root->output_layout, wlr_dir, current->sway_output->wlr_output, ref_lx, ref_ly); if (!next) { - wlr_log(L_DEBUG, "Hit edge of output, nowhere else to go"); + wlr_log(WLR_DEBUG, "Hit edge of output, nowhere else to go"); return; } struct sway_output *next_output = next->data; current = next_output->swayc; - wlr_log(L_DEBUG, "Selected next output (%s)", current->name); + wlr_log(WLR_DEBUG, "Selected next output (%s)", current->name); // Select workspace and get outta here current = seat_get_focus_inactive( config->handler_context.seat, current); @@ -398,20 +416,20 @@ void container_move(struct sway_container *container, case C_WORKSPACE: if (!is_parallel(current->layout, move_dir)) { if (current->children->length >= 2) { - wlr_log(L_DEBUG, "Rejiggering the workspace (%d kiddos)", + wlr_log(WLR_DEBUG, "Rejiggering the workspace (%d kiddos)", current->children->length); workspace_rejigger(current, container, move_dir); return; } else { - wlr_log(L_DEBUG, "Selecting output"); + wlr_log(WLR_DEBUG, "Selecting output"); current = current->parent; } } else if (current->layout == L_TABBED || current->layout == L_STACKED) { - wlr_log(L_DEBUG, "Rejiggering out of tabs/stacks"); + wlr_log(WLR_DEBUG, "Rejiggering out of tabs/stacks"); workspace_rejigger(current, container, move_dir); } else { - wlr_log(L_DEBUG, "Selecting output"); + wlr_log(WLR_DEBUG, "Selecting output"); current = current->parent; } break; @@ -427,11 +445,11 @@ void container_move(struct sway_container *container, move_dir, offs); return; } else { - wlr_log(L_DEBUG, "Hit limit, selecting parent"); + wlr_log(WLR_DEBUG, "Hit limit, selecting parent"); current = current->parent; } } else { - wlr_log(L_DEBUG, "Hit limit, " + wlr_log(WLR_DEBUG, "Hit limit, " "promoting descendant to sibling"); // Special case container_insert_child(current->parent, container, @@ -441,14 +459,14 @@ void container_move(struct sway_container *container, } } else { sibling = parent->children->items[index + offs]; - wlr_log(L_DEBUG, "Selecting sibling id:%zd", sibling->id); + wlr_log(WLR_DEBUG, "Selecting sibling id:%zd", sibling->id); } } else if (parent->layout == L_TABBED || parent->layout == L_STACKED) { move_out_of_tabs_stacks(container, current, move_dir, offs); return; } else { - wlr_log(L_DEBUG, "Moving up to find a parallel container"); + wlr_log(WLR_DEBUG, "Moving up to find a parallel container"); current = current->parent; } break; @@ -467,11 +485,11 @@ void container_move(struct sway_container *container, switch (sibling->type) { case C_VIEW: if (sibling->parent == container->parent) { - wlr_log(L_DEBUG, "Swapping siblings"); + wlr_log(WLR_DEBUG, "Swapping siblings"); sibling->parent->children->items[index + offs] = container; sibling->parent->children->items[index] = sibling; } else { - wlr_log(L_DEBUG, "Promoting to sibling of cousin"); + wlr_log(WLR_DEBUG, "Promoting to sibling of cousin"); container_insert_child(sibling->parent, container, index_child(sibling) + (offs > 0 ? 0 : 1)); container->width = container->height = 0; @@ -482,31 +500,31 @@ void container_move(struct sway_container *container, case C_CONTAINER: if (is_parallel(sibling->layout, move_dir)) { int limit = container_limit(sibling, invert_movement(move_dir)); - wlr_log(L_DEBUG, "limit: %d", limit); - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "limit: %d", limit); + wlr_log(WLR_DEBUG, "Reparenting container (parallel) to index %d " "(move dir: %d)", limit, move_dir); container_insert_child(sibling, container, limit); container->width = container->height = 0; sibling = NULL; } else { - wlr_log(L_DEBUG, "Reparenting container (perpendicular)"); + wlr_log(WLR_DEBUG, "Reparenting container (perpendicular)"); struct sway_container *focus_inactive = seat_get_focus_inactive( config->handler_context.seat, sibling); if (focus_inactive && focus_inactive != sibling) { while (focus_inactive->parent != sibling) { focus_inactive = focus_inactive->parent; } - wlr_log(L_DEBUG, "Focus inactive: id:%zd", + wlr_log(WLR_DEBUG, "Focus inactive: id:%zd", focus_inactive->id); sibling = focus_inactive; continue; } else if (sibling->children->length) { - wlr_log(L_DEBUG, "No focus-inactive, adding arbitrarily"); + wlr_log(WLR_DEBUG, "No focus-inactive, adding arbitrarily"); container_remove_child(container); container_add_sibling(sibling->children->items[0], container); } else { - wlr_log(L_DEBUG, "No kiddos, adding container alone"); + wlr_log(WLR_DEBUG, "No kiddos, adding container alone"); container_remove_child(container); container_add_child(sibling, container); } @@ -539,6 +557,8 @@ void container_move(struct sway_container *container, } if (last_ws && next_ws && last_ws != next_ws) { ipc_event_workspace(last_ws, container, "focus"); + workspace_detect_urgent(last_ws); + workspace_detect_urgent(next_ws); } } @@ -603,7 +623,7 @@ static struct sway_container *get_swayc_in_output_direction( } if (ws == NULL) { - wlr_log(L_ERROR, "got an output without a workspace"); + wlr_log(WLR_ERROR, "got an output without a workspace"); return NULL; } @@ -775,7 +795,7 @@ struct sway_container *container_get_in_direction( } else { struct sway_container *desired_con = parent->children->items[desired]; - wlr_log(L_DEBUG, + wlr_log(WLR_DEBUG, "cont %d-%p dir %i sibling %d: %p", idx, container, dir, desired, desired_con); return seat_get_focus_inactive_view(seat, desired_con); @@ -840,7 +860,7 @@ struct sway_container *container_split(struct sway_container *child, struct sway_container *cont = container_create(C_CONTAINER); - wlr_log(L_DEBUG, "creating container %p around %p", cont, child); + wlr_log(WLR_DEBUG, "creating container %p around %p", cont, child); remove_gaps(child); @@ -888,7 +908,7 @@ struct sway_container *container_split(struct sway_container *child, void container_recursive_resize(struct sway_container *container, double amount, enum resize_edge edge) { bool layout_match = true; - wlr_log(L_DEBUG, "Resizing %p with amount: %f", container, amount); + wlr_log(WLR_DEBUG, "Resizing %p with amount: %f", container, amount); if (edge == RESIZE_EDGE_LEFT || edge == RESIZE_EDGE_RIGHT) { container->width += amount; layout_match = container->layout == L_HORIZ; @@ -978,7 +998,7 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) { return; } - wlr_log(L_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id); + wlr_log(WLR_DEBUG, "Swapping containers %zu and %zu", con1->id, con2->id); int fs1 = con1->type == C_VIEW && con1->sway_view->is_fullscreen; int fs2 = con2->type == C_VIEW && con2->sway_view->is_fullscreen; diff --git a/sway/tree/output.c b/sway/tree/output.c index e2927cdb..da535c18 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -43,11 +43,11 @@ struct sway_container *output_create( if (strcasecmp(name, cur->name) == 0 || strcasecmp(identifier, cur->name) == 0) { - wlr_log(L_DEBUG, "Matched output config for %s", name); + wlr_log(WLR_DEBUG, "Matched output config for %s", name); oc = cur; } if (strcasecmp("*", cur->name) == 0) { - wlr_log(L_DEBUG, "Matched wildcard output config for %s", name); + wlr_log(WLR_DEBUG, "Matched wildcard output config for %s", name); all = cur; } @@ -86,7 +86,7 @@ struct sway_container *output_create( if (!output->children->length) { // Create workspace char *ws_name = workspace_next_name(output->name); - wlr_log(L_DEBUG, "Creating default workspace %s", ws_name); + wlr_log(WLR_DEBUG, "Creating default workspace %s", ws_name); struct sway_container *ws = workspace_create(output, ws_name); // Set each seat's focus if not already set struct sway_seat *seat = NULL; diff --git a/sway/tree/view.c b/sway/tree/view.c index 3ef79fa8..fc31699c 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -25,6 +25,7 @@ void view_init(struct sway_view *view, enum sway_view_type type, view->impl = impl; view->executed_criteria = create_list(); view->marks = create_list(); + view->allow_request_urgent = true; wl_signal_init(&view->events.unmap); } @@ -150,12 +151,43 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, void view_init_floating(struct sway_view *view) { struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); - int max_width = ws->width * 0.6666; - int max_height = ws->height * 0.6666; - view->width = - view->natural_width > max_width ? max_width : view->natural_width; - view->height = - view->natural_height > max_height ? max_height : view->natural_height; + int min_width, min_height; + int max_width, max_height; + + if (config->floating_minimum_width == -1) { // no minimum + min_width = 0; + } else if (config->floating_minimum_width == 0) { // automatic + min_width = 75; + } else { + min_width = config->floating_minimum_width; + } + + if (config->floating_minimum_height == -1) { // no minimum + min_height = 0; + } else if (config->floating_minimum_height == 0) { // automatic + min_height = 50; + } else { + min_height = config->floating_minimum_height; + } + + if (config->floating_maximum_width == -1) { // no maximum + max_width = INT_MAX; + } else if (config->floating_maximum_width == 0) { // automatic + max_width = ws->width * 0.6666; + } else { + max_width = config->floating_maximum_width; + } + + if (config->floating_maximum_height == -1) { // no maximum + max_height = INT_MAX; + } else if (config->floating_maximum_height == 0) { // automatic + max_height = ws->height * 0.6666; + } else { + max_height = config->floating_maximum_height; + } + + view->width = fmax(min_width, fmin(view->natural_width, max_width)); + view->height = fmax(min_height, fmin(view->natural_height, max_height)); view->x = ws->x + (ws->width - view->width) / 2; view->y = ws->y + (ws->height - view->height) / 2; @@ -284,7 +316,15 @@ void view_set_activated(struct sway_view *view, bool activated) { } void view_set_tiled(struct sway_view *view, bool tiled) { - view->border = tiled ? config->border : B_NONE; + if (!tiled) { + view->using_csd = true; + if (view->impl->has_client_side_decorations) { + view->using_csd = view->impl->has_client_side_decorations(view); + } + } else { + view->using_csd = false; + } + if (view->impl->set_tiled) { view->impl->set_tiled(view, tiled); } @@ -462,27 +502,45 @@ void view_execute_criteria(struct sway_view *view) { list_t *criterias = criteria_for_view(view, CT_COMMAND); for (int i = 0; i < criterias->length; i++) { struct criteria *criteria = criterias->items[i]; - wlr_log(L_DEBUG, "Checking criteria %s", criteria->raw); + wlr_log(WLR_DEBUG, "Checking criteria %s", criteria->raw); if (view_has_executed_criteria(view, criteria)) { - wlr_log(L_DEBUG, "Criteria already executed"); + wlr_log(WLR_DEBUG, "Criteria already executed"); continue; } - wlr_log(L_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", + wlr_log(WLR_DEBUG, "for_window '%s' matches view %p, cmd: '%s'", criteria->raw, view, criteria->cmdlist); + seat_set_focus(seat, view->swayc); list_add(view->executed_criteria, criteria); struct cmd_results *res = execute_command(criteria->cmdlist, NULL); if (res->status != CMD_SUCCESS) { - wlr_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); + wlr_log(WLR_ERROR, "Command '%s' failed: %s", res->input, res->error); } free_cmd_results(res); - // view must be focused for commands to affect it, - // so always refocus in-between command lists - seat_set_focus(seat, view->swayc); } list_free(criterias); seat_set_focus(seat, prior_focus); } +static bool should_focus(struct sway_view *view) { + // If the view is the only one in the focused workspace, it'll get focus + // regardless of any no_focus criteria. + struct sway_container *parent = view->swayc->parent; + struct sway_seat *seat = input_manager_current_seat(input_manager); + if (parent->type == C_WORKSPACE && seat_get_focus(seat) == parent) { + size_t num_children = parent->children->length + + parent->sway_workspace->floating->children->length; + if (num_children == 1) { + return true; + } + } + + // Check no_focus criteria + list_t *criterias = criteria_for_view(view, CT_NO_FOCUS); + size_t len = criterias->length; + list_free(criterias); + return len == 0; +} + void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { if (!sway_assert(view->surface == NULL, "cannot map mapped view")) { return; @@ -519,8 +577,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { view->surface = wlr_surface; view->swayc = cont; - view->border = config->border; - view->border_thickness = config->border_thickness; view_init_subsurfaces(view, wlr_surface); wl_signal_add(&wlr_surface->events.new_subsurface, @@ -531,14 +587,20 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { view->container_reparent.notify = view_handle_container_reparent; if (view->impl->wants_floating && view->impl->wants_floating(view)) { + view->border = config->floating_border; + view->border_thickness = config->floating_border_thickness; container_set_floating(view->swayc, true); } else { + view->border = config->border; + view->border_thickness = config->border_thickness; view_set_tiled(view, true); } - input_manager_set_focus(input_manager, cont); - if (workspace) { - workspace_switch(workspace); + if (should_focus(view)) { + input_manager_set_focus(input_manager, cont); + if (workspace) { + workspace_switch(workspace); + } } view_update_title(view, false); @@ -554,16 +616,27 @@ void view_unmap(struct sway_view *view) { wl_list_remove(&view->surface_new_subsurface.link); wl_list_remove(&view->container_reparent.link); + if (view->urgent_timer) { + wl_event_source_remove(view->urgent_timer); + view->urgent_timer = NULL; + } + + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + + struct sway_container *parent; if (view->is_fullscreen) { - struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); ws->sway_workspace->fullscreen = NULL; - container_destroy(view->swayc); + parent = container_destroy(view->swayc); - arrange_and_commit(ws->parent); + arrange_windows(ws->parent); } else { - struct sway_container *parent = container_destroy(view->swayc); - arrange_and_commit(parent); + parent = container_destroy(view->swayc); + arrange_windows(parent); + } + if (parent->type >= C_WORKSPACE) { // if the workspace still exists + workspace_detect_urgent(ws); } + transaction_commit_dirty(); view->surface = NULL; } @@ -601,7 +674,7 @@ static void view_subsurface_create(struct sway_view *view, struct wlr_subsurface *subsurface) { struct sway_view_child *child = calloc(1, sizeof(struct sway_view_child)); if (child == NULL) { - wlr_log(L_ERROR, "Allocation failed"); + wlr_log(WLR_ERROR, "Allocation failed"); return; } view_child_init(child, NULL, view, subsurface->surface); @@ -721,8 +794,9 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { return NULL; } - wlr_log(L_DEBUG, "Surface of unknown type (role %s): %p", - wlr_surface->role, wlr_surface); + const char *role = wlr_surface->role ? wlr_surface->role->name : NULL; + wlr_log(WLR_DEBUG, "Surface of unknown type (role %s): %p", + role, wlr_surface); return NULL; } @@ -789,7 +863,7 @@ static char *escape_title(char *buffer) { char *escaped_title = calloc(length + 1, sizeof(char)); int result = escape_markup_text(buffer, escaped_title, length); if (result != length) { - wlr_log(L_ERROR, "Could not escape title: %s", buffer); + wlr_log(WLR_ERROR, "Could not escape title: %s", buffer); free(escaped_title); return buffer; } @@ -1010,3 +1084,32 @@ bool view_is_visible(struct sway_view *view) { } return true; } + +void view_set_urgent(struct sway_view *view, bool enable) { + if (view_is_urgent(view) == enable) { + return; + } + if (enable) { + struct sway_seat *seat = input_manager_current_seat(input_manager); + if (seat_get_focus(seat) == view->swayc) { + return; + } + clock_gettime(CLOCK_MONOTONIC, &view->urgent); + } else { + view->urgent = (struct timespec){ 0 }; + if (view->urgent_timer) { + wl_event_source_remove(view->urgent_timer); + view->urgent_timer = NULL; + } + } + container_damage_whole(view->swayc); + + ipc_event_window(view->swayc, "urgent"); + + struct sway_container *ws = container_parent(view->swayc, C_WORKSPACE); + workspace_detect_urgent(ws); +} + +bool view_is_urgent(struct sway_view *view) { + return view->urgent.tv_sec || view->urgent.tv_nsec; +} diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 51f0fcb4..622f01ec 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c @@ -11,6 +11,7 @@ #include "sway/ipc-server.h" #include "sway/tree/arrange.h" #include "sway/tree/container.h" +#include "sway/tree/view.h" #include "sway/tree/workspace.h" #include "list.h" #include "log.h" @@ -49,7 +50,7 @@ struct sway_container *workspace_create(struct sway_container *output, output = get_workspace_initial_output(name); } - wlr_log(L_DEBUG, "Added workspace %s for output %s", name, output->name); + wlr_log(WLR_DEBUG, "Added workspace %s for output %s", name, output->name); struct sway_container *workspace = container_create(C_WORKSPACE); workspace->x = output->x; @@ -107,7 +108,7 @@ static bool workspace_valid_on_output(const char *output_name, } char *workspace_next_name(const char *output_name) { - wlr_log(L_DEBUG, "Workspace: Generating new workspace name for output %s", + wlr_log(WLR_DEBUG, "Workspace: Generating new workspace name for output %s", output_name); // Scan all workspace bindings to find the next available workspace name, // if none are found/available then default to a number @@ -135,7 +136,7 @@ char *workspace_next_name(const char *output_name) { while (isspace(*_target)) { memmove(_target, _target+1, strlen(_target+1)); } - wlr_log(L_DEBUG, "Got valid workspace command for target: '%s'", + wlr_log(WLR_DEBUG, "Got valid workspace command for target: '%s'", _target); // Make sure that the command references an actual workspace @@ -161,7 +162,7 @@ char *workspace_next_name(const char *output_name) { temp[length - 1] = '\0'; free(_target); _target = temp; - wlr_log(L_DEBUG, "Isolated name from workspace number: '%s'", _target); + wlr_log(WLR_DEBUG, "Isolated name from workspace number: '%s'", _target); // Make sure the workspace number doesn't already exist if (workspace_by_number(_target)) { @@ -190,7 +191,7 @@ char *workspace_next_name(const char *output_name) { order = binding->order; free(target); target = _target; - wlr_log(L_DEBUG, "Workspace: Found free name %s", _target); + wlr_log(WLR_DEBUG, "Workspace: Found free name %s", _target); } else { free(_target); } @@ -387,7 +388,7 @@ bool workspace_switch(struct sway_container *workspace) { free(prev_workspace_name); prev_workspace_name = malloc(strlen(active_ws->name) + 1); if (!prev_workspace_name) { - wlr_log(L_ERROR, "Unable to allocate previous workspace name"); + wlr_log(WLR_ERROR, "Unable to allocate previous workspace name"); return false; } strcpy(prev_workspace_name, active_ws->name); @@ -409,7 +410,7 @@ bool workspace_switch(struct sway_container *workspace) { } } - wlr_log(L_DEBUG, "Switching to workspace %p:%s", + wlr_log(WLR_DEBUG, "Switching to workspace %p:%s", workspace, workspace->name); struct sway_container *next = seat_get_focus_inactive(seat, workspace); if (next == NULL) { @@ -427,7 +428,7 @@ bool workspace_switch(struct sway_container *workspace) { } seat_set_focus(seat, next); struct sway_container *output = container_parent(workspace, C_OUTPUT); - arrange_and_commit(output); + arrange_windows(output); return true; } @@ -518,3 +519,13 @@ struct sway_container *workspace_output_get_highest_available( return NULL; } + +void workspace_detect_urgent(struct sway_container *workspace) { + bool new_urgent = container_has_urgent_child(workspace); + + if (workspace->sway_workspace->urgent != new_urgent) { + workspace->sway_workspace->urgent = new_urgent; + ipc_event_workspace(NULL, workspace, "urgent"); + container_damage_whole(workspace); + } +} |