Implement inhibit_idle command
This implements the following command to set/unset a user idle inhibitor for a view: `inhibit_idle focus|fullscreen|open|none|visible` The modes are as follows: - focus: inhibited when the view is focused by any seat - fullscreen: inhibited when the view is fullscreen (or a descendant of a fullscreen container) and is visible on any output - open: inhibited until the view is closed or the inhibitor is unset or changed - none: unsets any user set idle inhibitors for the view - visible: inhibited when the view is visible on any output This should have no effect on idle inhibitors set by the applications themselves and those should still work as intended. Since this operates on the view in the handler context, it is possible to set it on the currently focused view, on any existing view with criteria, or for any future view with for_window.
This commit is contained in:
parent
8d2c982f3f
commit
d9de5b8758
|
@ -136,6 +136,7 @@ sway_cmd cmd_fullscreen;
|
|||
sway_cmd cmd_gaps;
|
||||
sway_cmd cmd_hide_edge_borders;
|
||||
sway_cmd cmd_include;
|
||||
sway_cmd cmd_inhibit_idle;
|
||||
sway_cmd cmd_input;
|
||||
sway_cmd cmd_seat;
|
||||
sway_cmd cmd_ipc;
|
||||
|
|
|
@ -4,6 +4,14 @@
|
|||
#include <wlr/types/wlr_idle.h>
|
||||
#include "sway/server.h"
|
||||
|
||||
enum sway_idle_inhibit_mode {
|
||||
INHIBIT_IDLE_APPLICATION, // Application set inhibitor (when visible)
|
||||
INHIBIT_IDLE_FOCUS, // User set inhibitor when focused
|
||||
INHIBIT_IDLE_FULLSCREEN, // User set inhibitor when fullscreen + visible
|
||||
INHIBIT_IDLE_OPEN, // User set inhibitor while open
|
||||
INHIBIT_IDLE_VISIBLE // User set inhibitor when visible
|
||||
};
|
||||
|
||||
struct sway_idle_inhibit_manager_v1 {
|
||||
struct wlr_idle_inhibit_manager_v1 *wlr_manager;
|
||||
struct wl_listener new_idle_inhibitor_v1;
|
||||
|
@ -15,14 +23,24 @@ struct sway_idle_inhibit_manager_v1 {
|
|||
struct sway_idle_inhibitor_v1 {
|
||||
struct sway_idle_inhibit_manager_v1 *manager;
|
||||
struct sway_view *view;
|
||||
enum sway_idle_inhibit_mode mode;
|
||||
|
||||
struct wl_list link;
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
void idle_inhibit_v1_check_active(
|
||||
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_user_inhibitor_for_view(
|
||||
struct sway_view *view);
|
||||
|
||||
void sway_idle_inhibit_v1_user_inhibitor_destroy(
|
||||
struct sway_idle_inhibitor_v1 *inhibitor);
|
||||
|
||||
struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
|
||||
struct wl_display *wl_display, struct wlr_idle *idle);
|
||||
#endif
|
||||
|
|
|
@ -112,6 +112,7 @@ static struct cmd_handler command_handlers[] = {
|
|||
{ "exit", cmd_exit },
|
||||
{ "floating", cmd_floating },
|
||||
{ "fullscreen", cmd_fullscreen },
|
||||
{ "inhibit_idle", cmd_inhibit_idle },
|
||||
{ "kill", cmd_kill },
|
||||
{ "layout", cmd_layout },
|
||||
{ "mark", cmd_mark },
|
||||
|
|
51
sway/commands/inhibit_idle.c
Normal file
51
sway/commands/inhibit_idle.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include <string.h>
|
||||
#include "sway/commands.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/desktop/idle_inhibit_v1.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/view.h"
|
||||
|
||||
struct cmd_results *cmd_inhibit_idle(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "inhibit_idle", EXPECTED_EQUAL_TO, 1))) {
|
||||
return error;
|
||||
}
|
||||
|
||||
struct sway_container *con = config->handler_context.container;
|
||||
if (!con || !con->view) {
|
||||
return cmd_results_new(CMD_INVALID,
|
||||
"Only views can have idle inhibitors");
|
||||
}
|
||||
|
||||
bool clear = false;
|
||||
enum sway_idle_inhibit_mode mode;
|
||||
if (strcmp(argv[0], "focus") == 0) {
|
||||
mode = INHIBIT_IDLE_FOCUS;
|
||||
} else if (strcmp(argv[0], "fullscreen") == 0) {
|
||||
mode = INHIBIT_IDLE_FULLSCREEN;
|
||||
} else if (strcmp(argv[0], "open") == 0) {
|
||||
mode = INHIBIT_IDLE_OPEN;
|
||||
} else if (strcmp(argv[0], "none") == 0) {
|
||||
clear = true;
|
||||
} else if (strcmp(argv[0], "visible") == 0) {
|
||||
mode = INHIBIT_IDLE_VISIBLE;
|
||||
} else {
|
||||
return cmd_results_new(CMD_INVALID,
|
||||
"Expected `inhibit_idle focus|fullscreen|open|none|visible`");
|
||||
}
|
||||
|
||||
struct sway_idle_inhibitor_v1 *inhibitor =
|
||||
sway_idle_inhibit_v1_user_inhibitor_for_view(con->view);
|
||||
if (inhibitor) {
|
||||
if (clear) {
|
||||
sway_idle_inhibit_v1_user_inhibitor_destroy(inhibitor);
|
||||
} else {
|
||||
inhibitor->mode = mode;
|
||||
sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
|
||||
}
|
||||
} else if (!clear) {
|
||||
sway_idle_inhibit_v1_user_inhibitor_register(con->view, mode);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
}
|
|
@ -2,18 +2,24 @@
|
|||
#include <wlr/types/wlr_idle.h>
|
||||
#include "log.h"
|
||||
#include "sway/desktop/idle_inhibit_v1.h"
|
||||
#include "sway/input/seat.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "sway/server.h"
|
||||
|
||||
|
||||
static void destroy_inhibitor(struct sway_idle_inhibitor_v1 *inhibitor) {
|
||||
wl_list_remove(&inhibitor->link);
|
||||
wl_list_remove(&inhibitor->destroy.link);
|
||||
sway_idle_inhibit_v1_check_active(inhibitor->manager);
|
||||
free(inhibitor);
|
||||
}
|
||||
|
||||
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");
|
||||
wl_list_remove(&inhibitor->link);
|
||||
wl_list_remove(&inhibitor->destroy.link);
|
||||
idle_inhibit_v1_check_active(inhibitor->manager);
|
||||
free(inhibitor);
|
||||
destroy_inhibitor(inhibitor);
|
||||
}
|
||||
|
||||
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) {
|
||||
|
@ -29,28 +35,93 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) {
|
|||
}
|
||||
|
||||
inhibitor->manager = manager;
|
||||
inhibitor->mode = INHIBIT_IDLE_APPLICATION;
|
||||
inhibitor->view = view_from_wlr_surface(wlr_inhibitor->surface);
|
||||
wl_list_insert(&manager->inhibitors, &inhibitor->link);
|
||||
|
||||
|
||||
inhibitor->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy);
|
||||
|
||||
idle_inhibit_v1_check_active(manager);
|
||||
sway_idle_inhibit_v1_check_active(manager);
|
||||
}
|
||||
|
||||
void idle_inhibit_v1_check_active(
|
||||
void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view,
|
||||
enum sway_idle_inhibit_mode mode) {
|
||||
struct sway_idle_inhibitor_v1 *inhibitor =
|
||||
calloc(1, sizeof(struct sway_idle_inhibitor_v1));
|
||||
if (!inhibitor) {
|
||||
return;
|
||||
}
|
||||
|
||||
inhibitor->manager = server.idle_inhibit_manager_v1;
|
||||
inhibitor->mode = mode;
|
||||
inhibitor->view = view;
|
||||
wl_list_insert(&inhibitor->manager->inhibitors, &inhibitor->link);
|
||||
|
||||
inhibitor->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&view->events.unmap, &inhibitor->destroy);
|
||||
|
||||
sway_idle_inhibit_v1_check_active(inhibitor->manager);
|
||||
}
|
||||
|
||||
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_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) {
|
||||
return inhibitor;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sway_idle_inhibit_v1_user_inhibitor_destroy(
|
||||
struct sway_idle_inhibitor_v1 *inhibitor) {
|
||||
if (!inhibitor) {
|
||||
return;
|
||||
}
|
||||
if (!sway_assert(inhibitor->mode != INHIBIT_IDLE_APPLICATION,
|
||||
"User should not be able to destroy application inhibitor")) {
|
||||
return;
|
||||
}
|
||||
destroy_inhibitor(inhibitor);
|
||||
}
|
||||
|
||||
static bool 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
|
||||
return !inhibitor->view || view_is_visible(inhibitor->view);
|
||||
case INHIBIT_IDLE_FOCUS:;
|
||||
struct sway_seat *seat = NULL;
|
||||
wl_list_for_each(seat, &server.input->seats, link) {
|
||||
struct sway_container *con = seat_get_focused_container(seat);
|
||||
if (con && con->view && con->view == inhibitor->view) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
case INHIBIT_IDLE_FULLSCREEN:
|
||||
return inhibitor->view->container &&
|
||||
container_is_fullscreen_or_child(inhibitor->view->container) &&
|
||||
view_is_visible(inhibitor->view);
|
||||
case INHIBIT_IDLE_OPEN:
|
||||
// Inhibitor is destroyed on unmap so it must be open/mapped
|
||||
return true;
|
||||
case INHIBIT_IDLE_VISIBLE:
|
||||
return view_is_visible(inhibitor->view);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void sway_idle_inhibit_v1_check_active(
|
||||
struct sway_idle_inhibit_manager_v1 *manager) {
|
||||
struct sway_idle_inhibitor_v1 *inhibitor;
|
||||
bool inhibited = false;
|
||||
wl_list_for_each(inhibitor, &manager->inhibitors, link) {
|
||||
if (!inhibitor->view || !inhibitor->view->container) {
|
||||
/* Cannot guess if view is visible so assume it is */
|
||||
inhibited = true;
|
||||
break;
|
||||
}
|
||||
if (view_is_visible(inhibitor->view)) {
|
||||
inhibited = true;
|
||||
if ((inhibited = check_active(inhibitor))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -349,7 +349,7 @@ static void transaction_progress_queue(void) {
|
|||
list_del(server.transactions, 0);
|
||||
|
||||
if (!server.transactions->length) {
|
||||
idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
|
||||
sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,7 @@ sway_sources = files(
|
|||
'commands/fullscreen.c',
|
||||
'commands/gaps.c',
|
||||
'commands/hide_edge_borders.c',
|
||||
'commands/inhibit_idle.c',
|
||||
'commands/kill.c',
|
||||
'commands/mark.c',
|
||||
'commands/opacity.c',
|
||||
|
|
|
@ -146,6 +146,18 @@ set|plus|minus <amount>
|
|||
_right_, _bottom_, and _left_ or per direction with _horizontal_ and
|
||||
_vertical_.
|
||||
|
||||
*inhibit_idle* focus|fullscreen|open|none|visible
|
||||
Set/unset an idle inhibitor for the view. _focus_ will inhibit idle when
|
||||
the view is focused by any seat. _fullscreen_ will inhibit idle when the
|
||||
view is fullscreen (or a descendant of a fullscreen container) and is
|
||||
visible. _open_ will inhibit idle until the view is closed (or the
|
||||
inhibitor is unset/changed). _visible_ will inhibit idle when the view is
|
||||
visible on any output. _none_ will remove any existing idle inhibitor for
|
||||
the view.
|
||||
|
||||
This can also be used with criteria to set an idle inhibitor for any
|
||||
existing view or with _for_window_ to set idle inhibitors for future views.
|
||||
|
||||
*layout* default|splith|splitv|stacking|tabbed
|
||||
Sets the layout mode of the focused container.
|
||||
|
||||
|
|
Loading…
Reference in a new issue