criteria: Add additional call sites

Now that there are criteria that can be re-executed on state change and
match the state of keyboard shortcuts inhibitors, add additional
criteria execution call sites right after keyboard shortcuts inhibitor
state changes. This allows to immediately and efficiently visually
reflect inhibitor state changes to the user (or trigger any other
desired action).

Since the surface implemenation might already have been destroyed when
the keyboard shortcuts inhibitor destruction handler is called, we need
to defer criteria execution via the event loop and then go looking
whether a matching surface still exists and derive the view to execute
the criteria on from that.

Signed-off-by: Michael Weiser <michael.weiser@gmx.de>
This commit is contained in:
Michael Weiser 2020-03-18 22:14:37 +01:00
parent 224576afcc
commit 0889c1816e
6 changed files with 89 additions and 7 deletions

View file

@ -343,4 +343,7 @@ void view_save_buffer(struct sway_view *view);
bool view_is_transient_for(struct sway_view *child, struct sway_view *ancestor);
void view_schedule_criteria_execution_from_wlr_surface(
struct wlr_surface *wlr_surface);
#endif

View file

@ -2,6 +2,7 @@
#include "sway/commands.h"
#include "sway/input/seat.h"
#include "sway/input/input-manager.h"
#include "sway/tree/view.h"
#include "util.h"
static struct cmd_results *handle_action(struct seat_config *sc,
@ -12,8 +13,17 @@ static struct cmd_results *handle_action(struct seat_config *sc,
wl_list_for_each(sway_inhibitor,
&seat->keyboard_shortcuts_inhibitors, link) {
wlr_keyboard_shortcuts_inhibitor_v1_deactivate(
sway_inhibitor->inhibitor);
struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor =
sway_inhibitor->inhibitor;
wlr_keyboard_shortcuts_inhibitor_v1_deactivate(inhibitor);
// execute criteria on the affected view after
// inhibitor changed state
struct sway_view *view =
view_from_wlr_surface(inhibitor->surface);
if (view) {
view_execute_criteria(view);
}
}
sway_log(SWAY_DEBUG, "Deactivated all keyboard shortcuts inhibitors");
@ -46,6 +56,11 @@ static struct cmd_results *handle_action(struct seat_config *sc,
sway_log(SWAY_DEBUG, "%sctivated keyboard shortcuts inhibitor",
inhibit ? "A" : "Dea");
struct sway_view *view = view_from_wlr_surface(inhibitor->surface);
if (view) {
view_execute_criteria(view);
}
}
return cmd_results_new(CMD_SUCCESS, NULL);

View file

@ -33,12 +33,20 @@ struct cmd_results *cmd_shortcuts_inhibitor(int argc, char **argv) {
continue;
}
wlr_keyboard_shortcuts_inhibitor_v1_deactivate(
sway_inhibitor->inhibitor);
struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor =
sway_inhibitor->inhibitor;
wlr_keyboard_shortcuts_inhibitor_v1_deactivate(inhibitor);
sway_log(SWAY_DEBUG, "Deactivated keyboard shortcuts "
"inhibitor for seat %s on view",
seat->wlr_seat->name);
// execute criteria on the affected view after
// inhibitor changed state
struct sway_view *view =
view_from_wlr_surface(inhibitor->surface);
if (view) {
view_execute_criteria(view);
}
}
} else {
return cmd_results_new(CMD_INVALID,

View file

@ -304,6 +304,11 @@ static void handle_keyboard_shortcuts_inhibitor_destroy(
sway_log(SWAY_DEBUG, "Removing keyboard shortcuts inhibitor");
// avoid use-after free of view by scheduling deferred execution of
// criteria
view_schedule_criteria_execution_from_wlr_surface(
sway_inhibitor->inhibitor->surface);
// sway_seat::keyboard_shortcuts_inhibitors
wl_list_remove(&sway_inhibitor->link);
wl_list_remove(&sway_inhibitor->destroy.link);
@ -353,6 +358,10 @@ static void handle_keyboard_shortcuts_inhibit_new_inhibitor(
}
if (inhibit == SHORTCUTS_INHIBIT_DISABLE) {
if (view) {
view_execute_criteria(view);
}
/**
* Here we deny to honour the inhibitor by never sending the
* activate signal. We can not, however, destroy the inhibitor
@ -368,6 +377,10 @@ static void handle_keyboard_shortcuts_inhibit_new_inhibitor(
}
wlr_keyboard_shortcuts_inhibitor_v1_activate(inhibitor);
if (view) {
view_execute_criteria(view);
}
}
void handle_virtual_keyboard(struct wl_listener *listener, void *data) {

View file

@ -266,9 +266,10 @@ correct seat.
escape a state where shortcuts are inhibited and the client becomes
uncooperative. It is worth noting that whether disabled or deactivated
inhibitors are removed is entirely up to the client. Depending on the
client it may therefore be possible to (re-)activate them later. Any
visual indication that an inhibitor is present is currently left to the
client as well.
client it may therefore be possible to (re-)activate them later.
Note that visual indication of inhibitor presence and state beyond what
the client may provide can be implemented using criteria with match
_shortcuts_inhibitor_.
*seat* <name> xcursor_theme <theme> [<size>]
Override the system default XCursor theme. The default seat's

View file

@ -1176,3 +1176,45 @@ bool view_is_transient_for(struct sway_view *child,
return child->impl->is_transient_for &&
child->impl->is_transient_for(child, ancestor);
}
struct view_surface_iterator_context {
struct sway_view *view;
struct wlr_surface *wlr_surface;
};
static void view_criteria_execution_surface_iterator(
struct wlr_surface *surface, int sx, int sy, void *data) {
struct view_surface_iterator_context *context = data;
if (surface != context->wlr_surface) {
return;
}
view_execute_criteria(context->view);
}
static void view_criteria_execution_container_iterator(
struct sway_container *container, void *data) {
if (container->view) {
struct view_surface_iterator_context context = {
.view = container->view,
.wlr_surface = data,
};
view_for_each_surface(container->view,
view_criteria_execution_surface_iterator,
&context);
}
}
static void view_execute_criteria_from_wlr_surface(void *data) {
// here we intentionally go looking for a surface matching our argument
// because that surface might have since been freed
root_for_each_container(view_criteria_execution_container_iterator, data);
}
void view_schedule_criteria_execution_from_wlr_surface(
struct wlr_surface *wlr_surface) {
wl_event_loop_add_idle(server.wl_event_loop,
view_execute_criteria_from_wlr_surface, wlr_surface);
}