aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sway/commands.h1
-rw-r--r--include/sway/desktop/idle_inhibit_v1.h20
-rw-r--r--sway/commands.c1
-rw-r--r--sway/commands/inhibit_idle.c51
-rw-r--r--sway/desktop/idle_inhibit_v1.c99
-rw-r--r--sway/desktop/transaction.c2
-rw-r--r--sway/meson.build1
-rw-r--r--sway/sway.5.scd12
8 files changed, 171 insertions, 16 deletions
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 7533a14d..9bd0f1cb 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -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;
diff --git a/include/sway/desktop/idle_inhibit_v1.h b/include/sway/desktop/idle_inhibit_v1.h
index e5ed8a3d..4d4e59b0 100644
--- a/include/sway/desktop/idle_inhibit_v1.h
+++ b/include/sway/desktop/idle_inhibit_v1.h
@@ -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
diff --git a/sway/commands.c b/sway/commands.c
index 0d9460a2..abdaa3b8 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -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 },
diff --git a/sway/commands/inhibit_idle.c b/sway/commands/inhibit_idle.c
new file mode 100644
index 00000000..aebc2bf9
--- /dev/null
+++ b/sway/commands/inhibit_idle.c
@@ -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);
+}
diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c
index 87b4ef43..b981e5e5 100644
--- a/sway/desktop/idle_inhibit_v1.c
+++ b/sway/desktop/idle_inhibit_v1.c
@@ -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 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 idle_inhibit_v1_check_active(
+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;
}
}
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index e5f0ee3d..51c6e7fc 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -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;
}
diff --git a/sway/meson.build b/sway/meson.build
index 9f79fb6c..12b86efb 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -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',
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index dbfeefe3..1650cd60 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -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.