aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Brian Ashworth <RedSoxFan@users.noreply.github.com>2018-10-08 15:28:09 -0400
committerLibravatar GitHub <noreply@github.com>2018-10-08 15:28:09 -0400
commita999269e1cf8eeb423547a0c8ab3420f27628168 (patch)
tree3572a9e1bff58710c22638d85ce1206af3999d94
parentMerge pull request #2799 from ianyfan/commands (diff)
parentMerge branch 'master' into popup-during-fullscreen (diff)
downloadsway-a999269e1cf8eeb423547a0c8ab3420f27628168.tar.gz
sway-a999269e1cf8eeb423547a0c8ab3420f27628168.tar.zst
sway-a999269e1cf8eeb423547a0c8ab3420f27628168.zip
Merge pull request #2782 from RyanDwyer/popup-during-fullscreen
Implement popup_during_fullscreen
-rw-r--r--include/sway/commands.h1
-rw-r--r--include/sway/config.h7
-rw-r--r--include/sway/tree/container.h3
-rw-r--r--include/sway/tree/view.h4
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/popup_during_fullscreen.c25
-rw-r--r--sway/config.c1
-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/seat.c5
-rw-r--r--sway/meson.build1
-rw-r--r--sway/sway.5.scd6
-rw-r--r--sway/tree/container.c7
-rw-r--r--sway/tree/view.c23
18 files changed, 160 insertions, 2 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 21b8b87a..48228a98 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -154,6 +154,7 @@ sway_cmd cmd_new_window;
154sway_cmd cmd_no_focus; 154sway_cmd cmd_no_focus;
155sway_cmd cmd_output; 155sway_cmd cmd_output;
156sway_cmd cmd_permit; 156sway_cmd cmd_permit;
157sway_cmd cmd_popup_during_fullscreen;
157sway_cmd cmd_reject; 158sway_cmd cmd_reject;
158sway_cmd cmd_reload; 159sway_cmd cmd_reload;
159sway_cmd cmd_rename; 160sway_cmd cmd_rename;
diff --git a/include/sway/config.h b/include/sway/config.h
index 0e51fbfb..00b5f25b 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -256,6 +256,12 @@ enum edge_border_types {
256 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 */
257}; 257};
258 258
259enum sway_popup_during_fullscreen {
260 POPUP_SMART,
261 POPUP_IGNORE,
262 POPUP_LEAVE,
263};
264
259enum command_context { 265enum command_context {
260 CONTEXT_CONFIG = 1, 266 CONTEXT_CONFIG = 1,
261 CONTEXT_BINDING = 2, 267 CONTEXT_BINDING = 2,
@@ -355,6 +361,7 @@ struct sway_config {
355 bool pango_markup; 361 bool pango_markup;
356 size_t urgent_timeout; 362 size_t urgent_timeout;
357 enum sway_fowa focus_on_window_activation; 363 enum sway_fowa focus_on_window_activation;
364 enum sway_popup_during_fullscreen popup_during_fullscreen;
358 365
359 // Flags 366 // Flags
360 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 028be536..eb1e98e1 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);
@@ -396,4 +398,6 @@ void view_remove_saved_buffer(struct sway_view *view);
396 398
397void view_save_buffer(struct sway_view *view); 399void view_save_buffer(struct sway_view *view);
398 400
401bool view_is_transient_for(struct sway_view *child, struct sway_view *ancestor);
402
399#endif 403#endif
diff --git a/sway/commands.c b/sway/commands.c
index 780cd7d6..8db1df01 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -109,6 +109,7 @@ static struct cmd_handler handlers[] = {
109 { "new_window", cmd_default_border }, 109 { "new_window", cmd_default_border },
110 { "no_focus", cmd_no_focus }, 110 { "no_focus", cmd_no_focus },
111 { "output", cmd_output }, 111 { "output", cmd_output },
112 { "popup_during_fullscreen", cmd_popup_during_fullscreen },
112 { "raise_floating", cmd_raise_floating }, 113 { "raise_floating", cmd_raise_floating },
113 { "seat", cmd_seat }, 114 { "seat", cmd_seat },
114 { "set", cmd_set }, 115 { "set", cmd_set },
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/config.c b/sway/config.c
index e95c7b35..a50e9144 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -214,6 +214,7 @@ static void config_defaults(struct sway_config *config) {
214 if (!(config->font = strdup("monospace 10"))) goto cleanup; 214 if (!(config->font = strdup("monospace 10"))) goto cleanup;
215 config->font_height = 17; // height of monospace 10 215 config->font_height = 17; // height of monospace 10
216 config->urgent_timeout = 500; 216 config->urgent_timeout = 500;
217 config->popup_during_fullscreen = POPUP_SMART;
217 218
218 // floating view 219 // floating view
219 config->floating_maximum_width = 0; 220 config->floating_maximum_width = 0;
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 a8b527a7..4690a3c5 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -192,6 +192,21 @@ static void for_each_popup(struct sway_view *view,
192 wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, iterator, user_data); 192 wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, iterator, user_data);
193} 193}
194 194
195static bool is_transient_for(struct sway_view *child,
196 struct sway_view *ancestor) {
197 if (xdg_shell_view_from_view(child) == NULL) {
198 return false;
199 }
200 struct wlr_xdg_surface *surface = child->wlr_xdg_surface;
201 while (surface) {
202 if (surface->toplevel->parent == ancestor->wlr_xdg_surface) {
203 return true;
204 }
205 surface = surface->toplevel->parent;
206 }
207 return false;
208}
209
195static void _close(struct sway_view *view) { 210static void _close(struct sway_view *view) {
196 if (xdg_shell_view_from_view(view) == NULL) { 211 if (xdg_shell_view_from_view(view) == NULL) {
197 return; 212 return;
@@ -233,6 +248,7 @@ static const struct sway_view_impl view_impl = {
233 .wants_floating = wants_floating, 248 .wants_floating = wants_floating,
234 .for_each_surface = for_each_surface, 249 .for_each_surface = for_each_surface,
235 .for_each_popup = for_each_popup, 250 .for_each_popup = for_each_popup,
251 .is_transient_for = is_transient_for,
236 .close = _close, 252 .close = _close,
237 .close_popups = close_popups, 253 .close_popups = close_popups,
238 .destroy = destroy, 254 .destroy = destroy,
@@ -395,6 +411,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
395 arrange_workspace(view->container->workspace); 411 arrange_workspace(view->container->workspace);
396 } 412 }
397 } 413 }
414
398 transaction_commit_dirty(); 415 transaction_commit_dirty();
399 416
400 xdg_shell_view->commit.notify = handle_commit; 417 xdg_shell_view->commit.notify = handle_commit;
diff --git a/sway/desktop/xdg_shell_v6.c b/sway/desktop/xdg_shell_v6.c
index a7838c0f..ff950c70 100644
--- a/sway/desktop/xdg_shell_v6.c
+++ b/sway/desktop/xdg_shell_v6.c
@@ -189,6 +189,21 @@ static void for_each_popup(struct sway_view *view,
189 user_data); 189 user_data);
190} 190}
191 191
192static bool is_transient_for(struct sway_view *child,
193 struct sway_view *ancestor) {
194 if (xdg_shell_v6_view_from_view(child) == NULL) {
195 return false;
196 }
197 struct wlr_xdg_surface_v6 *surface = child->wlr_xdg_surface_v6;
198 while (surface) {
199 if (surface->toplevel->parent == ancestor->wlr_xdg_surface_v6) {
200 return true;
201 }
202 surface = surface->toplevel->parent;
203 }
204 return false;
205}
206
192static void _close(struct sway_view *view) { 207static void _close(struct sway_view *view) {
193 if (xdg_shell_v6_view_from_view(view) == NULL) { 208 if (xdg_shell_v6_view_from_view(view) == NULL) {
194 return; 209 return;
@@ -230,6 +245,7 @@ static const struct sway_view_impl view_impl = {
230 .wants_floating = wants_floating, 245 .wants_floating = wants_floating,
231 .for_each_surface = for_each_surface, 246 .for_each_surface = for_each_surface,
232 .for_each_popup = for_each_popup, 247 .for_each_popup = for_each_popup,
248 .is_transient_for = is_transient_for,
233 .close = _close, 249 .close = _close,
234 .close_popups = close_popups, 250 .close_popups = close_popups,
235 .destroy = destroy, 251 .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/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/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.5.scd b/sway/sway.5.scd
index 43f0e132..28ab15df 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -555,6 +555,12 @@ You may combine output commands into one, like so:
555You 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
556match any output by using the output name "\*". 556match any output by using the output name "\*".
557 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
558*set* $<name> <value> 564*set* $<name> <value>
559 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
560 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/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 73ce55ac..97525d6b 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -575,6 +575,16 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
575 view_set_tiled(view, true); 575 view_set_tiled(view, true);
576 } 576 }
577 577
578 if (config->popup_during_fullscreen == POPUP_LEAVE &&
579 view->container->workspace &&
580 view->container->workspace->fullscreen &&
581 view->container->workspace->fullscreen->view) {
582 struct sway_container *fs = view->container->workspace->fullscreen;
583 if (view_is_transient_for(view, fs->view)) {
584 container_set_fullscreen(fs, false);
585 }
586 }
587
578 if (should_focus(view)) { 588 if (should_focus(view)) {
579 input_manager_set_focus(input_manager, &view->container->node); 589 input_manager_set_focus(input_manager, &view->container->node);
580 } 590 }
@@ -1042,7 +1052,12 @@ bool view_is_visible(struct sway_view *view) {
1042 // Check view isn't hidden by another fullscreen view 1052 // Check view isn't hidden by another fullscreen view
1043 if (workspace->fullscreen && 1053 if (workspace->fullscreen &&
1044 !container_is_fullscreen_or_child(view->container)) { 1054 !container_is_fullscreen_or_child(view->container)) {
1045 return false; 1055 // However, if we're transient for the fullscreen view and we allow
1056 // "popups" during fullscreen then it might be visible
1057 if (!container_is_transient_for(view->container,
1058 workspace->fullscreen)) {
1059 return false;
1060 }
1046 } 1061 }
1047 return true; 1062 return true;
1048} 1063}
@@ -1095,3 +1110,9 @@ void view_save_buffer(struct sway_view *view) {
1095 view->saved_buffer_height = view->surface->current.height; 1110 view->saved_buffer_height = view->surface->current.height;
1096 } 1111 }
1097} 1112}
1113
1114bool view_is_transient_for(struct sway_view *child,
1115 struct sway_view *ancestor) {
1116 return child->impl->is_transient_for &&
1117 child->impl->is_transient_for(child, ancestor);
1118}