Merge pull request #2782 from RyanDwyer/popup-during-fullscreen

Implement popup_during_fullscreen
This commit is contained in:
Brian Ashworth 2018-10-08 15:28:09 -04:00 committed by GitHub
commit a999269e1c
Failed to generate hash of commit
18 changed files with 160 additions and 2 deletions

View file

@ -154,6 +154,7 @@ sway_cmd cmd_new_window;
sway_cmd cmd_no_focus; sway_cmd cmd_no_focus;
sway_cmd cmd_output; sway_cmd cmd_output;
sway_cmd cmd_permit; sway_cmd cmd_permit;
sway_cmd cmd_popup_during_fullscreen;
sway_cmd cmd_reject; sway_cmd cmd_reject;
sway_cmd cmd_reload; sway_cmd cmd_reload;
sway_cmd cmd_rename; sway_cmd cmd_rename;

View file

@ -256,6 +256,12 @@ enum edge_border_types {
E_SMART_NO_GAPS, /**< hide both if one window and gaps to edge is zero */ E_SMART_NO_GAPS, /**< hide both if one window and gaps to edge is zero */
}; };
enum sway_popup_during_fullscreen {
POPUP_SMART,
POPUP_IGNORE,
POPUP_LEAVE,
};
enum command_context { enum command_context {
CONTEXT_CONFIG = 1, CONTEXT_CONFIG = 1,
CONTEXT_BINDING = 2, CONTEXT_BINDING = 2,
@ -355,6 +361,7 @@ struct sway_config {
bool pango_markup; bool pango_markup;
size_t urgent_timeout; size_t urgent_timeout;
enum sway_fowa focus_on_window_activation; enum sway_fowa focus_on_window_activation;
enum sway_popup_during_fullscreen popup_during_fullscreen;
// Flags // Flags
bool focus_follows_mouse; bool focus_follows_mouse;

View file

@ -292,4 +292,7 @@ bool sway_dir_to_wlr(enum movement_direction dir, enum wlr_direction *out);
struct sway_container *container_split(struct sway_container *child, struct sway_container *container_split(struct sway_container *child,
enum sway_container_layout layout); enum sway_container_layout layout);
bool container_is_transient_for(struct sway_container *child,
struct sway_container *ancestor);
#endif #endif

View file

@ -49,6 +49,8 @@ struct sway_view_impl {
wlr_surface_iterator_func_t iterator, void *user_data); wlr_surface_iterator_func_t iterator, void *user_data);
void (*for_each_popup)(struct sway_view *view, void (*for_each_popup)(struct sway_view *view,
wlr_surface_iterator_func_t iterator, void *user_data); wlr_surface_iterator_func_t iterator, void *user_data);
bool (*is_transient_for)(struct sway_view *child,
struct sway_view *ancestor);
void (*close)(struct sway_view *view); void (*close)(struct sway_view *view);
void (*close_popups)(struct sway_view *view); void (*close_popups)(struct sway_view *view);
void (*destroy)(struct sway_view *view); void (*destroy)(struct sway_view *view);
@ -396,4 +398,6 @@ void view_remove_saved_buffer(struct sway_view *view);
void view_save_buffer(struct sway_view *view); void view_save_buffer(struct sway_view *view);
bool view_is_transient_for(struct sway_view *child, struct sway_view *ancestor);
#endif #endif

View file

@ -109,6 +109,7 @@ static struct cmd_handler handlers[] = {
{ "new_window", cmd_default_border }, { "new_window", cmd_default_border },
{ "no_focus", cmd_no_focus }, { "no_focus", cmd_no_focus },
{ "output", cmd_output }, { "output", cmd_output },
{ "popup_during_fullscreen", cmd_popup_during_fullscreen },
{ "raise_floating", cmd_raise_floating }, { "raise_floating", cmd_raise_floating },
{ "seat", cmd_seat }, { "seat", cmd_seat },
{ "set", cmd_set }, { "set", cmd_set },

View file

@ -0,0 +1,25 @@
#include <strings.h>
#include "sway/commands.h"
#include "sway/config.h"
struct cmd_results *cmd_popup_during_fullscreen(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "popup_during_fullscreen",
EXPECTED_EQUAL_TO, 1))) {
return error;
}
if (strcasecmp(argv[0], "smart") == 0) {
config->popup_during_fullscreen = POPUP_SMART;
} else if (strcasecmp(argv[0], "ignore") == 0) {
config->popup_during_fullscreen = POPUP_IGNORE;
} else if (strcasecmp(argv[0], "leave_fullscreen") == 0) {
config->popup_during_fullscreen = POPUP_LEAVE;
} else {
return cmd_results_new(CMD_INVALID, "popup_during_fullscreen",
"Expected "
"'popup_during_fullscreen smart|ignore|leave_fullscreen'");
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}

View file

@ -214,6 +214,7 @@ static void config_defaults(struct sway_config *config) {
if (!(config->font = strdup("monospace 10"))) goto cleanup; if (!(config->font = strdup("monospace 10"))) goto cleanup;
config->font_height = 17; // height of monospace 10 config->font_height = 17; // height of monospace 10
config->urgent_timeout = 500; config->urgent_timeout = 500;
config->popup_during_fullscreen = POPUP_SMART;
// floating view // floating view
config->floating_maximum_width = 0; config->floating_maximum_width = 0;

View file

@ -329,6 +329,14 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) {
workspace->current.fullscreen, &data); workspace->current.fullscreen, &data);
container_for_each_child(workspace->current.fullscreen, container_for_each_child(workspace->current.fullscreen,
send_frame_done_container_iterator, &data); send_frame_done_container_iterator, &data);
for (int i = 0; i < workspace->current.floating->length; ++i) {
struct sway_container *floater =
workspace->current.floating->items[i];
if (container_is_transient_for(floater,
workspace->current.fullscreen)) {
send_frame_done_container_iterator(floater, &data);
}
}
#ifdef HAVE_XWAYLAND #ifdef HAVE_XWAYLAND
send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when); send_frame_done_unmanaged(output, &root->xwayland_unmanaged, when);
#endif #endif

View file

@ -961,6 +961,14 @@ void output_render(struct sway_output *output, struct timespec *when,
render_container(output, damage, fullscreen_con, render_container(output, damage, fullscreen_con,
fullscreen_con->current.focused); fullscreen_con->current.focused);
} }
for (int i = 0; i < workspace->current.floating->length; ++i) {
struct sway_container *floater =
workspace->current.floating->items[i];
if (container_is_transient_for(floater, fullscreen_con)) {
render_floating_container(output, damage, floater);
}
}
#ifdef HAVE_XWAYLAND #ifdef HAVE_XWAYLAND
render_unmanaged(output, damage, &root->xwayland_unmanaged); render_unmanaged(output, damage, &root->xwayland_unmanaged);
#endif #endif

View file

@ -192,6 +192,21 @@ static void for_each_popup(struct sway_view *view,
wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, iterator, user_data); wlr_xdg_surface_for_each_popup(view->wlr_xdg_surface, iterator, user_data);
} }
static bool is_transient_for(struct sway_view *child,
struct sway_view *ancestor) {
if (xdg_shell_view_from_view(child) == NULL) {
return false;
}
struct wlr_xdg_surface *surface = child->wlr_xdg_surface;
while (surface) {
if (surface->toplevel->parent == ancestor->wlr_xdg_surface) {
return true;
}
surface = surface->toplevel->parent;
}
return false;
}
static void _close(struct sway_view *view) { static void _close(struct sway_view *view) {
if (xdg_shell_view_from_view(view) == NULL) { if (xdg_shell_view_from_view(view) == NULL) {
return; return;
@ -233,6 +248,7 @@ static const struct sway_view_impl view_impl = {
.wants_floating = wants_floating, .wants_floating = wants_floating,
.for_each_surface = for_each_surface, .for_each_surface = for_each_surface,
.for_each_popup = for_each_popup, .for_each_popup = for_each_popup,
.is_transient_for = is_transient_for,
.close = _close, .close = _close,
.close_popups = close_popups, .close_popups = close_popups,
.destroy = destroy, .destroy = destroy,
@ -395,6 +411,7 @@ static void handle_map(struct wl_listener *listener, void *data) {
arrange_workspace(view->container->workspace); arrange_workspace(view->container->workspace);
} }
} }
transaction_commit_dirty(); transaction_commit_dirty();
xdg_shell_view->commit.notify = handle_commit; xdg_shell_view->commit.notify = handle_commit;

View file

@ -189,6 +189,21 @@ static void for_each_popup(struct sway_view *view,
user_data); user_data);
} }
static bool is_transient_for(struct sway_view *child,
struct sway_view *ancestor) {
if (xdg_shell_v6_view_from_view(child) == NULL) {
return false;
}
struct wlr_xdg_surface_v6 *surface = child->wlr_xdg_surface_v6;
while (surface) {
if (surface->toplevel->parent == ancestor->wlr_xdg_surface_v6) {
return true;
}
surface = surface->toplevel->parent;
}
return false;
}
static void _close(struct sway_view *view) { static void _close(struct sway_view *view) {
if (xdg_shell_v6_view_from_view(view) == NULL) { if (xdg_shell_v6_view_from_view(view) == NULL) {
return; return;
@ -230,6 +245,7 @@ static const struct sway_view_impl view_impl = {
.wants_floating = wants_floating, .wants_floating = wants_floating,
.for_each_surface = for_each_surface, .for_each_surface = for_each_surface,
.for_each_popup = for_each_popup, .for_each_popup = for_each_popup,
.is_transient_for = is_transient_for,
.close = _close, .close = _close,
.close_popups = close_popups, .close_popups = close_popups,
.destroy = destroy, .destroy = destroy,

View file

@ -15,6 +15,7 @@
#include "sway/tree/arrange.h" #include "sway/tree/arrange.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "sway/tree/view.h" #include "sway/tree/view.h"
#include "sway/tree/workspace.h"
static const char *atom_map[ATOM_LAST] = { static const char *atom_map[ATOM_LAST] = {
"_NET_WM_WINDOW_TYPE_NORMAL", "_NET_WM_WINDOW_TYPE_NORMAL",
@ -253,6 +254,21 @@ static void handle_set_decorations(struct wl_listener *listener, void *data) {
view_update_csd_from_client(view, csd); view_update_csd_from_client(view, csd);
} }
static bool is_transient_for(struct sway_view *child,
struct sway_view *ancestor) {
if (xwayland_view_from_view(child) == NULL) {
return false;
}
struct wlr_xwayland_surface *surface = child->wlr_xwayland_surface;
while (surface) {
if (surface->parent == ancestor->wlr_xwayland_surface) {
return true;
}
surface = surface->parent;
}
return false;
}
static void _close(struct sway_view *view) { static void _close(struct sway_view *view) {
if (xwayland_view_from_view(view) == NULL) { if (xwayland_view_from_view(view) == NULL) {
return; return;
@ -276,6 +292,7 @@ static const struct sway_view_impl view_impl = {
.set_tiled = set_tiled, .set_tiled = set_tiled,
.set_fullscreen = set_fullscreen, .set_fullscreen = set_fullscreen,
.wants_floating = wants_floating, .wants_floating = wants_floating,
.is_transient_for = is_transient_for,
.close = _close, .close = _close,
.destroy = destroy, .destroy = destroy,
}; };

View file

@ -98,6 +98,18 @@ static struct sway_node *node_at_coords(
return NULL; return NULL;
} }
if (ws->fullscreen) { if (ws->fullscreen) {
// Try transient containers
for (int i = 0; i < ws->floating->length; ++i) {
struct sway_container *floater = ws->floating->items[i];
if (container_is_transient_for(floater, ws->fullscreen)) {
struct sway_container *con = tiling_container_at(
&floater->node, lx, ly, surface, sx, sy);
if (con) {
return &con->node;
}
}
}
// Try fullscreen container
struct sway_container *con = struct sway_container *con =
tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy); tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy);
if (con) { if (con) {

View file

@ -655,7 +655,10 @@ void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node,
// Deny setting focus to a view which is hidden by a fullscreen container // Deny setting focus to a view which is hidden by a fullscreen container
if (new_workspace && new_workspace->fullscreen && container && if (new_workspace && new_workspace->fullscreen && container &&
!container_is_fullscreen_or_child(container)) { !container_is_fullscreen_or_child(container)) {
return; // Unless it's a transient container
if (!container_is_transient_for(container, new_workspace->fullscreen)) {
return;
}
} }
struct sway_output *last_output = last_workspace ? struct sway_output *last_output = last_workspace ?

View file

@ -70,6 +70,7 @@ sway_sources = files(
'commands/no_focus.c', 'commands/no_focus.c',
'commands/nop.c', 'commands/nop.c',
'commands/output.c', 'commands/output.c',
'commands/popup_during_fullscreen.c',
'commands/reload.c', 'commands/reload.c',
'commands/rename.c', 'commands/rename.c',
'commands/resize.c', 'commands/resize.c',

View file

@ -555,6 +555,12 @@ You may combine output commands into one, like so:
You can get a list of output names with *swaymsg -t get\_outputs*. You may also You can get a list of output names with *swaymsg -t get\_outputs*. You may also
match any output by using the output name "\*". match any output by using the output name "\*".
*popup\_during\_fullscreen* smart|ignore|leave\_fullscreen
Determines what to do when a fullscreen view opens a dialog.
If _smart_ (the default), the dialog will be displayed. If _ignore_, the
dialog will not be rendered. If _leave\_fullscreen_, the view will exit
fullscreen mode and the dialog will be rendered.
*set* $<name> <value> *set* $<name> <value>
Sets variable $_name_ to _value_. You can use the new variable in the Sets variable $_name_ to _value_. You can use the new variable in the
arguments of future commands. When the variable is used, it can be escaped arguments of future commands. When the variable is used, it can be escaped

View file

@ -1212,3 +1212,10 @@ struct sway_container *container_split(struct sway_container *child,
return cont; return cont;
} }
bool container_is_transient_for(struct sway_container *child,
struct sway_container *ancestor) {
return config->popup_during_fullscreen == POPUP_SMART &&
child->view && ancestor->view &&
view_is_transient_for(child->view, ancestor->view);
}

View file

@ -575,6 +575,16 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface) {
view_set_tiled(view, true); view_set_tiled(view, true);
} }
if (config->popup_during_fullscreen == POPUP_LEAVE &&
view->container->workspace &&
view->container->workspace->fullscreen &&
view->container->workspace->fullscreen->view) {
struct sway_container *fs = view->container->workspace->fullscreen;
if (view_is_transient_for(view, fs->view)) {
container_set_fullscreen(fs, false);
}
}
if (should_focus(view)) { if (should_focus(view)) {
input_manager_set_focus(input_manager, &view->container->node); input_manager_set_focus(input_manager, &view->container->node);
} }
@ -1042,7 +1052,12 @@ bool view_is_visible(struct sway_view *view) {
// Check view isn't hidden by another fullscreen view // Check view isn't hidden by another fullscreen view
if (workspace->fullscreen && if (workspace->fullscreen &&
!container_is_fullscreen_or_child(view->container)) { !container_is_fullscreen_or_child(view->container)) {
return false; // However, if we're transient for the fullscreen view and we allow
// "popups" during fullscreen then it might be visible
if (!container_is_transient_for(view->container,
workspace->fullscreen)) {
return false;
}
} }
return true; return true;
} }
@ -1095,3 +1110,9 @@ void view_save_buffer(struct sway_view *view) {
view->saved_buffer_height = view->surface->current.height; view->saved_buffer_height = view->surface->current.height;
} }
} }
bool view_is_transient_for(struct sway_view *child,
struct sway_view *ancestor) {
return child->impl->is_transient_for &&
child->impl->is_transient_for(child, ancestor);
}