mirror of
https://github.com/swaywm/sway.git
synced 2026-04-25 06:46:24 -04:00
criteria: Add idle inhibitor criteria
Add a criterion that matches idle inhibitors in all their various states and types. Add call sites at creation and destruction, either via the protocol or due to command call. This allows to trigger actions based on idle inhibitor state changes on windows. Example config combined with keyboard shortcuts inhibitor criterion: for_window [shortcuts_inhibitor=inactive] title_format !-%title for_window [shortcuts_inhibitor=active] title_format !+%title for_window [idle_inhibitor=active] title_format ^%title for_window [idle_inhibitor=none shortcuts_inhibitor=absent] title_format %title Signed-off-by: Michael Weiser <michael.weiser@gmx.de>
This commit is contained in:
parent
726d187d3c
commit
37235b7131
8 changed files with 158 additions and 6 deletions
|
|
@ -24,6 +24,18 @@ struct pattern {
|
|||
pcre *regex;
|
||||
};
|
||||
|
||||
enum criteria_idle_inhibitor {
|
||||
// implicit: C_IDLE_INHIBITOR_UNSPEC = 0,
|
||||
C_IDLE_INHIBITOR_NONE = 1,
|
||||
C_IDLE_INHIBITOR_APPLICATION,
|
||||
C_IDLE_INHIBITOR_USER,
|
||||
C_IDLE_INHIBITOR_FOCUS,
|
||||
C_IDLE_INHIBITOR_FULLSCREEN,
|
||||
C_IDLE_INHIBITOR_OPEN,
|
||||
C_IDLE_INHIBITOR_VISIBLE,
|
||||
C_IDLE_INHIBITOR_ACTIVE,
|
||||
};
|
||||
|
||||
struct criteria {
|
||||
enum criteria_type type;
|
||||
char *raw; // entire criteria string (for logging)
|
||||
|
|
@ -47,6 +59,7 @@ struct criteria {
|
|||
char urgent; // 'l' for latest or 'o' for oldest
|
||||
struct pattern *workspace;
|
||||
pid_t pid;
|
||||
enum criteria_idle_inhibitor idle_inhibitor;
|
||||
};
|
||||
|
||||
bool criteria_is_empty(struct criteria *criteria);
|
||||
|
|
|
|||
|
|
@ -29,12 +29,18 @@ struct sway_idle_inhibitor_v1 {
|
|||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
bool sway_idle_inhibit_v1_inhibitor_check_active(
|
||||
struct sway_idle_inhibitor_v1 *inhibitor);
|
||||
|
||||
void sway_idle_inhibit_v1_check_active(
|
||||
struct sway_idle_inhibit_manager_v1 *manager);
|
||||
|
||||
void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view,
|
||||
enum sway_idle_inhibit_mode mode);
|
||||
|
||||
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_inhibitor_for_view(
|
||||
struct sway_view *view);
|
||||
|
||||
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view(
|
||||
struct sway_view *view);
|
||||
|
||||
|
|
|
|||
|
|
@ -341,4 +341,9 @@ 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);
|
||||
|
||||
void view_schedule_criteria_execution_from_view(struct sway_view *view);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -47,5 +47,7 @@ struct cmd_results *cmd_inhibit_idle(int argc, char **argv) {
|
|||
sway_idle_inhibit_v1_user_inhibitor_register(con->view, mode);
|
||||
}
|
||||
|
||||
view_execute_criteria(con->view);
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <strings.h>
|
||||
#include <pcre.h>
|
||||
#include "sway/criteria.h"
|
||||
#include "sway/desktop/idle_inhibit_v1.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/tree/root.h"
|
||||
|
|
@ -32,7 +33,8 @@ bool criteria_is_empty(struct criteria *criteria) {
|
|||
&& !criteria->tiling
|
||||
&& !criteria->urgent
|
||||
&& !criteria->workspace
|
||||
&& !criteria->pid;
|
||||
&& !criteria->pid
|
||||
&& !criteria->idle_inhibitor;
|
||||
}
|
||||
|
||||
// The error pointer is used for parsing functions, and saves having to pass it
|
||||
|
|
@ -377,6 +379,61 @@ static bool criteria_matches_view(struct criteria *criteria,
|
|||
}
|
||||
}
|
||||
|
||||
if (criteria->idle_inhibitor) {
|
||||
struct sway_idle_inhibitor_v1 *sway_inhibitor =
|
||||
sway_idle_inhibit_v1_inhibitor_for_view(view);
|
||||
switch (criteria->idle_inhibitor) {
|
||||
case C_IDLE_INHIBITOR_NONE:
|
||||
if (sway_inhibitor) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case C_IDLE_INHIBITOR_APPLICATION:
|
||||
if (!sway_inhibitor || sway_inhibitor->mode !=
|
||||
INHIBIT_IDLE_APPLICATION) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case C_IDLE_INHIBITOR_USER:
|
||||
if (!sway_inhibitor || sway_inhibitor->mode ==
|
||||
INHIBIT_IDLE_APPLICATION) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case C_IDLE_INHIBITOR_FOCUS:
|
||||
if (!sway_inhibitor || sway_inhibitor->mode !=
|
||||
INHIBIT_IDLE_FOCUS) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case C_IDLE_INHIBITOR_FULLSCREEN:
|
||||
if (!sway_inhibitor || sway_inhibitor->mode !=
|
||||
INHIBIT_IDLE_FULLSCREEN) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case C_IDLE_INHIBITOR_OPEN:
|
||||
if (!sway_inhibitor || sway_inhibitor->mode !=
|
||||
INHIBIT_IDLE_OPEN) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case C_IDLE_INHIBITOR_VISIBLE:
|
||||
if (!sway_inhibitor || sway_inhibitor->mode !=
|
||||
INHIBIT_IDLE_VISIBLE) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case C_IDLE_INHIBITOR_ACTIVE:
|
||||
if (!sway_inhibitor ||
|
||||
!sway_idle_inhibit_v1_inhibitor_check_active(
|
||||
sway_inhibitor)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -466,6 +523,7 @@ enum criteria_token {
|
|||
T_URGENT,
|
||||
T_WORKSPACE,
|
||||
T_PID,
|
||||
T_IDLE_INHIBITOR,
|
||||
|
||||
T_INVALID,
|
||||
};
|
||||
|
|
@ -503,6 +561,8 @@ static enum criteria_token token_from_name(char *name) {
|
|||
return T_FLOATING;
|
||||
} else if (strcmp(name, "pid") == 0) {
|
||||
return T_PID;
|
||||
} else if (strcmp(name, "idle_inhibitor") == 0) {
|
||||
return T_IDLE_INHIBITOR;
|
||||
}
|
||||
return T_INVALID;
|
||||
}
|
||||
|
|
@ -603,6 +663,30 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
|
|||
error = strdup("The value for 'pid' should be numeric");
|
||||
}
|
||||
break;
|
||||
case T_IDLE_INHIBITOR:
|
||||
if (strcmp(value, "none") == 0) {
|
||||
criteria->idle_inhibitor = C_IDLE_INHIBITOR_NONE;
|
||||
} else if (strcmp(value, "application") == 0) {
|
||||
criteria->idle_inhibitor = C_IDLE_INHIBITOR_APPLICATION;
|
||||
} else if (strcmp(value, "user") == 0) {
|
||||
criteria->idle_inhibitor = C_IDLE_INHIBITOR_USER;
|
||||
} else if (strcmp(value, "focus") == 0) {
|
||||
criteria->idle_inhibitor = C_IDLE_INHIBITOR_FOCUS;
|
||||
} else if (strcmp(value, "fullscreen ") == 0) {
|
||||
criteria->idle_inhibitor = C_IDLE_INHIBITOR_FULLSCREEN;
|
||||
} else if (strcmp(value, "open") == 0) {
|
||||
criteria->idle_inhibitor = C_IDLE_INHIBITOR_OPEN;
|
||||
} else if (strcmp(value, "visible") == 0) {
|
||||
criteria->idle_inhibitor = C_IDLE_INHIBITOR_VISIBLE;
|
||||
} else if (strcmp(value, "active") == 0) {
|
||||
criteria->idle_inhibitor = C_IDLE_INHIBITOR_ACTIVE;
|
||||
} else {
|
||||
error = strdup("The value for 'idle_inhibitor' must be "
|
||||
"'none', 'application', 'user', 'focus', "
|
||||
"'fullscreen', 'open', 'visible' or "
|
||||
"'active'");
|
||||
}
|
||||
break;
|
||||
case T_INVALID:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
|
|||
struct sway_idle_inhibitor_v1 *inhibitor =
|
||||
wl_container_of(listener, inhibitor, destroy);
|
||||
sway_log(SWAY_DEBUG, "Sway idle inhibitor destroyed");
|
||||
|
||||
// avoid use-after free of view by scheduling deferred execution of
|
||||
// criteria
|
||||
view_schedule_criteria_execution_from_view(inhibitor->view);
|
||||
destroy_inhibitor(inhibitor);
|
||||
}
|
||||
|
||||
|
|
@ -42,6 +46,7 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) {
|
|||
inhibitor->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy);
|
||||
|
||||
view_execute_criteria(inhibitor->view);
|
||||
sway_idle_inhibit_v1_check_active(manager);
|
||||
}
|
||||
|
||||
|
|
@ -64,19 +69,28 @@ void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view,
|
|||
sway_idle_inhibit_v1_check_active(inhibitor->manager);
|
||||
}
|
||||
|
||||
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view(
|
||||
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_inhibitor_for_view(
|
||||
struct sway_view *view) {
|
||||
struct sway_idle_inhibitor_v1 *inhibitor;
|
||||
wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors,
|
||||
link) {
|
||||
if (inhibitor->view == view &&
|
||||
inhibitor->mode != INHIBIT_IDLE_APPLICATION) {
|
||||
if (inhibitor->view == view) {
|
||||
return inhibitor;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view(
|
||||
struct sway_view *view) {
|
||||
struct sway_idle_inhibitor_v1 *inhibitor =
|
||||
sway_idle_inhibit_v1_inhibitor_for_view(view);
|
||||
if (inhibitor && inhibitor->mode != INHIBIT_IDLE_APPLICATION) {
|
||||
return inhibitor;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sway_idle_inhibit_v1_user_inhibitor_destroy(
|
||||
struct sway_idle_inhibitor_v1 *inhibitor) {
|
||||
if (!inhibitor) {
|
||||
|
|
@ -89,7 +103,7 @@ void sway_idle_inhibit_v1_user_inhibitor_destroy(
|
|||
destroy_inhibitor(inhibitor);
|
||||
}
|
||||
|
||||
static bool check_active(struct sway_idle_inhibitor_v1 *inhibitor) {
|
||||
bool sway_idle_inhibit_v1_inhibitor_check_active(struct sway_idle_inhibitor_v1 *inhibitor) {
|
||||
switch (inhibitor->mode) {
|
||||
case INHIBIT_IDLE_APPLICATION:
|
||||
// If there is no view associated with the inhibitor, assume visible
|
||||
|
|
@ -122,7 +136,7 @@ void sway_idle_inhibit_v1_check_active(
|
|||
struct sway_idle_inhibitor_v1 *inhibitor;
|
||||
bool inhibited = false;
|
||||
wl_list_for_each(inhibitor, &manager->inhibitors, link) {
|
||||
if ((inhibited = check_active(inhibitor))) {
|
||||
if ((inhibited = sway_idle_inhibit_v1_inhibitor_check_active(inhibitor))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -870,6 +870,14 @@ The following attributes may be matched with:
|
|||
*id*
|
||||
Compare value against the X11 window ID. Must be numeric.
|
||||
|
||||
*idle_inhibitor*
|
||||
Matches the state of idle inhibitors on windows. Values can be "none",
|
||||
"application", "user", "focus", "fullscreen", "open", "none", "visible"
|
||||
and "active" and will match windows where no, an application or a user
|
||||
inhibitor is present with the "focus" to "visible" keywords describing
|
||||
the type of user inhibtor to match more closely. "active" matches any
|
||||
inhibitor that is currently preventing idle regardless of type.
|
||||
|
||||
*instance*
|
||||
Compare value against the window instance. Can be a regular expression. If
|
||||
value is \_\_focused\_\_, then the window instance must be the same as that
|
||||
|
|
|
|||
|
|
@ -1175,3 +1175,23 @@ bool view_is_transient_for(struct sway_view *child,
|
|||
return child->impl->is_transient_for &&
|
||||
child->impl->is_transient_for(child, ancestor);
|
||||
}
|
||||
|
||||
static void view_criteria_execution_view_iterator(
|
||||
struct sway_container *container, void *data) {
|
||||
struct sway_view *view = data;
|
||||
|
||||
if (container->view == view) {
|
||||
view_execute_criteria(container->view);
|
||||
}
|
||||
}
|
||||
|
||||
static void view_execute_criteria_from_view(void *data) {
|
||||
// here we intentionally go looking for a view matching our argument
|
||||
// because that view might have been freed since
|
||||
root_for_each_container(view_criteria_execution_view_iterator, data);
|
||||
}
|
||||
|
||||
void view_schedule_criteria_execution_from_view(struct sway_view *view) {
|
||||
wl_event_loop_add_idle(server.wl_event_loop,
|
||||
view_execute_criteria_from_view, view);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue