diff --git a/include/ipc.h b/include/ipc.h index ff0117502..fcf1133bd 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -36,6 +36,8 @@ enum ipc_command_type { // sway-specific event types IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20), IPC_EVENT_INPUT = ((1<<31) | 21), + IPC_EVENT_IDLE_INHIBITOR = ((1<<31) | 22), + IPC_EVENT_KEYBOARD_SHORTCUTS_INHIBITOR = ((1<<31) | 23), }; #endif diff --git a/include/sway/desktop/idle_inhibit_v1.h b/include/sway/desktop/idle_inhibit_v1.h index 84cc666d0..047762450 100644 --- a/include/sway/desktop/idle_inhibit_v1.h +++ b/include/sway/desktop/idle_inhibit_v1.h @@ -39,6 +39,10 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view( struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_view( struct sway_view *view); +void sway_idle_inhibit_v1_user_inhibitor_update_mode( + struct sway_idle_inhibitor_v1 *inhibitor, + enum sway_idle_inhibit_mode mode); + void sway_idle_inhibit_v1_user_inhibitor_destroy( struct sway_idle_inhibitor_v1 *inhibitor); diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 428f96796..3e66cbc0e 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -369,4 +369,12 @@ keyboard_shortcuts_inhibitor_get_for_surface(const struct sway_seat *seat, struct sway_keyboard_shortcuts_inhibitor * keyboard_shortcuts_inhibitor_get_for_focused_surface(const struct sway_seat *seat); +/** + * Returns the keyboard shortcuts inhibitor that applies to the given surface + * or NULL if none exists. It looks at inhibitors attached to all seats. + */ +struct sway_keyboard_shortcuts_inhibitor * +keyboard_shortcuts_inhibitor_get_for_surface_on_any_seat( + const struct wlr_surface *surface); + #endif diff --git a/include/sway/ipc-json.h b/include/sway/ipc-json.h index bc9f49856..2f36c795e 100644 --- a/include/sway/ipc-json.h +++ b/include/sway/ipc-json.h @@ -3,7 +3,10 @@ #include #include "sway/output.h" #include "sway/tree/container.h" +#include "sway/desktop/idle_inhibit_v1.h" #include "sway/input/input-manager.h" +#include "sway/input/seat.h" +#include "sway/tree/container.h" json_object *ipc_json_get_version(void); @@ -16,5 +19,9 @@ json_object *ipc_json_describe_node_recursive(struct sway_node *node); json_object *ipc_json_describe_input(struct sway_input_device *device); json_object *ipc_json_describe_seat(struct sway_seat *seat); json_object *ipc_json_describe_bar_config(struct bar_config *bar); +json_object *ipc_json_describe_idle_inhibitor( + struct sway_idle_inhibitor_v1 *sway_inhibitor); +json_object *ipc_json_describe_keyboard_shortcuts_inhibitor( + struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor); #endif diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h index d4c009427..4590e0065 100644 --- a/include/sway/ipc-server.h +++ b/include/sway/ipc-server.h @@ -2,7 +2,9 @@ #define _SWAY_IPC_SERVER_H #include #include "sway/config.h" +#include "sway/desktop/idle_inhibit_v1.h" #include "sway/input/input-manager.h" +#include "sway/input/seat.h" #include "sway/tree/container.h" #include "ipc.h" @@ -22,5 +24,9 @@ void ipc_event_shutdown(const char *reason); void ipc_event_binding(struct sway_binding *binding); void ipc_event_input(const char *change, struct sway_input_device *device); void ipc_event_output(void); +void ipc_event_idle_inhibitor(struct sway_idle_inhibitor_v1 *inhibitor, const char *change); +void ipc_event_keyboard_shortcuts_inhibitor( + struct sway_keyboard_shortcuts_inhibitor *inhibitor, + const char *change); #endif diff --git a/sway/commands/inhibit_idle.c b/sway/commands/inhibit_idle.c index 6125736ac..23cdb7f8d 100644 --- a/sway/commands/inhibit_idle.c +++ b/sway/commands/inhibit_idle.c @@ -40,7 +40,7 @@ struct cmd_results *cmd_inhibit_idle(int argc, char **argv) { if (clear) { sway_idle_inhibit_v1_user_inhibitor_destroy(inhibitor); } else { - inhibitor->mode = mode; + sway_idle_inhibit_v1_user_inhibitor_update_mode(inhibitor, mode); sway_idle_inhibit_v1_check_active(); } } else if (!clear) { diff --git a/sway/commands/seat/shortcuts_inhibitor.c b/sway/commands/seat/shortcuts_inhibitor.c index 7c7f99cf0..ce895cde8 100644 --- a/sway/commands/seat/shortcuts_inhibitor.c +++ b/sway/commands/seat/shortcuts_inhibitor.c @@ -2,6 +2,7 @@ #include "sway/commands.h" #include "sway/input/seat.h" #include "sway/input/input-manager.h" +#include "sway/ipc-server.h" #include "util.h" static struct cmd_results *handle_action(struct seat_config *sc, @@ -12,6 +13,8 @@ static struct cmd_results *handle_action(struct seat_config *sc, wl_list_for_each(sway_inhibitor, &seat->keyboard_shortcuts_inhibitors, link) { + ipc_event_keyboard_shortcuts_inhibitor( + sway_inhibitor, "deactivate"); wlr_keyboard_shortcuts_inhibitor_v1_deactivate( sway_inhibitor->inhibitor); } @@ -39,8 +42,12 @@ static struct cmd_results *handle_action(struct seat_config *sc, } if (inhibit) { + ipc_event_keyboard_shortcuts_inhibitor( + sway_inhibitor, "activate"); wlr_keyboard_shortcuts_inhibitor_v1_activate(inhibitor); } else { + ipc_event_keyboard_shortcuts_inhibitor( + sway_inhibitor, "deactivate"); wlr_keyboard_shortcuts_inhibitor_v1_deactivate(inhibitor); } diff --git a/sway/commands/shortcuts_inhibitor.c b/sway/commands/shortcuts_inhibitor.c index ffa1a5c99..45eb5d6e6 100644 --- a/sway/commands/shortcuts_inhibitor.c +++ b/sway/commands/shortcuts_inhibitor.c @@ -3,6 +3,7 @@ #include "sway/commands.h" #include "sway/config.h" #include "sway/input/seat.h" +#include "sway/ipc-server.h" #include "sway/tree/container.h" #include "sway/tree/view.h" @@ -33,12 +34,13 @@ struct cmd_results *cmd_shortcuts_inhibitor(int argc, char **argv) { continue; } + ipc_event_keyboard_shortcuts_inhibitor( + sway_inhibitor, "deactivate"); wlr_keyboard_shortcuts_inhibitor_v1_deactivate( sway_inhibitor->inhibitor); sway_log(SWAY_DEBUG, "Deactivated keyboard shortcuts " "inhibitor for seat %s on view", seat->wlr_seat->name); - } } else { return cmd_results_new(CMD_INVALID, diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index f3af7aa1b..2f2306fa9 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -3,12 +3,14 @@ #include "log.h" #include "sway/desktop/idle_inhibit_v1.h" #include "sway/input/seat.h" +#include "sway/ipc-server.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) { + ipc_event_idle_inhibitor(inhibitor, "destroy"); wl_list_remove(&inhibitor->link); wl_list_remove(&inhibitor->destroy.link); sway_idle_inhibit_v1_check_active(); @@ -36,6 +38,9 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) { inhibitor->mode = INHIBIT_IDLE_APPLICATION; inhibitor->wlr_inhibitor = wlr_inhibitor; + + ipc_event_idle_inhibitor(inhibitor, "create"); + wl_list_insert(&manager->inhibitors, &inhibitor->link); inhibitor->destroy.notify = handle_destroy; @@ -56,6 +61,9 @@ void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view, inhibitor->mode = mode; inhibitor->view = view; + + ipc_event_idle_inhibitor(inhibitor, "create"); + wl_list_insert(&manager->inhibitors, &inhibitor->link); inhibitor->destroy.notify = handle_destroy; @@ -90,6 +98,13 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_vi return NULL; } +void sway_idle_inhibit_v1_user_inhibitor_update_mode( + struct sway_idle_inhibitor_v1 *inhibitor, + enum sway_idle_inhibit_mode mode) { + inhibitor->mode = mode; + ipc_event_idle_inhibitor(inhibitor, "mode"); +} + void sway_idle_inhibit_v1_user_inhibitor_destroy( struct sway_idle_inhibitor_v1 *inhibitor) { if (!inhibitor) { diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index 248ca34ee..592694db9 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -298,6 +298,8 @@ static void handle_keyboard_shortcuts_inhibitor_destroy( sway_log(SWAY_DEBUG, "Removing keyboard shortcuts inhibitor"); + ipc_event_keyboard_shortcuts_inhibitor(sway_inhibitor, "destroy"); + // sway_seat::keyboard_shortcuts_inhibitors wl_list_remove(&sway_inhibitor->link); wl_list_remove(&sway_inhibitor->destroy.link); @@ -321,6 +323,8 @@ static void handle_keyboard_shortcuts_inhibit_new_inhibitor( } sway_inhibitor->inhibitor = inhibitor; + ipc_event_keyboard_shortcuts_inhibitor(sway_inhibitor, "create"); + sway_inhibitor->destroy.notify = handle_keyboard_shortcuts_inhibitor_destroy; wl_signal_add(&inhibitor->events.destroy, &sway_inhibitor->destroy); @@ -361,6 +365,7 @@ static void handle_keyboard_shortcuts_inhibit_new_inhibitor( return; } + ipc_event_keyboard_shortcuts_inhibitor(sway_inhibitor, "activate"); wlr_keyboard_shortcuts_inhibitor_v1_activate(inhibitor); } diff --git a/sway/input/seat.c b/sway/input/seat.c index 0c5672bca..077119d05 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -1723,3 +1723,18 @@ keyboard_shortcuts_inhibitor_get_for_focused_surface( return keyboard_shortcuts_inhibitor_get_for_surface(seat, seat->wlr_seat->keyboard_state.focused_surface); } + +struct sway_keyboard_shortcuts_inhibitor * +keyboard_shortcuts_inhibitor_get_for_surface_on_any_seat( + const struct wlr_surface *surface) { + struct sway_seat *seat = NULL; + wl_list_for_each(seat, &server.input->seats, link) { + struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor = + keyboard_shortcuts_inhibitor_get_for_surface(seat, surface); + if (sway_inhibitor) { + return sway_inhibitor; + } + } + + return NULL; +} diff --git a/sway/ipc-json.c b/sway/ipc-json.c index 81ca34831..ca3df2b0e 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -220,6 +220,19 @@ static const char *ipc_json_content_type_description(enum wp_content_type_v1_typ return NULL; } +static const char *ipc_json_keyboard_shortcuts_inhibitor_description( + struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor) { + if (!sway_inhibitor) { + return "none"; + } + + if (!sway_inhibitor->inhibitor->active) { + return "inactive"; + } + + return "active"; +} + json_object *ipc_json_get_version(void) { int major = 0, minor = 0, patch = 0; json_object *version = json_object_new_object(); @@ -633,6 +646,12 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object json_object_new_string(ipc_json_content_type_description(content_type))); } + json_object_object_add(object, "keyboard_shortcuts_inhibitor", + json_object_new_string( + ipc_json_keyboard_shortcuts_inhibitor_description( + keyboard_shortcuts_inhibitor_get_for_surface_on_any_seat( + c->view->surface)))); + #if HAVE_XWAYLAND if (c->view->type == SWAY_VIEW_XWAYLAND) { json_object_object_add(object, "window", @@ -1426,3 +1445,51 @@ json_object *ipc_json_get_binding_mode(void) { json_object_new_string(config->current_mode->name)); return current_mode; } + +json_object *ipc_json_describe_idle_inhibitor( + struct sway_idle_inhibitor_v1 *sway_inhibitor) { + json_object *object = json_object_new_object(); + + json_object_object_add(object, "active", + json_object_new_boolean( + sway_idle_inhibit_v1_is_active(sway_inhibitor))); + + const char *type = NULL; + struct sway_view *view = NULL; + if (sway_inhibitor->mode == INHIBIT_IDLE_APPLICATION) { + type = "application"; + view = view_from_wlr_surface(sway_inhibitor->wlr_inhibitor->surface); + } else { + type = "user"; + view = sway_inhibitor->view; + json_object_object_add(object, "mode", + json_object_new_string( + ipc_json_user_idle_inhibitor_description( + sway_inhibitor->mode))); + } + + if (type) { + json_object_object_add(object, "type", json_object_new_string(type)); + } + + if (view && view->container) { + json_object_object_add(object, "container", + ipc_json_describe_node(&view->container->node)); + } + + return object; +} + +json_object *ipc_json_describe_keyboard_shortcuts_inhibitor( + struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor) { + json_object *object = json_object_new_object(); + + struct sway_view *view = view_from_wlr_surface( + sway_inhibitor->inhibitor->surface); + if (view && view->container) { + json_object_object_add(object, "container", + ipc_json_describe_node(&view->container->node)); + } + + return object; +} diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 7f353c0ec..643ad1520 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -521,6 +521,39 @@ void ipc_event_output(void) { json_object_put(json); } +void ipc_event_idle_inhibitor(struct sway_idle_inhibitor_v1 *inhibitor, const char *change) { + if (!ipc_has_event_listeners(IPC_EVENT_IDLE_INHIBITOR)) { + return; + } + sway_log(SWAY_DEBUG, "Sending idle inhibitor::%s event", change); + json_object *obj = json_object_new_object(); + json_object_object_add(obj, "change", json_object_new_string(change)); + json_object_object_add(obj, "idle_inhibitor", + ipc_json_describe_idle_inhibitor(inhibitor)); + + const char *json_string = json_object_to_json_string(obj); + ipc_send_event(json_string, IPC_EVENT_IDLE_INHIBITOR); + json_object_put(obj); +} + +void ipc_event_keyboard_shortcuts_inhibitor( + struct sway_keyboard_shortcuts_inhibitor *inhibitor, + const char *change) { + if (!ipc_has_event_listeners(IPC_EVENT_KEYBOARD_SHORTCUTS_INHIBITOR)) { + return; + } + sway_log(SWAY_DEBUG, "Sending keyboard shortcuts " + "inhibitor::%s event", change); + json_object *obj = json_object_new_object(); + json_object_object_add(obj, "change", json_object_new_string(change)); + json_object_object_add(obj, "keyboard_shortcuts_inhibitor", + ipc_json_describe_keyboard_shortcuts_inhibitor(inhibitor)); + + const char *json_string = json_object_to_json_string(obj); + ipc_send_event(json_string, IPC_EVENT_KEYBOARD_SHORTCUTS_INHIBITOR); + json_object_put(obj); +} + int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { struct ipc_client *client = data; @@ -757,6 +790,11 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt is_tick = true; } else if (strcmp(event_type, "input") == 0) { client->subscribed_events |= event_mask(IPC_EVENT_INPUT); + } else if (strcmp(event_type, "idle_inhibitor") == 0) { + client->subscribed_events |= event_mask(IPC_EVENT_IDLE_INHIBITOR); + } else if (strcmp(event_type, "keyboard_shortcuts_inhibitor") == 0) { + client->subscribed_events |= event_mask( + IPC_EVENT_KEYBOARD_SHORTCUTS_INHIBITOR); } else { const char msg[] = "{\"success\": false}"; ipc_send_reply(client, payload_type, msg, strlen(msg));