diff options
40 files changed, 314 insertions, 124 deletions
@@ -202,6 +202,11 @@ bindsym $mod+r mode "resize" | |||
202 | # Read `man 5 sway-bar` for more information about this section. | 202 | # Read `man 5 sway-bar` for more information about this section. |
203 | bar { | 203 | bar { |
204 | position top | 204 | position top |
205 | |||
206 | # When the status_command prints a new line to stdout, swaybar updates. | ||
207 | # The default just shows the current date and time. | ||
208 | status_command while date +'%Y-%m-%d %l:%M:%S %p'; do sleep 1; done | ||
209 | |||
205 | colors { | 210 | colors { |
206 | statusline #ffffff | 211 | statusline #ffffff |
207 | background #323232 | 212 | background #323232 |
diff --git a/include/sway/commands.h b/include/sway/commands.h index f7fafb96..48228a98 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h | |||
@@ -103,6 +103,7 @@ sway_cmd cmd_bar; | |||
103 | sway_cmd cmd_bindcode; | 103 | sway_cmd cmd_bindcode; |
104 | sway_cmd cmd_bindsym; | 104 | sway_cmd cmd_bindsym; |
105 | sway_cmd cmd_border; | 105 | sway_cmd cmd_border; |
106 | sway_cmd cmd_client_noop; | ||
106 | sway_cmd cmd_client_focused; | 107 | sway_cmd cmd_client_focused; |
107 | sway_cmd cmd_client_focused_inactive; | 108 | sway_cmd cmd_client_focused_inactive; |
108 | sway_cmd cmd_client_unfocused; | 109 | sway_cmd cmd_client_unfocused; |
@@ -153,6 +154,7 @@ sway_cmd cmd_new_window; | |||
153 | sway_cmd cmd_no_focus; | 154 | sway_cmd cmd_no_focus; |
154 | sway_cmd cmd_output; | 155 | sway_cmd cmd_output; |
155 | sway_cmd cmd_permit; | 156 | sway_cmd cmd_permit; |
157 | sway_cmd cmd_popup_during_fullscreen; | ||
156 | sway_cmd cmd_reject; | 158 | sway_cmd cmd_reject; |
157 | sway_cmd cmd_reload; | 159 | sway_cmd cmd_reload; |
158 | sway_cmd cmd_rename; | 160 | sway_cmd cmd_rename; |
diff --git a/include/sway/config.h b/include/sway/config.h index 02ace979..00b5f25b 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -35,7 +35,6 @@ enum binding_flags { | |||
35 | BINDING_BORDER=4, // mouse only; trigger on container border | 35 | BINDING_BORDER=4, // mouse only; trigger on container border |
36 | BINDING_CONTENTS=8, // mouse only; trigger on container contents | 36 | BINDING_CONTENTS=8, // mouse only; trigger on container contents |
37 | BINDING_TITLEBAR=16, // mouse only; trigger on container titlebar | 37 | BINDING_TITLEBAR=16, // mouse only; trigger on container titlebar |
38 | BINDING_RELOAD=32, // the binding runs the reload command | ||
39 | }; | 38 | }; |
40 | 39 | ||
41 | /** | 40 | /** |
@@ -257,6 +256,12 @@ enum edge_border_types { | |||
257 | E_SMART_NO_GAPS, /**< hide both if one window and gaps to edge is zero */ | 256 | E_SMART_NO_GAPS, /**< hide both if one window and gaps to edge is zero */ |
258 | }; | 257 | }; |
259 | 258 | ||
259 | enum sway_popup_during_fullscreen { | ||
260 | POPUP_SMART, | ||
261 | POPUP_IGNORE, | ||
262 | POPUP_LEAVE, | ||
263 | }; | ||
264 | |||
260 | enum command_context { | 265 | enum command_context { |
261 | CONTEXT_CONFIG = 1, | 266 | CONTEXT_CONFIG = 1, |
262 | CONTEXT_BINDING = 2, | 267 | CONTEXT_BINDING = 2, |
@@ -356,6 +361,7 @@ struct sway_config { | |||
356 | bool pango_markup; | 361 | bool pango_markup; |
357 | size_t urgent_timeout; | 362 | size_t urgent_timeout; |
358 | enum sway_fowa focus_on_window_activation; | 363 | enum sway_fowa focus_on_window_activation; |
364 | enum sway_popup_during_fullscreen popup_during_fullscreen; | ||
359 | 365 | ||
360 | // Flags | 366 | // Flags |
361 | bool focus_follows_mouse; | 367 | bool focus_follows_mouse; |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index da6592b4..920ef038 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -292,4 +292,7 @@ bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out); | |||
292 | struct sway_container *container_split(struct sway_container *child, | 292 | struct sway_container *container_split(struct sway_container *child, |
293 | enum sway_container_layout layout); | 293 | enum sway_container_layout layout); |
294 | 294 | ||
295 | bool container_is_transient_for(struct sway_container *child, | ||
296 | struct sway_container *ancestor); | ||
297 | |||
295 | #endif | 298 | #endif |
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index eed3d13d..870ef2e0 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -49,6 +49,8 @@ struct sway_view_impl { | |||
49 | wlr_surface_iterator_func_t iterator, void *user_data); | 49 | wlr_surface_iterator_func_t iterator, void *user_data); |
50 | void (*for_each_popup)(struct sway_view *view, | 50 | void (*for_each_popup)(struct sway_view *view, |
51 | wlr_surface_iterator_func_t iterator, void *user_data); | 51 | wlr_surface_iterator_func_t iterator, void *user_data); |
52 | bool (*is_transient_for)(struct sway_view *child, | ||
53 | struct sway_view *ancestor); | ||
52 | void (*close)(struct sway_view *view); | 54 | void (*close)(struct sway_view *view); |
53 | void (*close_popups)(struct sway_view *view); | 55 | void (*close_popups)(struct sway_view *view); |
54 | void (*destroy)(struct sway_view *view); | 56 | void (*destroy)(struct sway_view *view); |
@@ -399,4 +401,6 @@ void view_remove_saved_buffer(struct sway_view *view); | |||
399 | 401 | ||
400 | void view_save_buffer(struct sway_view *view); | 402 | void view_save_buffer(struct sway_view *view); |
401 | 403 | ||
404 | bool view_is_transient_for(struct sway_view *child, struct sway_view *ancestor); | ||
405 | |||
402 | #endif | 406 | #endif |
diff --git a/sway/commands.c b/sway/commands.c index 5dd27f7e..8db1df01 100644 --- a/sway/commands.c +++ b/sway/commands.c | |||
@@ -77,8 +77,10 @@ static struct cmd_handler handlers[] = { | |||
77 | { "bar", cmd_bar }, | 77 | { "bar", cmd_bar }, |
78 | { "bindcode", cmd_bindcode }, | 78 | { "bindcode", cmd_bindcode }, |
79 | { "bindsym", cmd_bindsym }, | 79 | { "bindsym", cmd_bindsym }, |
80 | { "client.background", cmd_client_noop }, | ||
80 | { "client.focused", cmd_client_focused }, | 81 | { "client.focused", cmd_client_focused }, |
81 | { "client.focused_inactive", cmd_client_focused_inactive }, | 82 | { "client.focused_inactive", cmd_client_focused_inactive }, |
83 | { "client.placeholder", cmd_client_noop }, | ||
82 | { "client.unfocused", cmd_client_unfocused }, | 84 | { "client.unfocused", cmd_client_unfocused }, |
83 | { "client.urgent", cmd_client_urgent }, | 85 | { "client.urgent", cmd_client_urgent }, |
84 | { "default_border", cmd_default_border }, | 86 | { "default_border", cmd_default_border }, |
@@ -107,6 +109,7 @@ static struct cmd_handler handlers[] = { | |||
107 | { "new_window", cmd_default_border }, | 109 | { "new_window", cmd_default_border }, |
108 | { "no_focus", cmd_no_focus }, | 110 | { "no_focus", cmd_no_focus }, |
109 | { "output", cmd_output }, | 111 | { "output", cmd_output }, |
112 | { "popup_during_fullscreen", cmd_popup_during_fullscreen }, | ||
110 | { "raise_floating", cmd_raise_floating }, | 113 | { "raise_floating", cmd_raise_floating }, |
111 | { "seat", cmd_seat }, | 114 | { "seat", cmd_seat }, |
112 | { "set", cmd_set }, | 115 | { "set", cmd_set }, |
diff --git a/sway/commands/bar.c b/sway/commands/bar.c index f760888e..03f4c557 100644 --- a/sway/commands/bar.c +++ b/sway/commands/bar.c | |||
@@ -46,14 +46,14 @@ struct cmd_results *cmd_bar(int argc, char **argv) { | |||
46 | return error; | 46 | return error; |
47 | } | 47 | } |
48 | 48 | ||
49 | if (!config->reading) { | 49 | if (find_handler(argv[0], bar_config_handlers, |
50 | if (!find_handler(argv[0], bar_config_handlers, | 50 | sizeof(bar_config_handlers))) { |
51 | sizeof(bar_config_handlers))) { | 51 | if (config->reading) { |
52 | return cmd_results_new(CMD_FAILURE, "bar", | 52 | return config_subcommand(argv, argc, bar_config_handlers, |
53 | "Can only be used in config file."); | 53 | sizeof(bar_config_handlers)); |
54 | } | 54 | } |
55 | return config_subcommand(argv, argc, bar_config_handlers, | 55 | return cmd_results_new(CMD_FAILURE, "bar", |
56 | sizeof(bar_config_handlers)); | 56 | "Can only be used in config file."); |
57 | } | 57 | } |
58 | 58 | ||
59 | if (argc > 1) { | 59 | if (argc > 1) { |
diff --git a/sway/commands/bar/status_command.c b/sway/commands/bar/status_command.c index 6f6f81a3..5b4fdc87 100644 --- a/sway/commands/bar/status_command.c +++ b/sway/commands/bar/status_command.c | |||
@@ -13,8 +13,20 @@ struct cmd_results *bar_cmd_status_command(int argc, char **argv) { | |||
13 | "status_command", "No bar defined."); | 13 | "status_command", "No bar defined."); |
14 | } | 14 | } |
15 | free(config->current_bar->status_command); | 15 | free(config->current_bar->status_command); |
16 | config->current_bar->status_command = join_args(argv, argc); | 16 | config->current_bar->status_command = NULL; |
17 | wlr_log(WLR_DEBUG, "Feeding bar with status command: %s", | 17 | |
18 | config->current_bar->status_command); | 18 | char *new_command = join_args(argv, argc); |
19 | if (strcmp(new_command, "-") != 0) { | ||
20 | config->current_bar->status_command = new_command; | ||
21 | wlr_log(WLR_DEBUG, "Feeding bar with status command: %s", | ||
22 | config->current_bar->status_command); | ||
23 | } else { | ||
24 | free(new_command); | ||
25 | } | ||
26 | |||
27 | if (config->active && !config->validating) { | ||
28 | load_swaybars(); | ||
29 | } | ||
30 | |||
19 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 31 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
20 | } | 32 | } |
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 820c2a6a..701d9746 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c | |||
@@ -30,33 +30,6 @@ void free_sway_binding(struct sway_binding *binding) { | |||
30 | free(binding); | 30 | free(binding); |
31 | } | 31 | } |
32 | 32 | ||
33 | static struct sway_binding *sway_binding_dup(struct sway_binding *sb) { | ||
34 | struct sway_binding *new_sb = calloc(1, sizeof(struct sway_binding)); | ||
35 | if (!new_sb) { | ||
36 | return NULL; | ||
37 | } | ||
38 | |||
39 | new_sb->type = sb->type; | ||
40 | new_sb->order = sb->order; | ||
41 | new_sb->flags = sb->flags; | ||
42 | new_sb->modifiers = sb->modifiers; | ||
43 | new_sb->command = strdup(sb->command); | ||
44 | |||
45 | new_sb->keys = create_list(); | ||
46 | int i; | ||
47 | for (i = 0; i < sb->keys->length; ++i) { | ||
48 | xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); | ||
49 | if (!key) { | ||
50 | free_sway_binding(new_sb); | ||
51 | return NULL; | ||
52 | } | ||
53 | *key = *(xkb_keysym_t *)sb->keys->items[i]; | ||
54 | list_add(new_sb->keys, key); | ||
55 | } | ||
56 | |||
57 | return new_sb; | ||
58 | } | ||
59 | |||
60 | /** | 33 | /** |
61 | * Returns true if the bindings have the same key and modifier combinations. | 34 | * Returns true if the bindings have the same key and modifier combinations. |
62 | * Note that keyboard layout is not considered, so the bindings might actually | 35 | * Note that keyboard layout is not considered, so the bindings might actually |
@@ -214,9 +187,6 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, | |||
214 | } | 187 | } |
215 | 188 | ||
216 | binding->command = join_args(argv + 1, argc - 1); | 189 | binding->command = join_args(argv + 1, argc - 1); |
217 | if (strcasestr(binding->command, "reload")) { | ||
218 | binding->flags |= BINDING_RELOAD; | ||
219 | } | ||
220 | 190 | ||
221 | list_t *split = split_string(argv[0], "+"); | 191 | list_t *split = split_string(argv[0], "+"); |
222 | for (int i = 0; i < split->length; ++i) { | 192 | for (int i = 0; i < split->length; ++i) { |
@@ -306,31 +276,16 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) { | |||
306 | * Execute the command associated to a binding | 276 | * Execute the command associated to a binding |
307 | */ | 277 | */ |
308 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { | 278 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { |
309 | wlr_log(WLR_DEBUG, "running command for binding: %s", | 279 | wlr_log(WLR_DEBUG, "running command for binding: %s", binding->command); |
310 | binding->command); | ||
311 | |||
312 | struct sway_binding *binding_copy = binding; | ||
313 | // if this is a reload command we need to make a duplicate of the | ||
314 | // binding since it will be gone after the reload has completed. | ||
315 | if (binding->flags & BINDING_RELOAD) { | ||
316 | binding_copy = sway_binding_dup(binding); | ||
317 | if (!binding_copy) { | ||
318 | wlr_log(WLR_ERROR, "Failed to duplicate binding during reload"); | ||
319 | return; | ||
320 | } | ||
321 | } | ||
322 | 280 | ||
323 | config->handler_context.seat = seat; | 281 | config->handler_context.seat = seat; |
324 | struct cmd_results *results = execute_command(binding->command, NULL, NULL); | 282 | struct cmd_results *results = execute_command(binding->command, NULL, NULL); |
325 | if (results->status == CMD_SUCCESS) { | 283 | if (results->status == CMD_SUCCESS) { |
326 | ipc_event_binding(binding_copy); | 284 | ipc_event_binding(binding); |
327 | } else { | 285 | } else { |
328 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", | 286 | wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", |
329 | binding->command, results->error); | 287 | binding->command, results->error); |
330 | } | 288 | } |
331 | 289 | ||
332 | if (binding_copy->flags & BINDING_RELOAD) { | ||
333 | free_sway_binding(binding_copy); | ||
334 | } | ||
335 | free_cmd_results(results); | 290 | free_cmd_results(results); |
336 | } | 291 | } |
diff --git a/sway/commands/client.c b/sway/commands/client.c index 6e5f08a2..9f54fa94 100644 --- a/sway/commands/client.c +++ b/sway/commands/client.c | |||
@@ -64,27 +64,27 @@ static struct cmd_results *handle_command(int argc, char **argv, | |||
64 | 64 | ||
65 | if (!parse_color_float(argv[0], class->border)) { | 65 | if (!parse_color_float(argv[0], class->border)) { |
66 | return cmd_results_new(CMD_INVALID, cmd_name, | 66 | return cmd_results_new(CMD_INVALID, cmd_name, |
67 | "Unable to parse border color"); | 67 | "Unable to parse border color '%s'", argv[0]); |
68 | } | 68 | } |
69 | 69 | ||
70 | if (!parse_color_float(argv[1], class->background)) { | 70 | if (!parse_color_float(argv[1], class->background)) { |
71 | return cmd_results_new(CMD_INVALID, cmd_name, | 71 | return cmd_results_new(CMD_INVALID, cmd_name, |
72 | "Unable to parse background color"); | 72 | "Unable to parse background color '%s'", argv[1]); |
73 | } | 73 | } |
74 | 74 | ||
75 | if (!parse_color_float(argv[2], class->text)) { | 75 | if (!parse_color_float(argv[2], class->text)) { |
76 | return cmd_results_new(CMD_INVALID, cmd_name, | 76 | return cmd_results_new(CMD_INVALID, cmd_name, |
77 | "Unable to parse text color"); | 77 | "Unable to parse text color '%s'", argv[2]); |
78 | } | 78 | } |
79 | 79 | ||
80 | if (!parse_color_float(argv[3], class->indicator)) { | 80 | if (!parse_color_float(argv[3], class->indicator)) { |
81 | return cmd_results_new(CMD_INVALID, cmd_name, | 81 | return cmd_results_new(CMD_INVALID, cmd_name, |
82 | "Unable to parse indicator color"); | 82 | "Unable to parse indicator color '%s'", argv[3]); |
83 | } | 83 | } |
84 | 84 | ||
85 | if (!parse_color_float(argv[4], class->child_border)) { | 85 | if (!parse_color_float(argv[4], class->child_border)) { |
86 | return cmd_results_new(CMD_INVALID, cmd_name, | 86 | return cmd_results_new(CMD_INVALID, cmd_name, |
87 | "Unable to parse child border color"); | 87 | "Unable to parse child border color '%s'", argv[4]); |
88 | } | 88 | } |
89 | 89 | ||
90 | if (config->active) { | 90 | if (config->active) { |
@@ -114,3 +114,8 @@ struct cmd_results *cmd_client_unfocused(int argc, char **argv) { | |||
114 | struct cmd_results *cmd_client_urgent(int argc, char **argv) { | 114 | struct cmd_results *cmd_client_urgent(int argc, char **argv) { |
115 | return handle_command(argc, argv, &config->border_colors.urgent, "client.urgent"); | 115 | return handle_command(argc, argv, &config->border_colors.urgent, "client.urgent"); |
116 | } | 116 | } |
117 | |||
118 | struct cmd_results *cmd_client_noop(int argc, char **argv) { | ||
119 | wlr_log(WLR_INFO, "Warning: %s is ignored by sway", argv[-1]); | ||
120 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
121 | } | ||
diff --git a/sway/commands/opacity.c b/sway/commands/opacity.c index 9cdaad7f..4e4fc994 100644 --- a/sway/commands/opacity.c +++ b/sway/commands/opacity.c | |||
@@ -21,6 +21,10 @@ struct cmd_results *cmd_opacity(int argc, char **argv) { | |||
21 | 21 | ||
22 | struct sway_container *con = config->handler_context.container; | 22 | struct sway_container *con = config->handler_context.container; |
23 | 23 | ||
24 | if (con == NULL) { | ||
25 | return cmd_results_new(CMD_FAILURE, "opacity", "No current container"); | ||
26 | } | ||
27 | |||
24 | float opacity = 0.0f; | 28 | float opacity = 0.0f; |
25 | 29 | ||
26 | if (!parse_opacity(argv[0], &opacity)) { | 30 | if (!parse_opacity(argv[0], &opacity)) { |
diff --git a/sway/commands/popup_during_fullscreen.c b/sway/commands/popup_during_fullscreen.c new file mode 100644 index 00000000..da1904b6 --- /dev/null +++ b/sway/commands/popup_during_fullscreen.c | |||
@@ -0,0 +1,25 @@ | |||
1 | #include <strings.h> | ||
2 | #include "sway/commands.h" | ||
3 | #include "sway/config.h" | ||
4 | |||
5 | struct cmd_results *cmd_popup_during_fullscreen(int argc, char **argv) { | ||
6 | struct cmd_results *error = NULL; | ||
7 | if ((error = checkarg(argc, "popup_during_fullscreen", | ||
8 | EXPECTED_EQUAL_TO, 1))) { | ||
9 | return error; | ||
10 | } | ||
11 | |||
12 | if (strcasecmp(argv[0], "smart") == 0) { | ||
13 | config->popup_during_fullscreen = POPUP_SMART; | ||
14 | } else if (strcasecmp(argv[0], "ignore") == 0) { | ||
15 | config->popup_during_fullscreen = POPUP_IGNORE; | ||
16 | } else if (strcasecmp(argv[0], "leave_fullscreen") == 0) { | ||
17 | config->popup_during_fullscreen = POPUP_LEAVE; | ||
18 | } else { | ||
19 | return cmd_results_new(CMD_INVALID, "popup_during_fullscreen", | ||
20 | "Expected " | ||
21 | "'popup_during_fullscreen smart|ignore|leave_fullscreen'"); | ||
22 | } | ||
23 | |||
24 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
25 | } | ||
diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 36fb9092..9e136d48 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c | |||
@@ -3,15 +3,12 @@ | |||
3 | #include "sway/commands.h" | 3 | #include "sway/commands.h" |
4 | #include "sway/config.h" | 4 | #include "sway/config.h" |
5 | #include "sway/ipc-server.h" | 5 | #include "sway/ipc-server.h" |
6 | #include "sway/server.h" | ||
6 | #include "sway/tree/arrange.h" | 7 | #include "sway/tree/arrange.h" |
7 | #include "list.h" | 8 | #include "list.h" |
9 | #include "log.h" | ||
8 | 10 | ||
9 | struct cmd_results *cmd_reload(int argc, char **argv) { | 11 | static void do_reload(void *data) { |
10 | struct cmd_results *error = NULL; | ||
11 | if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { | ||
12 | return error; | ||
13 | } | ||
14 | |||
15 | // store bar ids to check against new bars for barconfig_update events | 12 | // store bar ids to check against new bars for barconfig_update events |
16 | list_t *bar_ids = create_list(); | 13 | list_t *bar_ids = create_list(); |
17 | for (int i = 0; i < config->bars->length; ++i) { | 14 | for (int i = 0; i < config->bars->length; ++i) { |
@@ -20,9 +17,12 @@ struct cmd_results *cmd_reload(int argc, char **argv) { | |||
20 | } | 17 | } |
21 | 18 | ||
22 | if (!load_main_config(config->current_config_path, true, false)) { | 19 | if (!load_main_config(config->current_config_path, true, false)) { |
23 | return cmd_results_new(CMD_FAILURE, "reload", | 20 | wlr_log(WLR_ERROR, "Error(s) reloading config"); |
24 | "Error(s) reloading config."); | 21 | list_foreach(bar_ids, free); |
22 | list_free(bar_ids); | ||
23 | return; | ||
25 | } | 24 | } |
25 | |||
26 | ipc_event_workspace(NULL, NULL, "reload"); | 26 | ipc_event_workspace(NULL, NULL, "reload"); |
27 | 27 | ||
28 | load_swaybars(); | 28 | load_swaybars(); |
@@ -37,12 +37,26 @@ struct cmd_results *cmd_reload(int argc, char **argv) { | |||
37 | } | 37 | } |
38 | } | 38 | } |
39 | 39 | ||
40 | for (int i = 0; i < bar_ids->length; ++i) { | 40 | list_foreach(bar_ids, free); |
41 | free(bar_ids->items[i]); | ||
42 | } | ||
43 | list_free(bar_ids); | 41 | list_free(bar_ids); |
44 | 42 | ||
45 | arrange_root(); | 43 | arrange_root(); |
44 | } | ||
45 | |||
46 | struct cmd_results *cmd_reload(int argc, char **argv) { | ||
47 | struct cmd_results *error = NULL; | ||
48 | if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { | ||
49 | return error; | ||
50 | } | ||
51 | |||
52 | if (!load_main_config(config->current_config_path, true, true)) { | ||
53 | return cmd_results_new(CMD_FAILURE, "reload", | ||
54 | "Error(s) reloading config."); | ||
55 | } | ||
56 | |||
57 | // The reload command frees a lot of stuff, so to avoid use-after-frees | ||
58 | // we schedule the reload to happen using an idle event. | ||
59 | wl_event_loop_add_idle(server.wl_event_loop, do_reload, NULL); | ||
46 | 60 | ||
47 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 61 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
48 | } | 62 | } |
diff --git a/sway/commands/seat/attach.c b/sway/commands/seat/attach.c index 3e771c00..6b4bcf1f 100644 --- a/sway/commands/seat/attach.c +++ b/sway/commands/seat/attach.c | |||
@@ -23,6 +23,8 @@ struct cmd_results *seat_cmd_attach(int argc, char **argv) { | |||
23 | new_attachment->identifier = strdup(argv[0]); | 23 | new_attachment->identifier = strdup(argv[0]); |
24 | list_add(new_config->attachments, new_attachment); | 24 | list_add(new_config->attachments, new_attachment); |
25 | 25 | ||
26 | apply_seat_config(new_config); | 26 | if (!config->validating) { |
27 | apply_seat_config(new_config); | ||
28 | } | ||
27 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 29 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
28 | } | 30 | } |
diff --git a/sway/commands/seat/fallback.c b/sway/commands/seat/fallback.c index 56feaab5..11f5a08c 100644 --- a/sway/commands/seat/fallback.c +++ b/sway/commands/seat/fallback.c | |||
@@ -27,6 +27,8 @@ struct cmd_results *seat_cmd_fallback(int argc, char **argv) { | |||
27 | "Expected 'fallback <true|false>'"); | 27 | "Expected 'fallback <true|false>'"); |
28 | } | 28 | } |
29 | 29 | ||
30 | apply_seat_config(new_config); | 30 | if (!config->validating) { |
31 | apply_seat_config(new_config); | ||
32 | } | ||
31 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 33 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
32 | } | 34 | } |
diff --git a/sway/commands/swaybg_command.c b/sway/commands/swaybg_command.c index 36f7fdcd..b184b193 100644 --- a/sway/commands/swaybg_command.c +++ b/sway/commands/swaybg_command.c | |||
@@ -9,12 +9,17 @@ struct cmd_results *cmd_swaybg_command(int argc, char **argv) { | |||
9 | return error; | 9 | return error; |
10 | } | 10 | } |
11 | 11 | ||
12 | if (config->swaybg_command) { | 12 | free(config->swaybg_command); |
13 | free(config->swaybg_command); | 13 | config->swaybg_command = NULL; |
14 | |||
15 | char *new_command = join_args(argv, argc); | ||
16 | if (strcmp(new_command, "-") != 0) { | ||
17 | config->swaybg_command = new_command; | ||
18 | wlr_log(WLR_DEBUG, "Using custom swaybg command: %s", | ||
19 | config->swaybg_command); | ||
20 | } else { | ||
21 | free(new_command); | ||
14 | } | 22 | } |
15 | config->swaybg_command = join_args(argv, argc); | ||
16 | wlr_log(WLR_DEBUG, "Using custom swaybg command: %s", | ||
17 | config->swaybg_command); | ||
18 | 23 | ||
19 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 24 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
20 | } | 25 | } |
diff --git a/sway/commands/swaynag_command.c b/sway/commands/swaynag_command.c index c57a80a6..6c86f1a7 100644 --- a/sway/commands/swaynag_command.c +++ b/sway/commands/swaynag_command.c | |||
@@ -9,12 +9,17 @@ struct cmd_results *cmd_swaynag_command(int argc, char **argv) { | |||
9 | return error; | 9 | return error; |
10 | } | 10 | } |
11 | 11 | ||
12 | if (config->swaynag_command) { | 12 | free(config->swaynag_command); |
13 | free(config->swaynag_command); | 13 | config->swaynag_command = NULL; |
14 | |||
15 | char *new_command = join_args(argv, argc); | ||
16 | if (strcmp(new_command, "-") != 0) { | ||
17 | config->swaybg_command = new_command; | ||
18 | wlr_log(WLR_DEBUG, "Using custom swaynag command: %s", | ||
19 | config->swaynag_command); | ||
20 | } else { | ||
21 | free(new_command); | ||
14 | } | 22 | } |
15 | config->swaynag_command = join_args(argv, argc); | ||
16 | wlr_log(WLR_DEBUG, "Using custom swaynag command: %s", | ||
17 | config->swaynag_command); | ||
18 | 23 | ||
19 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 24 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
20 | } | 25 | } |
diff --git a/sway/commands/urgent.c b/sway/commands/urgent.c index 53c37d4d..4f283c55 100644 --- a/sway/commands/urgent.c +++ b/sway/commands/urgent.c | |||
@@ -12,6 +12,9 @@ struct cmd_results *cmd_urgent(int argc, char **argv) { | |||
12 | return error; | 12 | return error; |
13 | } | 13 | } |
14 | struct sway_container *container = config->handler_context.container; | 14 | struct sway_container *container = config->handler_context.container; |
15 | if (!container) { | ||
16 | return cmd_results_new(CMD_FAILURE, "urgent", "No current container"); | ||
17 | } | ||
15 | if (!container->view) { | 18 | if (!container->view) { |
16 | return cmd_results_new(CMD_INVALID, "urgent", | 19 | return cmd_results_new(CMD_INVALID, "urgent", |
17 | "Only views can be urgent"); | 20 | "Only views can be urgent"); |
diff --git a/sway/config.c b/sway/config.c index b56c4f71..a50e9144 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -136,6 +136,8 @@ void free_config(struct sway_config *config) { | |||
136 | free(config->floating_scroll_left_cmd); | 136 | free(config->floating_scroll_left_cmd); |
137 | free(config->floating_scroll_right_cmd); | 137 | free(config->floating_scroll_right_cmd); |
138 | free(config->font); | 138 | free(config->font); |
139 | free(config->swaybg_command); | ||
140 | free(config->swaynag_command); | ||
139 | free((char *)config->current_config_path); | 141 | free((char *)config->current_config_path); |
140 | free((char *)config->current_config); | 142 | free((char *)config->current_config); |
141 | free(config); | 143 | free(config); |
@@ -166,7 +168,7 @@ static void set_color(float dest[static 4], uint32_t color) { | |||
166 | } | 168 | } |
167 | 169 | ||
168 | static void config_defaults(struct sway_config *config) { | 170 | static void config_defaults(struct sway_config *config) { |
169 | config->swaynag_command = strdup("swaynag"); | 171 | if (!(config->swaynag_command = strdup("swaynag"))) goto cleanup; |
170 | config->swaynag_config_errors = (struct swaynag_instance){ | 172 | config->swaynag_config_errors = (struct swaynag_instance){ |
171 | .args = "--type error " | 173 | .args = "--type error " |
172 | "--message 'There are errors in your config file' " | 174 | "--message 'There are errors in your config file' " |
@@ -212,6 +214,7 @@ static void config_defaults(struct sway_config *config) { | |||
212 | if (!(config->font = strdup("monospace 10"))) goto cleanup; | 214 | if (!(config->font = strdup("monospace 10"))) goto cleanup; |
213 | config->font_height = 17; // height of monospace 10 | 215 | config->font_height = 17; // height of monospace 10 |
214 | config->urgent_timeout = 500; | 216 | config->urgent_timeout = 500; |
217 | config->popup_during_fullscreen = POPUP_SMART; | ||
215 | 218 | ||
216 | // floating view | 219 | // floating view |
217 | config->floating_maximum_width = 0; | 220 | config->floating_maximum_width = 0; |
@@ -240,6 +243,8 @@ static void config_defaults(struct sway_config *config) { | |||
240 | 243 | ||
241 | if (!(config->active_bar_modifiers = create_list())) goto cleanup; | 244 | if (!(config->active_bar_modifiers = create_list())) goto cleanup; |
242 | 245 | ||
246 | if (!(config->swaybg_command = strdup("swaybg"))) goto cleanup; | ||
247 | |||
243 | if (!(config->config_chain = create_list())) goto cleanup; | 248 | if (!(config->config_chain = create_list())) goto cleanup; |
244 | config->current_config_path = NULL; | 249 | config->current_config_path = NULL; |
245 | config->current_config = NULL; | 250 | config->current_config = NULL; |
@@ -457,6 +462,12 @@ bool load_main_config(const char *file, bool is_active, bool validating) { | |||
457 | success = success && load_config(path, config, | 462 | success = success && load_config(path, config, |
458 | &config->swaynag_config_errors); | 463 | &config->swaynag_config_errors); |
459 | 464 | ||
465 | if (validating) { | ||
466 | free_config(config); | ||
467 | config = old_config; | ||
468 | return success; | ||
469 | } | ||
470 | |||
460 | if (is_active) { | 471 | if (is_active) { |
461 | for (int i = 0; i < config->output_configs->length; i++) { | 472 | for (int i = 0; i < config->output_configs->length; i++) { |
462 | apply_output_config_to_outputs(config->output_configs->items[i]); | 473 | apply_output_config_to_outputs(config->output_configs->items[i]); |
diff --git a/sway/config/bar.c b/sway/config/bar.c index 48a632fb..b8695798 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c | |||
@@ -99,10 +99,6 @@ struct bar_config *default_bar_config(void) { | |||
99 | if (!(bar->bindings = create_list())) { | 99 | if (!(bar->bindings = create_list())) { |
100 | goto cleanup; | 100 | goto cleanup; |
101 | } | 101 | } |
102 | if (!(bar->status_command = | ||
103 | strdup("while date +'%Y-%m-%d %l:%M:%S %p'; do sleep 1; done"))) { | ||
104 | goto cleanup; | ||
105 | } | ||
106 | // set default colors | 102 | // set default colors |
107 | if (!(bar->colors.background = strndup("#000000ff", 9))) { | 103 | if (!(bar->colors.background = strndup("#000000ff", 9))) { |
108 | goto cleanup; | 104 | goto cleanup; |
diff --git a/sway/config/output.c b/sway/config/output.c index 6f337b66..2b041353 100644 --- a/sway/config/output.c +++ b/sway/config/output.c | |||
@@ -229,17 +229,16 @@ void apply_output_config(struct output_config *oc, struct sway_output *output) { | |||
229 | } | 229 | } |
230 | } | 230 | } |
231 | 231 | ||
232 | if (oc && oc->background) { | 232 | if (output->bg_pid != 0) { |
233 | if (output->bg_pid != 0) { | 233 | terminate_swaybg(output->bg_pid); |
234 | terminate_swaybg(output->bg_pid); | 234 | } |
235 | } | 235 | if (oc && oc->background && config->swaybg_command) { |
236 | |||
237 | wlr_log(WLR_DEBUG, "Setting background for output %d to %s", | 236 | wlr_log(WLR_DEBUG, "Setting background for output %d to %s", |
238 | output_i, oc->background); | 237 | output_i, oc->background); |
239 | 238 | ||
240 | size_t len = snprintf(NULL, 0, "%s %d \"%s\" %s %s", | 239 | size_t len = snprintf(NULL, 0, "%s %d \"%s\" %s %s", |
241 | config->swaybg_command ? config->swaybg_command : "swaybg", | 240 | config->swaybg_command, output_i, oc->background, |
242 | output_i, oc->background, oc->background_option, | 241 | oc->background_option, |
243 | oc->background_fallback ? oc->background_fallback : ""); | 242 | oc->background_fallback ? oc->background_fallback : ""); |
244 | char *command = malloc(len + 1); | 243 | char *command = malloc(len + 1); |
245 | if (!command) { | 244 | if (!command) { |
@@ -247,8 +246,8 @@ void apply_output_config(struct output_config *oc, struct sway_output *output) { | |||
247 | return; | 246 | return; |
248 | } | 247 | } |
249 | snprintf(command, len + 1, "%s %d \"%s\" %s %s", | 248 | snprintf(command, len + 1, "%s %d \"%s\" %s %s", |
250 | config->swaybg_command ? config->swaybg_command : "swaybg", | 249 | config->swaybg_command, output_i, oc->background, |
251 | output_i, oc->background, oc->background_option, | 250 | oc->background_option, |
252 | oc->background_fallback ? oc->background_fallback : ""); | 251 | oc->background_fallback ? oc->background_fallback : ""); |
253 | wlr_log(WLR_DEBUG, "-> %s", command); | 252 | wlr_log(WLR_DEBUG, "-> %s", command); |
254 | 253 | ||
@@ -260,6 +259,7 @@ void apply_output_config(struct output_config *oc, struct sway_output *output) { | |||
260 | free(command); | 259 | free(command); |
261 | } | 260 | } |
262 | } | 261 | } |
262 | |||
263 | if (oc) { | 263 | if (oc) { |
264 | switch (oc->dpms_state) { | 264 | switch (oc->dpms_state) { |
265 | case DPMS_ON: | 265 | case DPMS_ON: |
@@ -353,4 +353,3 @@ void create_default_output_configs(void) { | |||
353 | list_add(config->output_configs, oc); | 353 | list_add(config->output_configs, oc); |
354 | } | 354 | } |
355 | } | 355 | } |
356 | |||
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index cfb5a710..adc1ee10 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -329,6 +329,14 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) { | |||
329 | workspace->current.fullscreen, &data); | 329 | workspace->current.fullscreen, &data); |
330 | container_for_each_child(workspace->current.fullscreen, | 330 | container_for_each_child(workspace->current.fullscreen, |
331 | send_frame_done_container_iterator, &data); | 331 | send_frame_done_container_iterator, &data); |
332 | for (int i = 0; i < workspace->current.floating->length; ++i) { | ||
333 | struct sway_container *floater = | ||
334 | workspace->current.floating->items[i]; | ||
335 | if (container_is_transient_for(floater, | ||
336 | workspace->current.fullscreen)) { | ||
337 | send_frame_done_container_iterator(floater, &data); | ||
338 | } | ||
339 | } | ||
332 | #ifdef HAVE_XWAYLAND | 340 | #ifdef HAVE_XWAYLAND |
333 | send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when); | 341 | send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when); |
334 | #endif | 342 | #endif |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index c8b08a58..3617da87 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -961,6 +961,14 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
961 | render_container(output, damage, fullscreen_con, | 961 | render_container(output, damage, fullscreen_con, |
962 | fullscreen_con->current.focused); | 962 | fullscreen_con->current.focused); |
963 | } | 963 | } |
964 | |||
965 | for (int i = 0; i < workspace->current.floating->length; ++i) { | ||
966 | struct sway_container *floater = | ||
967 | workspace->current.floating->items[i]; | ||
968 | if (container_is_transient_for(floater, fullscreen_con)) { | ||
969 | render_floating_container(output, damage, floater); | ||
970 | } | ||
971 | } | ||
964 | #ifdef HAVE_XWAYLAND | 972 | #ifdef HAVE_XWAYLAND |
965 | render_unmanaged(output, damage, &root->xwayland_unmanaged); | 973 | render_unmanaged(output, damage, &root->xwayland_unmanaged); |
966 | #endif | 974 | #endif |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 2e2815c1..46582204 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -207,6 +207,21 @@ static void for_each_popup(struct sway_view *view, | |||
207 | wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, iterator, user_data); | 207 | wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, iterator, user_data); |
208 | } | 208 | } |
209 | 209 | ||
210 | static bool is_transient_for(struct sway_view *child, | ||
211 | struct sway_view *ancestor) { | ||
212 | if (xdg_shell_view_from_view(child) == NULL) { | ||
213 | return false; | ||
214 | } | ||
215 | struct wlr_xdg_surface *surface = child->wlr_xdg_surface; | ||
216 | while (surface) { | ||
217 | if (surface->toplevel->parent == ancestor->wlr_xdg_surface) { | ||
218 | return true; | ||
219 | } | ||
220 | surface = surface->toplevel->parent; | ||
221 | } | ||
222 | return false; | ||
223 | } | ||
224 | |||
210 | static void _close(struct sway_view *view) { | 225 | static void _close(struct sway_view *view) { |
211 | if (xdg_shell_view_from_view(view) == NULL) { | 226 | if (xdg_shell_view_from_view(view) == NULL) { |
212 | return; | 227 | return; |
@@ -248,6 +263,7 @@ static const struct sway_view_impl view_impl = { | |||
248 | .wants_floating = wants_floating, | 263 | .wants_floating = wants_floating, |
249 | .for_each_surface = for_each_surface, | 264 | .for_each_surface = for_each_surface, |
250 | .for_each_popup = for_each_popup, | 265 | .for_each_popup = for_each_popup, |
266 | .is_transient_for = is_transient_for, | ||
251 | .close = _close, | 267 | .close = _close, |
252 | .close_popups = close_popups, | 268 | .close_popups = close_popups, |
253 | .destroy = destroy, | 269 | .destroy = destroy, |
@@ -410,6 +426,7 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
410 | arrange_workspace(view->container->workspace); | 426 | arrange_workspace(view->container->workspace); |
411 | } | 427 | } |
412 | } | 428 | } |
429 | |||
413 | transaction_commit_dirty(); | 430 | transaction_commit_dirty(); |
414 | 431 | ||
415 | xdg_shell_view->commit.notify = handle_commit; | 432 | xdg_shell_view->commit.notify = handle_commit; |
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c index e61bd652..165cc7eb 100644 --- a/sway/desktop/xdg_shell_v6.c +++ b/sway/desktop/xdg_shell_v6.c | |||
@@ -204,6 +204,21 @@ static void for_each_popup(struct sway_view *view, | |||
204 | user_data); | 204 | user_data); |
205 | } | 205 | } |
206 | 206 | ||
207 | static bool is_transient_for(struct sway_view *child, | ||
208 | struct sway_view *ancestor) { | ||
209 | if (xdg_shell_v6_view_from_view(child) == NULL) { | ||
210 | return false; | ||
211 | } | ||
212 | struct wlr_xdg_surface_v6 *surface = child->wlr_xdg_surface_v6; | ||
213 | while (surface) { | ||
214 | if (surface->toplevel->parent == ancestor->wlr_xdg_surface_v6) { | ||
215 | return true; | ||
216 | } | ||
217 | surface = surface->toplevel->parent; | ||
218 | } | ||
219 | return false; | ||
220 | } | ||
221 | |||
207 | static void _close(struct sway_view *view) { | 222 | static void _close(struct sway_view *view) { |
208 | if (xdg_shell_v6_view_from_view(view) == NULL) { | 223 | if (xdg_shell_v6_view_from_view(view) == NULL) { |
209 | return; | 224 | return; |
@@ -245,6 +260,7 @@ static const struct sway_view_impl view_impl = { | |||
245 | .wants_floating = wants_floating, | 260 | .wants_floating = wants_floating, |
246 | .for_each_surface = for_each_surface, | 261 | .for_each_surface = for_each_surface, |
247 | .for_each_popup = for_each_popup, | 262 | .for_each_popup = for_each_popup, |
263 | .is_transient_for = is_transient_for, | ||
248 | .close = _close, | 264 | .close = _close, |
249 | .close_popups = close_popups, | 265 | .close_popups = close_popups, |
250 | .destroy = destroy, | 266 | .destroy = destroy, |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index 4c710f7e..ebf2131e 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include "sway/tree/arrange.h" | 15 | #include "sway/tree/arrange.h" |
16 | #include "sway/tree/container.h" | 16 | #include "sway/tree/container.h" |
17 | #include "sway/tree/view.h" | 17 | #include "sway/tree/view.h" |
18 | #include "sway/tree/workspace.h" | ||
18 | 19 | ||
19 | static const char *atom_map[ATOM_LAST] = { | 20 | static const char *atom_map[ATOM_LAST] = { |
20 | "_NET_WM_WINDOW_TYPE_NORMAL", | 21 | "_NET_WM_WINDOW_TYPE_NORMAL", |
@@ -253,6 +254,21 @@ static void handle_set_decorations(struct wl_listener *listener, void *data) { | |||
253 | view_update_csd_from_client(view, csd); | 254 | view_update_csd_from_client(view, csd); |
254 | } | 255 | } |
255 | 256 | ||
257 | static bool is_transient_for(struct sway_view *child, | ||
258 | struct sway_view *ancestor) { | ||
259 | if (xwayland_view_from_view(child) == NULL) { | ||
260 | return false; | ||
261 | } | ||
262 | struct wlr_xwayland_surface *surface = child->wlr_xwayland_surface; | ||
263 | while (surface) { | ||
264 | if (surface->parent == ancestor->wlr_xwayland_surface) { | ||
265 | return true; | ||
266 | } | ||
267 | surface = surface->parent; | ||
268 | } | ||
269 | return false; | ||
270 | } | ||
271 | |||
256 | static void _close(struct sway_view *view) { | 272 | static void _close(struct sway_view *view) { |
257 | if (xwayland_view_from_view(view) == NULL) { | 273 | if (xwayland_view_from_view(view) == NULL) { |
258 | return; | 274 | return; |
@@ -276,6 +292,7 @@ static const struct sway_view_impl view_impl = { | |||
276 | .set_tiled = set_tiled, | 292 | .set_tiled = set_tiled, |
277 | .set_fullscreen = set_fullscreen, | 293 | .set_fullscreen = set_fullscreen, |
278 | .wants_floating = wants_floating, | 294 | .wants_floating = wants_floating, |
295 | .is_transient_for = is_transient_for, | ||
279 | .close = _close, | 296 | .close = _close, |
280 | .destroy = destroy, | 297 | .destroy = destroy, |
281 | }; | 298 | }; |
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 331c6c7e..6d57c45f 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -98,6 +98,18 @@ static struct sway_node *node_at_coords( | |||
98 | return NULL; | 98 | return NULL; |
99 | } | 99 | } |
100 | if (ws->fullscreen) { | 100 | if (ws->fullscreen) { |
101 | // Try transient containers | ||
102 | for (int i = 0; i < ws->floating->length; ++i) { | ||
103 | struct sway_container *floater = ws->floating->items[i]; | ||
104 | if (container_is_transient_for(floater, ws->fullscreen)) { | ||
105 | struct sway_container *con = tiling_container_at( | ||
106 | &floater->node, lx, ly, surface, sx, sy); | ||
107 | if (con) { | ||
108 | return &con->node; | ||
109 | } | ||
110 | } | ||
111 | } | ||
112 | // Try fullscreen container | ||
101 | struct sway_container *con = | 113 | struct sway_container *con = |
102 | tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy); | 114 | tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy); |
103 | if (con) { | 115 | if (con) { |
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index 5fc8a806..fb1fe7b5 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c | |||
@@ -264,31 +264,27 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
264 | } | 264 | } |
265 | 265 | ||
266 | // Identify and execute active pressed binding | 266 | // Identify and execute active pressed binding |
267 | struct sway_binding *next_repeat_binding = NULL; | 267 | struct sway_binding *binding = NULL; |
268 | if (event->state == WLR_KEY_PRESSED) { | 268 | if (event->state == WLR_KEY_PRESSED) { |
269 | struct sway_binding *binding_pressed = NULL; | ||
270 | get_active_binding(&keyboard->state_keycodes, | 269 | get_active_binding(&keyboard->state_keycodes, |
271 | config->current_mode->keycode_bindings, &binding_pressed, | 270 | config->current_mode->keycode_bindings, &binding, |
272 | code_modifiers, false, input_inhibited); | 271 | code_modifiers, false, input_inhibited); |
273 | get_active_binding(&keyboard->state_keysyms_translated, | 272 | get_active_binding(&keyboard->state_keysyms_translated, |
274 | config->current_mode->keysym_bindings, &binding_pressed, | 273 | config->current_mode->keysym_bindings, &binding, |
275 | translated_modifiers, false, input_inhibited); | 274 | translated_modifiers, false, input_inhibited); |
276 | get_active_binding(&keyboard->state_keysyms_raw, | 275 | get_active_binding(&keyboard->state_keysyms_raw, |
277 | config->current_mode->keysym_bindings, &binding_pressed, | 276 | config->current_mode->keysym_bindings, &binding, |
278 | raw_modifiers, false, input_inhibited); | 277 | raw_modifiers, false, input_inhibited); |
279 | 278 | ||
280 | if (binding_pressed) { | 279 | if (binding) { |
281 | if ((binding_pressed->flags & BINDING_RELOAD) == 0) { | 280 | seat_execute_command(seat, binding); |
282 | next_repeat_binding = binding_pressed; | ||
283 | } | ||
284 | seat_execute_command(seat, binding_pressed); | ||
285 | handled = true; | 281 | handled = true; |
286 | } | 282 | } |
287 | } | 283 | } |
288 | 284 | ||
289 | // Set up (or clear) keyboard repeat for a pressed binding | 285 | // Set up (or clear) keyboard repeat for a pressed binding |
290 | if (next_repeat_binding && wlr_device->keyboard->repeat_info.delay > 0) { | 286 | if (binding && wlr_device->keyboard->repeat_info.delay > 0) { |
291 | keyboard->repeat_binding = next_repeat_binding; | 287 | keyboard->repeat_binding = binding; |
292 | if (wl_event_source_timer_update(keyboard->key_repeat_source, | 288 | if (wl_event_source_timer_update(keyboard->key_repeat_source, |
293 | wlr_device->keyboard->repeat_info.delay) < 0) { | 289 | wlr_device->keyboard->repeat_info.delay) < 0) { |
294 | wlr_log(WLR_DEBUG, "failed to set key repeat timer"); | 290 | wlr_log(WLR_DEBUG, "failed to set key repeat timer"); |
diff --git a/sway/input/seat.c b/sway/input/seat.c index f5cb2f9e..f418785d 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -655,7 +655,10 @@ void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node, | |||
655 | // Deny setting focus to a view which is hidden by a fullscreen container | 655 | // Deny setting focus to a view which is hidden by a fullscreen container |
656 | if (new_workspace && new_workspace->fullscreen && container && | 656 | if (new_workspace && new_workspace->fullscreen && container && |
657 | !container_is_fullscreen_or_child(container)) { | 657 | !container_is_fullscreen_or_child(container)) { |
658 | return; | 658 | // Unless it's a transient container |
659 | if (!container_is_transient_for(container, new_workspace->fullscreen)) { | ||
660 | return; | ||
661 | } | ||
659 | } | 662 | } |
660 | 663 | ||
661 | struct sway_output *last_output = last_workspace ? | 664 | struct sway_output *last_output = last_workspace ? |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 7c5a0a5d..f02f370b 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -514,8 +514,8 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) { | |||
514 | json_object_new_string(bar->hidden_state)); | 514 | json_object_new_string(bar->hidden_state)); |
515 | json_object_object_add(json, "position", | 515 | json_object_object_add(json, "position", |
516 | json_object_new_string(bar->position)); | 516 | json_object_new_string(bar->position)); |
517 | json_object_object_add(json, "status_command", | 517 | json_object_object_add(json, "status_command", bar->status_command ? |
518 | json_object_new_string(bar->status_command)); | 518 | json_object_new_string(bar->status_command) : NULL); |
519 | json_object_object_add(json, "font", | 519 | json_object_object_add(json, "font", |
520 | json_object_new_string((bar->font) ? bar->font : config->font)); | 520 | json_object_new_string((bar->font) ? bar->font : config->font)); |
521 | if (bar->separator_symbol) { | 521 | if (bar->separator_symbol) { |
diff --git a/sway/meson.build b/sway/meson.build index 8ab28869..c7fc9697 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -70,6 +70,7 @@ sway_sources = files( | |||
70 | 'commands/no_focus.c', | 70 | 'commands/no_focus.c', |
71 | 'commands/nop.c', | 71 | 'commands/nop.c', |
72 | 'commands/output.c', | 72 | 'commands/output.c', |
73 | 'commands/popup_during_fullscreen.c', | ||
73 | 'commands/reload.c', | 74 | 'commands/reload.c', |
74 | 'commands/rename.c', | 75 | 'commands/rename.c', |
75 | 'commands/resize.c', | 76 | 'commands/resize.c', |
diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd index 00b9386e..8c7be8e7 100644 --- a/sway/sway-bar.5.scd +++ b/sway/sway-bar.5.scd | |||
@@ -17,6 +17,9 @@ Sway allows configuring swaybar in the sway configuration file. | |||
17 | 17 | ||
18 | https://i3wm.org/docs/i3bar-protocol.html | 18 | https://i3wm.org/docs/i3bar-protocol.html |
19 | 19 | ||
20 | If running this command via IPC, you can disable a running status command by | ||
21 | setting the command to a single dash: _swaybar bar bar-0 status\_command -_ | ||
22 | |||
20 | *pango\_markup* enabled|disabled | 23 | *pango\_markup* enabled|disabled |
21 | Enables or disables pango markup for status lines. This has no effect on | 24 | Enables or disables pango markup for status lines. This has no effect on |
22 | status lines using the i3bar JSON protocol. | 25 | status lines using the i3bar JSON protocol. |
diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 3fda6cef..28ab15df 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd | |||
@@ -71,6 +71,9 @@ The following commands may only be used in the configuration file. | |||
71 | Executes custom background _command_. Default is _swaybg_. Refer to | 71 | Executes custom background _command_. Default is _swaybg_. Refer to |
72 | *output* below for more information. | 72 | *output* below for more information. |
73 | 73 | ||
74 | It can be disabled by setting the command to a single dash: | ||
75 | _swaybg\_command -_ | ||
76 | |||
74 | *swaynag\_command* <command> | 77 | *swaynag\_command* <command> |
75 | Executes custom command for _swaynag_. Default is _swaynag_. Additional | 78 | Executes custom command for _swaynag_. Default is _swaynag_. Additional |
76 | arguments may be appended to the end. This should only be used to either | 79 | arguments may be appended to the end. This should only be used to either |
@@ -78,6 +81,9 @@ The following commands may only be used in the configuration file. | |||
78 | arguments. This should be placed at the top of the config for the best | 81 | arguments. This should be placed at the top of the config for the best |
79 | results. | 82 | results. |
80 | 83 | ||
84 | It can be disabled by setting the command to a single dash: | ||
85 | _swaynag\_command -_ | ||
86 | |||
81 | The following commands cannot be used directly in the configuration file. | 87 | The following commands cannot be used directly in the configuration file. |
82 | They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). | 88 | They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). |
83 | 89 | ||
@@ -549,6 +555,12 @@ You may combine output commands into one, like so: | |||
549 | You can get a list of output names with *swaymsg -t get\_outputs*. You may also | 555 | You can get a list of output names with *swaymsg -t get\_outputs*. You may also |
550 | match any output by using the output name "\*". | 556 | match any output by using the output name "\*". |
551 | 557 | ||
558 | *popup\_during\_fullscreen* smart|ignore|leave\_fullscreen | ||
559 | Determines what to do when a fullscreen view opens a dialog. | ||
560 | If _smart_ (the default), the dialog will be displayed. If _ignore_, the | ||
561 | dialog will not be rendered. If _leave\_fullscreen_, the view will exit | ||
562 | fullscreen mode and the dialog will be rendered. | ||
563 | |||
552 | *set* $<name> <value> | 564 | *set* $<name> <value> |
553 | Sets variable $_name_ to _value_. You can use the new variable in the | 565 | Sets variable $_name_ to _value_. You can use the new variable in the |
554 | arguments of future commands. When the variable is used, it can be escaped | 566 | arguments of future commands. When the variable is used, it can be escaped |
diff --git a/sway/swaynag.c b/sway/swaynag.c index d905db2b..38e74b88 100644 --- a/sway/swaynag.c +++ b/sway/swaynag.c | |||
@@ -11,6 +11,10 @@ | |||
11 | 11 | ||
12 | bool swaynag_spawn(const char *swaynag_command, | 12 | bool swaynag_spawn(const char *swaynag_command, |
13 | struct swaynag_instance *swaynag) { | 13 | struct swaynag_instance *swaynag) { |
14 | if (!swaynag_command) { | ||
15 | return true; | ||
16 | } | ||
17 | |||
14 | if (swaynag->detailed) { | 18 | if (swaynag->detailed) { |
15 | if (pipe(swaynag->fd) != 0) { | 19 | if (pipe(swaynag->fd) != 0) { |
16 | wlr_log(WLR_ERROR, "Failed to create pipe for swaynag"); | 20 | wlr_log(WLR_ERROR, "Failed to create pipe for swaynag"); |
@@ -58,6 +62,10 @@ void swaynag_kill(struct swaynag_instance *swaynag) { | |||
58 | 62 | ||
59 | void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, | 63 | void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, |
60 | const char *fmt, ...) { | 64 | const char *fmt, ...) { |
65 | if (!swaynag_command) { | ||
66 | return; | ||
67 | } | ||
68 | |||
61 | if (!swaynag->detailed) { | 69 | if (!swaynag->detailed) { |
62 | wlr_log(WLR_ERROR, "Attempting to write to non-detailed swaynag inst"); | 70 | wlr_log(WLR_ERROR, "Attempting to write to non-detailed swaynag inst"); |
63 | return; | 71 | return; |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 9db7aed1..1664514a 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -1212,3 +1212,10 @@ struct sway_container *container_split(struct sway_container *child, | |||
1212 | 1212 | ||
1213 | return cont; | 1213 | return cont; |
1214 | } | 1214 | } |
1215 | |||
1216 | bool container_is_transient_for(struct sway_container *child, | ||
1217 | struct sway_container *ancestor) { | ||
1218 | return config->popup_during_fullscreen == POPUP_SMART && | ||
1219 | child->view && ancestor->view && | ||
1220 | view_is_transient_for(child->view, ancestor->view); | ||
1221 | } | ||
diff --git a/sway/tree/view.c b/sway/tree/view.c index ae73a687..1f00452d 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -576,6 +576,16 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) { | |||
576 | view_set_tiled(view, true); | 576 | view_set_tiled(view, true); |
577 | } | 577 | } |
578 | 578 | ||
579 | if (config->popup_during_fullscreen == POPUP_LEAVE && | ||
580 | view->container->workspace && | ||
581 | view->container->workspace->fullscreen && | ||
582 | view->container->workspace->fullscreen->view) { | ||
583 | struct sway_container *fs = view->container->workspace->fullscreen; | ||
584 | if (view_is_transient_for(view, fs->view)) { | ||
585 | container_set_fullscreen(fs, false); | ||
586 | } | ||
587 | } | ||
588 | |||
579 | if (should_focus(view)) { | 589 | if (should_focus(view)) { |
580 | input_manager_set_focus(input_manager, &view->container->node); | 590 | input_manager_set_focus(input_manager, &view->container->node); |
581 | } | 591 | } |
@@ -1080,7 +1090,12 @@ bool view_is_visible(struct sway_view *view) { | |||
1080 | // Check view isn't hidden by another fullscreen view | 1090 | // Check view isn't hidden by another fullscreen view |
1081 | if (workspace->fullscreen && | 1091 | if (workspace->fullscreen && |
1082 | !container_is_fullscreen_or_child(view->container)) { | 1092 | !container_is_fullscreen_or_child(view->container)) { |
1083 | return false; | 1093 | // However, if we're transient for the fullscreen view and we allow |
1094 | // "popups" during fullscreen then it might be visible | ||
1095 | if (!container_is_transient_for(view->container, | ||
1096 | workspace->fullscreen)) { | ||
1097 | return false; | ||
1098 | } | ||
1084 | } | 1099 | } |
1085 | return true; | 1100 | return true; |
1086 | } | 1101 | } |
@@ -1133,3 +1148,9 @@ void view_save_buffer(struct sway_view *view) { | |||
1133 | view->saved_buffer_height = view->surface->current.height; | 1148 | view->saved_buffer_height = view->surface->current.height; |
1134 | } | 1149 | } |
1135 | } | 1150 | } |
1151 | |||
1152 | bool view_is_transient_for(struct sway_view *child, | ||
1153 | struct sway_view *ancestor) { | ||
1154 | return child->impl->is_transient_for && | ||
1155 | child->impl->is_transient_for(child, ancestor); | ||
1156 | } | ||
diff --git a/swaybar/bar.c b/swaybar/bar.c index c86e71b8..3990f1ca 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c | |||
@@ -572,8 +572,8 @@ void bar_run(struct swaybar *bar) { | |||
572 | add_event(bar->status->read_fd, POLLIN, status_in, bar); | 572 | add_event(bar->status->read_fd, POLLIN, status_in, bar); |
573 | } | 573 | } |
574 | while (1) { | 574 | while (1) { |
575 | event_loop_poll(); | ||
576 | wl_display_flush(bar->display); | 575 | wl_display_flush(bar->display); |
576 | event_loop_poll(); | ||
577 | } | 577 | } |
578 | } | 578 | } |
579 | 579 | ||
diff --git a/swaynag/main.c b/swaynag/main.c index d1a0d236..bae3c0e2 100644 --- a/swaynag/main.c +++ b/swaynag/main.c | |||
@@ -36,7 +36,7 @@ int main(int argc, char **argv) { | |||
36 | 36 | ||
37 | swaynag.details.button_details = | 37 | swaynag.details.button_details = |
38 | calloc(sizeof(struct swaynag_button), 1); | 38 | calloc(sizeof(struct swaynag_button), 1); |
39 | swaynag.details.button_details->text = strdup("Toggle Details"); | 39 | swaynag.details.button_details->text = strdup("Toggle details"); |
40 | swaynag.details.button_details->type = SWAYNAG_ACTION_EXPAND; | 40 | swaynag.details.button_details->type = SWAYNAG_ACTION_EXPAND; |
41 | 41 | ||
42 | char *config_path = NULL; | 42 | char *config_path = NULL; |
diff --git a/swaynag/swaynag.1.scd b/swaynag/swaynag.1.scd index 1c395aee..bb69e47d 100644 --- a/swaynag/swaynag.1.scd +++ b/swaynag/swaynag.1.scd | |||
@@ -40,7 +40,7 @@ _swaynag_ [options...] | |||
40 | 40 | ||
41 | *-L, --detailed-button* <text> | 41 | *-L, --detailed-button* <text> |
42 | Set the text for the button that toggles details. This has no effect if | 42 | Set the text for the button that toggles details. This has no effect if |
43 | there is not a detailed message. The default is _Toggle Details_. | 43 | there is not a detailed message. The default is _Toggle details_. |
44 | 44 | ||
45 | *-m, --message* <msg> | 45 | *-m, --message* <msg> |
46 | Set the message text. | 46 | Set the message text. |
diff --git a/swaynag/swaynag.c b/swaynag/swaynag.c index 26d3589e..69da851e 100644 --- a/swaynag/swaynag.c +++ b/swaynag/swaynag.c | |||
@@ -390,6 +390,10 @@ void swaynag_run(struct swaynag *swaynag) { | |||
390 | && wl_display_dispatch(swaynag->display) != -1) { | 390 | && wl_display_dispatch(swaynag->display) != -1) { |
391 | // This is intentionally left blank | 391 | // This is intentionally left blank |
392 | } | 392 | } |
393 | |||
394 | if (swaynag->display) { | ||
395 | wl_display_disconnect(swaynag->display); | ||
396 | } | ||
393 | } | 397 | } |
394 | 398 | ||
395 | void swaynag_destroy(struct swaynag *swaynag) { | 399 | void swaynag_destroy(struct swaynag *swaynag) { |
@@ -449,8 +453,4 @@ void swaynag_destroy(struct swaynag *swaynag) { | |||
449 | if (swaynag->shm) { | 453 | if (swaynag->shm) { |
450 | wl_shm_destroy(swaynag->shm); | 454 | wl_shm_destroy(swaynag->shm); |
451 | } | 455 | } |
452 | |||
453 | if (swaynag->display) { | ||
454 | wl_display_disconnect(swaynag->display); | ||
455 | } | ||
456 | } | 456 | } |