aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config.in5
-rw-r--r--include/sway/commands.h2
-rw-r--r--include/sway/config.h8
-rw-r--r--include/sway/tree/container.h3
-rw-r--r--include/sway/tree/view.h4
-rw-r--r--sway/commands.c3
-rw-r--r--sway/commands/bar.c14
-rw-r--r--sway/commands/bar/status_command.c18
-rw-r--r--sway/commands/bind.c49
-rw-r--r--sway/commands/client.c15
-rw-r--r--sway/commands/opacity.c4
-rw-r--r--sway/commands/popup_during_fullscreen.c25
-rw-r--r--sway/commands/reload.c36
-rw-r--r--sway/commands/seat/attach.c4
-rw-r--r--sway/commands/seat/fallback.c4
-rw-r--r--sway/commands/swaybg_command.c15
-rw-r--r--sway/commands/swaynag_command.c15
-rw-r--r--sway/commands/urgent.c3
-rw-r--r--sway/config.c13
-rw-r--r--sway/config/bar.c4
-rw-r--r--sway/config/output.c19
-rw-r--r--sway/desktop/output.c8
-rw-r--r--sway/desktop/render.c8
-rw-r--r--sway/desktop/xdg_shell.c17
-rw-r--r--sway/desktop/xdg_shell_v6.c16
-rw-r--r--sway/desktop/xwayland.c17
-rw-r--r--sway/input/cursor.c12
-rw-r--r--sway/input/keyboard.c20
-rw-r--r--sway/input/seat.c5
-rw-r--r--sway/ipc-json.c4
-rw-r--r--sway/meson.build1
-rw-r--r--sway/sway-bar.5.scd3
-rw-r--r--sway/sway.5.scd12
-rw-r--r--sway/swaynag.c8
-rw-r--r--sway/tree/container.c7
-rw-r--r--sway/tree/view.c23
-rw-r--r--swaybar/bar.c2
-rw-r--r--swaynag/main.c2
-rw-r--r--swaynag/swaynag.1.scd2
-rw-r--r--swaynag/swaynag.c8
40 files changed, 314 insertions, 124 deletions
diff --git a/config.in b/config.in
index 124f825d..72523816 100644
--- a/config.in
+++ b/config.in
@@ -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.
203bar { 203bar {
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;
103sway_cmd cmd_bindcode; 103sway_cmd cmd_bindcode;
104sway_cmd cmd_bindsym; 104sway_cmd cmd_bindsym;
105sway_cmd cmd_border; 105sway_cmd cmd_border;
106sway_cmd cmd_client_noop;
106sway_cmd cmd_client_focused; 107sway_cmd cmd_client_focused;
107sway_cmd cmd_client_focused_inactive; 108sway_cmd cmd_client_focused_inactive;
108sway_cmd cmd_client_unfocused; 109sway_cmd cmd_client_unfocused;
@@ -153,6 +154,7 @@ sway_cmd cmd_new_window;
153sway_cmd cmd_no_focus; 154sway_cmd cmd_no_focus;
154sway_cmd cmd_output; 155sway_cmd cmd_output;
155sway_cmd cmd_permit; 156sway_cmd cmd_permit;
157sway_cmd cmd_popup_during_fullscreen;
156sway_cmd cmd_reject; 158sway_cmd cmd_reject;
157sway_cmd cmd_reload; 159sway_cmd cmd_reload;
158sway_cmd cmd_rename; 160sway_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
259enum sway_popup_during_fullscreen {
260 POPUP_SMART,
261 POPUP_IGNORE,
262 POPUP_LEAVE,
263};
264
260enum command_context { 265enum 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);
292struct sway_container *container_split(struct sway_container *child, 292struct sway_container *container_split(struct sway_container *child,
293 enum sway_container_layout layout); 293 enum sway_container_layout layout);
294 294
295bool 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
400void view_save_buffer(struct sway_view *view); 402void view_save_buffer(struct sway_view *view);
401 403
404bool 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
33static 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 */
308void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { 278void 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) {
114struct cmd_results *cmd_client_urgent(int argc, char **argv) { 114struct 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
118struct 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
5struct 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
9struct cmd_results *cmd_reload(int argc, char **argv) { 11static 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
46struct 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
168static void config_defaults(struct sway_config *config) { 170static 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
210static 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
210static void _close(struct sway_view *view) { 225static 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
207static 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
207static void _close(struct sway_view *view) { 222static 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
19static const char *atom_map[ATOM_LAST] = { 20static 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
257static 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
256static void _close(struct sway_view *view) { 272static 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
81The following commands cannot be used directly in the configuration file. 87The following commands cannot be used directly in the configuration file.
82They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). 88They 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:
549You can get a list of output names with *swaymsg -t get\_outputs*. You may also 555You can get a list of output names with *swaymsg -t get\_outputs*. You may also
550match any output by using the output name "\*". 556match 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
12bool swaynag_spawn(const char *swaynag_command, 12bool 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
59void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, 63void 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
1216bool 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
1152bool 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
395void swaynag_destroy(struct swaynag *swaynag) { 399void 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}