From e8b179e313632c150ff7775f4f740296465cb58a Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Fri, 13 Jul 2018 16:58:45 +0100 Subject: [PATCH 01/19] ipc: add shutdown event --- include/ipc.h | 5 +++-- include/sway/ipc-server.h | 1 + sway/ipc-server.c | 16 ++++++++++++++++ sway/main.c | 1 + 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/ipc.h b/include/ipc.h index 0010718b..ffc57d1b 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -27,8 +27,9 @@ enum ipc_command_type { IPC_EVENT_WINDOW = ((1<<31) | 3), IPC_EVENT_BARCONFIG_UPDATE = ((1<<31) | 4), IPC_EVENT_BINDING = ((1<<31) | 5), - IPC_EVENT_MODIFIER = ((1<<31) | 6), - IPC_EVENT_INPUT = ((1<<31) | 7), + IPC_EVENT_SHUTDOWN = ((1<<31) | 6), + IPC_EVENT_MODIFIER = ((1<<31) | 16), + IPC_EVENT_INPUT = ((1<<31) | 17), }; #endif diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h index 6469f097..a11735cf 100644 --- a/include/sway/ipc-server.h +++ b/include/sway/ipc-server.h @@ -16,5 +16,6 @@ void ipc_event_workspace(struct sway_container *old, void ipc_event_window(struct sway_container *window, const char *change); void ipc_event_barconfig_update(struct bar_config *bar); void ipc_event_mode(const char *mode, bool pango); +void ipc_event_shutdown(const char *reason); #endif diff --git a/sway/ipc-server.c b/sway/ipc-server.c index be703915..72031e24 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -353,6 +353,20 @@ void ipc_event_mode(const char *mode, bool pango) { json_object_put(obj); } +void ipc_event_shutdown(const char *reason) { + if (!ipc_has_event_listeners(IPC_EVENT_SHUTDOWN)) { + return; + } + wlr_log(WLR_DEBUG, "Sending shutdown::%s event", reason); + + json_object *json = json_object_new_object(); + json_object_object_add(json, "change", json_object_new_string(reason)); + + const char *json_string = json_object_to_json_string(json); + ipc_send_event(json_string, IPC_EVENT_SHUTDOWN); + json_object_put(json); +} + int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { struct ipc_client *client = data; @@ -549,6 +563,8 @@ void ipc_client_handle_command(struct ipc_client *client) { client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); } else if (strcmp(event_type, "mode") == 0) { client->subscribed_events |= event_mask(IPC_EVENT_MODE); + } else if (strcmp(event_type, "shutdown") == 0) { + client->subscribed_events |= event_mask(IPC_EVENT_SHUTDOWN); } else if (strcmp(event_type, "window") == 0) { client->subscribed_events |= event_mask(IPC_EVENT_WINDOW); } else if (strcmp(event_type, "modifier") == 0) { diff --git a/sway/main.c b/sway/main.c index a20f1dac..477ffa5a 100644 --- a/sway/main.c +++ b/sway/main.c @@ -36,6 +36,7 @@ struct sway_server server; void sway_terminate(int exit_code) { terminate_request = true; exit_value = exit_code; + ipc_event_shutdown("exit"); wl_display_terminate(server.wl_display); } From 87ccf189646cfc79db791ef9b81b5b3f0c2040b7 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Fri, 13 Jul 2018 17:13:25 +0100 Subject: [PATCH 02/19] ipc: add workspace::init event --- sway/tree/container.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sway/tree/container.c b/sway/tree/container.c index 4e85021d..f082e8b1 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -64,6 +64,8 @@ void container_create_notify(struct sway_container *container) { if (container->type == C_VIEW || container->type == C_CONTAINER) { ipc_event_window(container, "new"); + } else if (container->type == C_WORKSPACE) { + ipc_event_workspace(NULL, container, "init"); } } From f0310933c89ba062a13df0b319d65f0574445ab8 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Fri, 13 Jul 2018 17:15:52 +0100 Subject: [PATCH 03/19] ipc: add window::close event --- sway/tree/container.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index f082e8b1..47855052 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -321,7 +321,11 @@ static struct sway_container *container_destroy_noreaping( } wl_signal_emit(&con->events.destroy, con); - ipc_event_window(con, "close"); + + // emit IPC event + if (con->type == C_VIEW) { + ipc_event_window(con, "close"); + } // The below functions move their children to somewhere else. if (con->type == C_OUTPUT) { From dd1d6255f0e558f2d62e03f701440a57f65254b2 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Fri, 13 Jul 2018 17:16:32 +0100 Subject: [PATCH 04/19] ipc: add window::focus event --- sway/input/seat.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sway/input/seat.c b/sway/input/seat.c index a4a449e4..c85e9242 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -766,6 +766,10 @@ void seat_set_focus_warp(struct sway_seat *seat, } } + if (container->type == C_VIEW) { + ipc_event_window(container, "focus"); + } + seat->has_focus = (container != NULL); update_debug_tree(); From 4f8f363dda2495810e419be6e79c3869bb7f17d8 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Fri, 13 Jul 2018 17:19:16 +0100 Subject: [PATCH 05/19] ipc: add window::title event --- sway/tree/view.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sway/tree/view.c b/sway/tree/view.c index 8f54cc11..7300f207 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -864,6 +864,8 @@ void view_update_title(struct sway_view *view, bool force) { // Update title after the global font height is updated container_update_title_textures(view->swayc); + + ipc_event_window(view->swayc, "title"); } static bool find_by_mark_iterator(struct sway_container *con, From 686c084cec0b1143c877e8c0088732fad5229ce4 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Fri, 13 Jul 2018 21:55:04 +0100 Subject: [PATCH 06/19] ipc: add workspace::empty event --- sway/tree/container.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sway/tree/container.c b/sway/tree/container.c index 47855052..3b3c5e2e 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -325,6 +325,8 @@ static struct sway_container *container_destroy_noreaping( // emit IPC event if (con->type == C_VIEW) { ipc_event_window(con, "close"); + } else if (con->type == C_WORKSPACE) { + ipc_event_workspace(NULL, con, "empty"); } // The below functions move their children to somewhere else. From dd6debf367420d0771cc0326ecb2511c1ce05ac1 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Fri, 13 Jul 2018 23:22:34 +0100 Subject: [PATCH 07/19] ipc: add barconfig_update event on config reload --- sway/commands/reload.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/sway/commands/reload.c b/sway/commands/reload.c index cea6a94b..36c6acce 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c @@ -1,17 +1,45 @@ +#define _XOPEN_SOURCE 500 +#include #include "sway/commands.h" #include "sway/config.h" +#include "sway/ipc-server.h" #include "sway/tree/arrange.h" +#include "list.h" struct cmd_results *cmd_reload(int argc, char **argv) { struct cmd_results *error = NULL; if ((error = checkarg(argc, "reload", EXPECTED_EQUAL_TO, 0))) { return error; } + + // store bar ids to check against new bars for barconfig_update events + list_t *bar_ids = create_list(); + for (int i = 0; i < config->bars->length; ++i) { + struct bar_config *bar = config->bars->items[i]; + list_add(bar_ids, strdup(bar->id)); + } + if (!load_main_config(config->current_config_path, true)) { return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); } load_swaybars(); + + for (int i = 0; i < config->bars->length; ++i) { + struct bar_config *bar = config->bars->items[i]; + for (int j = 0; j < bar_ids->length; ++j) { + if (strcmp(bar->id, bar_ids->items[j]) == 0) { + ipc_event_barconfig_update(bar); + break; + } + } + } + + for (int i = 0; i < bar_ids->length; ++i) { + free(bar_ids->items[i]); + } + list_free(bar_ids); + arrange_windows(&root_container); return cmd_results_new(CMD_SUCCESS, NULL, NULL); } From 317217f2c87aba4463806e211c22296ac9230b6c Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Sat, 14 Jul 2018 11:10:36 +0100 Subject: [PATCH 08/19] ipc: add window::mark event --- include/sway/tree/view.h | 2 ++ sway/commands/mark.c | 2 +- sway/ipc-json.c | 9 +++++++++ sway/tree/view.c | 13 +++++++++---- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index 0152ed55..800df073 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h @@ -311,6 +311,8 @@ void view_clear_marks(struct sway_view *view); bool view_has_mark(struct sway_view *view, char *mark); +void view_add_mark(struct sway_view *view, char *mark); + void view_update_marks_textures(struct sway_view *view); /** diff --git a/sway/commands/mark.c b/sway/commands/mark.c index 5a897e69..9ea8c301 100644 --- a/sway/commands/mark.c +++ b/sway/commands/mark.c @@ -58,7 +58,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) { view_find_and_unmark(mark); if (!toggle || !had_mark) { - list_add(view->marks, strdup(mark)); + view_add_mark(view, mark); } free(mark); diff --git a/sway/ipc-json.c b/sway/ipc-json.c index c49ea47e..4c2bcc98 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c @@ -201,6 +201,15 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object bool urgent = c->type == C_VIEW ? view_is_urgent(c->sway_view) : container_has_urgent_child(c); json_object_object_add(object, "urgent", json_object_new_boolean(urgent)); + + if (c->type == C_VIEW) { + json_object *marks = json_object_new_array(); + list_t *view_marks = c->sway_view->marks; + for (int i = 0; i < view_marks->length; ++i) { + json_object_array_add(marks, json_object_new_string(view_marks->items[i])); + } + json_object_object_add(object, "marks", marks); + } } static void focus_inactive_children_iterator(struct sway_container *c, void *data) { diff --git a/sway/tree/view.c b/sway/tree/view.c index 7300f207..48b39e80 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -888,6 +888,7 @@ bool view_find_and_unmark(char *mark) { free(view_mark); list_del(view->marks, i); view_update_marks_textures(view); + ipc_event_window(container, "mark"); return true; } } @@ -895,11 +896,10 @@ bool view_find_and_unmark(char *mark) { } void view_clear_marks(struct sway_view *view) { - for (int i = 0; i < view->marks->length; ++i) { - free(view->marks->items[i]); + while (view->marks->length) { + list_del(view->marks, 0); + ipc_event_window(view->swayc, "mark"); } - list_free(view->marks); - view->marks = create_list(); } bool view_has_mark(struct sway_view *view, char *mark) { @@ -912,6 +912,11 @@ bool view_has_mark(struct sway_view *view, char *mark) { return false; } +void view_add_mark(struct sway_view *view, char *mark) { + list_add(view->marks, strdup(mark)); + ipc_event_window(view->swayc, "mark"); +} + static void update_marks_texture(struct sway_view *view, struct wlr_texture **texture, struct border_colors *class) { struct sway_container *output = container_parent(view->swayc, C_OUTPUT); From 07101a570750f47fa5d4fb81739a40168b6c8ea6 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Mon, 16 Jul 2018 14:01:35 +0100 Subject: [PATCH 09/19] ipc: only emit window::create event for views --- sway/tree/container.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index 3b3c5e2e..92d9ce06 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -62,7 +62,7 @@ void container_create_notify(struct sway_container *container) { // TODO send ipc event type based on the container type wl_signal_emit(&root_container.sway_root->events.new_container, container); - if (container->type == C_VIEW || container->type == C_CONTAINER) { + if (container->type == C_VIEW) { ipc_event_window(container, "new"); } else if (container->type == C_WORKSPACE) { ipc_event_workspace(NULL, container, "init"); From 4bf253855f1946ffca5a41085b8ae3eb79ca62c4 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Wed, 18 Jul 2018 10:47:44 +0100 Subject: [PATCH 10/19] ipc: fix workspace::move calls argument order --- sway/tree/container.c | 2 +- sway/tree/layout.c | 2 +- sway/tree/output.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sway/tree/container.c b/sway/tree/container.c index 92d9ce06..b6ff4d30 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c @@ -283,7 +283,7 @@ static struct sway_container *container_output_destroy( container_remove_child(workspace); if (!workspace_is_empty(workspace)) { container_add_child(new_output, workspace); - ipc_event_workspace(workspace, NULL, "move"); + ipc_event_workspace(NULL, workspace, "move"); } else { container_destroy(workspace); } diff --git a/sway/tree/layout.c b/sway/tree/layout.c index a0764a54..b833e8e1 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -217,7 +217,7 @@ void container_move_to(struct sway_container *container, container_sort_workspaces(new_parent); seat_set_focus(seat, new_parent); workspace_output_raise_priority(container, old_parent, new_parent); - ipc_event_workspace(container, NULL, "move"); + ipc_event_workspace(NULL, container, "move"); } container_notify_subtree_changed(old_parent); container_notify_subtree_changed(new_parent); diff --git a/sway/tree/output.c b/sway/tree/output.c index da535c18..31e3bf9b 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -22,7 +22,7 @@ static void restore_workspaces(struct sway_container *output) { if (highest == output) { container_remove_child(ws); container_add_child(output, ws); - ipc_event_workspace(ws, NULL, "move"); + ipc_event_workspace(NULL, ws, "move"); j--; } } From e0e638281e193103b44105cb1689b2ec25cae7e8 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Wed, 18 Jul 2018 10:50:48 +0100 Subject: [PATCH 11/19] ipc: add window::move events --- sway/tree/layout.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sway/tree/layout.c b/sway/tree/layout.c index b833e8e1..a0f9b6de 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -218,6 +218,8 @@ void container_move_to(struct sway_container *container, seat_set_focus(seat, new_parent); workspace_output_raise_priority(container, old_parent, new_parent); ipc_event_workspace(NULL, container, "move"); + } else if (container->type == C_VIEW) { + ipc_event_window(container, "move"); } container_notify_subtree_changed(old_parent); container_notify_subtree_changed(new_parent); @@ -578,6 +580,10 @@ void container_move(struct sway_container *container, container_notify_subtree_changed(old_parent); container_notify_subtree_changed(container->parent); + if (container->type == C_VIEW) { + ipc_event_window(container, "move"); + } + if (old_parent) { seat_set_focus(config->handler_context.seat, old_parent); seat_set_focus(config->handler_context.seat, container); From 6865b8aae9736e73a2153bce89d979737f8162cc Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Wed, 18 Jul 2018 11:37:50 +0100 Subject: [PATCH 12/19] ipc: add binding event --- include/sway/config.h | 2 -- include/sway/ipc-server.h | 1 + sway/commands/bind.c | 52 ++++++++++++++++++++++++++- sway/ipc-server.c | 76 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 3 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 0f74b439..909b6827 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -488,8 +488,6 @@ int sway_binding_cmp_keys(const void *a, const void *b); void free_sway_binding(struct sway_binding *sb); -struct sway_binding *sway_binding_dup(struct sway_binding *sb); - void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); void load_swaybars(); diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h index a11735cf..4b6d0e25 100644 --- a/include/sway/ipc-server.h +++ b/include/sway/ipc-server.h @@ -17,5 +17,6 @@ void ipc_event_window(struct sway_container *window, const char *change); void ipc_event_barconfig_update(struct bar_config *bar); void ipc_event_mode(const char *mode, bool pango); void ipc_event_shutdown(const char *reason); +void ipc_event_binding(struct sway_binding *binding); #endif diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 133fd089..8270b958 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -1,3 +1,4 @@ +#define _XOPEN_SOURCE 500 #ifdef __linux__ #include #elif __FreeBSD__ @@ -5,9 +6,11 @@ #endif #include #include +#include #include #include "sway/commands.h" #include "sway/config.h" +#include "sway/ipc-server.h" #include "list.h" #include "log.h" #include "stringop.h" @@ -27,6 +30,33 @@ void free_sway_binding(struct sway_binding *binding) { free(binding); } +static struct sway_binding *sway_binding_dup(struct sway_binding *sb) { + struct sway_binding *new_sb = calloc(1, sizeof(struct sway_binding)); + if (!new_sb) { + return NULL; + } + + new_sb->type = sb->type; + new_sb->order = sb->order; + new_sb->flags = sb->flags; + new_sb->modifiers = sb->modifiers; + new_sb->command = strdup(sb->command); + + new_sb->keys = create_list(); + int i; + for (i = 0; i < sb->keys->length; ++i) { + xkb_keysym_t *key = malloc(sizeof(xkb_keysym_t)); + if (!key) { + free_sway_binding(new_sb); + return NULL; + } + *key = *(xkb_keysym_t *)sb->keys->items[i]; + list_add(new_sb->keys, key); + } + + return new_sb; +} + /** * Returns true if the bindings have the same key and modifier combinations. * Note that keyboard layout is not considered, so the bindings might actually @@ -275,11 +305,31 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) { void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) { wlr_log(WLR_DEBUG, "running command for binding: %s", binding->command); + + struct sway_binding *binding_copy = binding; + bool reload = false; + // if this is a reload command we need to make a duplicate of the + // binding since it will be gone after the reload has completed. + if (strcasecmp(binding->command, "reload") == 0) { + reload = true; + binding_copy = sway_binding_dup(binding); + if (!binding_copy) { + wlr_log(WLR_ERROR, "Failed to duplicate binding during reload"); + return; + } + } + config->handler_context.seat = seat; struct cmd_results *results = execute_command(binding->command, NULL); - if (results->status != CMD_SUCCESS) { + if (results->status == CMD_SUCCESS) { + ipc_event_binding(binding_copy); + } else { wlr_log(WLR_DEBUG, "could not run command for binding: %s (%s)", binding->command, results->error); } + + if (reload) { // free the binding if we made a copy + free_sway_binding(binding_copy); + } free_cmd_results(results); } diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 72031e24..8fceafa2 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -3,12 +3,18 @@ // Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0) #define _XOPEN_SOURCE 700 #endif +#ifdef __linux__ +#include +#elif __FreeBSD__ +#include +#endif #include #include #include #include #include #include +#include #include #include #include @@ -28,6 +34,7 @@ #include "sway/tree/view.h" #include "list.h" #include "log.h" +#include "util.h" static int ipc_socket = -1; static struct wl_event_source *ipc_event_source = NULL; @@ -367,6 +374,75 @@ void ipc_event_shutdown(const char *reason) { json_object_put(json); } +void ipc_event_binding(struct sway_binding *binding) { + if (!ipc_has_event_listeners(IPC_EVENT_BINDING)) { + return; + } + wlr_log(WLR_DEBUG, "Sending binding event"); + + json_object *json_binding = json_object_new_object(); + json_object_object_add(json_binding, "command", json_object_new_string(binding->command)); + + const char *names[10]; + int len = get_modifier_names(names, binding->modifiers); + json_object *modifiers = json_object_new_array(); + for (int i = 0; i < len; ++i) { + json_object_array_add(modifiers, json_object_new_string(names[i])); + } + json_object_object_add(json_binding, "event_state_mask", modifiers); + + json_object *input_codes = json_object_new_array(); + int input_code = 0; + json_object *symbols = json_object_new_array(); + json_object *symbol = NULL; + + if (binding->type == BINDING_KEYCODE) { // bindcode: populate input_codes + uint32_t keycode; + for (int i = 0; i < binding->keys->length; ++i) { + keycode = *(uint32_t *)binding->keys->items[i]; + json_object_array_add(input_codes, json_object_new_int(keycode)); + if (i == 0) { + input_code = keycode; + } + } + } else { // bindsym/mouse: populate symbols + uint32_t keysym; + char buffer[64]; + for (int i = 0; i < binding->keys->length; ++i) { + keysym = *(uint32_t *)binding->keys->items[i]; + if (keysym >= BTN_LEFT && keysym <= BTN_LEFT + 8) { + snprintf(buffer, 64, "button%u", keysym - BTN_LEFT + 1); + } else if (xkb_keysym_get_name(keysym, buffer, 64) < 0) { + continue; + } + + json_object *str = json_object_new_string(buffer); + if (i == 0) { + // str is owned by both symbol and symbols. Make sure + // to bump the ref count. + json_object_array_add(symbols, json_object_get(str)); + symbol = str; + } else { + json_object_array_add(symbols, str); + } + } + } + + json_object_object_add(json_binding, "input_codes", input_codes); + json_object_object_add(json_binding, "input_code", json_object_new_int(input_code)); + json_object_object_add(json_binding, "symbols", symbols); + json_object_object_add(json_binding, "symbol", symbol); + json_object_object_add(json_binding, "input_type", binding->type == BINDING_MOUSE ? + json_object_new_string("mouse") : json_object_new_string("keyboard")); + + json_object *json = json_object_new_object(); + json_object_object_add(json, "change", json_object_new_string("run")); + json_object_object_add(json, "binding", json_binding); + const char *json_string = json_object_to_json_string(json); + ipc_send_event(json_string, IPC_EVENT_BINDING); + json_object_put(json); +} + int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { struct ipc_client *client = data; From d898e035ba539005a8d7fa8283191f4c4054612e Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Wed, 18 Jul 2018 11:38:06 +0100 Subject: [PATCH 13/19] ipc: add workspace::reload event --- sway/commands/reload.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 36c6acce..5c1b19b4 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c @@ -22,6 +22,7 @@ struct cmd_results *cmd_reload(int argc, char **argv) { if (!load_main_config(config->current_config_path, true)) { return cmd_results_new(CMD_FAILURE, "reload", "Error(s) reloading config."); } + ipc_event_workspace(NULL, NULL, "reload"); load_swaybars(); From 75aba004603e35c80eda397c2e987f2c3e75cbf5 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Wed, 18 Jul 2018 11:40:16 +0100 Subject: [PATCH 14/19] ipc: always include old property in workspace events --- sway/ipc-server.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 8fceafa2..dc6b353b 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -298,13 +298,11 @@ void ipc_event_workspace(struct sway_container *old, wlr_log(WLR_DEBUG, "Sending workspace::%s event", change); json_object *obj = json_object_new_object(); json_object_object_add(obj, "change", json_object_new_string(change)); - if (strcmp("focus", change) == 0) { - if (old) { - json_object_object_add(obj, "old", - ipc_json_describe_container_recursive(old)); - } else { - json_object_object_add(obj, "old", NULL); - } + if (old) { + json_object_object_add(obj, "old", + ipc_json_describe_container_recursive(old)); + } else { + json_object_object_add(obj, "old", NULL); } if (new) { From 33433c64347eb0bfd7c1465a3b60579fa88ef724 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Wed, 18 Jul 2018 11:52:29 +0100 Subject: [PATCH 15/19] Add missing swaymsg completions --- completions/bash/swaymsg | 3 ++- completions/zsh/_swaymsg | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/completions/bash/swaymsg b/completions/bash/swaymsg index 8ec90b6f..e4b2c1b7 100644 --- a/completions/bash/swaymsg +++ b/completions/bash/swaymsg @@ -14,7 +14,8 @@ _swaymsg() 'get_marks' 'get_bar_config' 'get_version' - 'get_clipboard' + 'get_binding_modes' + 'get_config' ) short=( diff --git a/completions/zsh/_swaymsg b/completions/zsh/_swaymsg index 2e39deb6..28de474d 100644 --- a/completions/zsh/_swaymsg +++ b/completions/zsh/_swaymsg @@ -22,6 +22,8 @@ types=( 'get_marks' 'get_bar_config' 'get_version' +'get_binding_modes' +'get_config' ) _arguments -s \ From 3edaf2ce2a8a4753c162491329a7dfa492ff7e77 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Wed, 18 Jul 2018 12:30:39 +0100 Subject: [PATCH 16/19] ipc: add tick event --- completions/bash/swaymsg | 1 + completions/zsh/_swaymsg | 1 + include/ipc.h | 2 ++ sway/ipc-server.c | 30 ++++++++++++++++++++++++++++++ swaymsg/main.c | 8 +++++++- swaymsg/swaymsg.1.scd | 3 +++ 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/completions/bash/swaymsg b/completions/bash/swaymsg index e4b2c1b7..20092bdc 100644 --- a/completions/bash/swaymsg +++ b/completions/bash/swaymsg @@ -16,6 +16,7 @@ _swaymsg() 'get_version' 'get_binding_modes' 'get_config' + 'send_tick' ) short=( diff --git a/completions/zsh/_swaymsg b/completions/zsh/_swaymsg index 28de474d..a7a1c8e0 100644 --- a/completions/zsh/_swaymsg +++ b/completions/zsh/_swaymsg @@ -24,6 +24,7 @@ types=( 'get_version' 'get_binding_modes' 'get_config' +'send_tick' ) _arguments -s \ diff --git a/include/ipc.h b/include/ipc.h index ffc57d1b..2138d3fa 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -15,6 +15,7 @@ enum ipc_command_type { IPC_GET_VERSION = 7, IPC_GET_BINDING_MODES = 8, IPC_GET_CONFIG = 9, + IPC_SEND_TICK = 10, // sway-specific command types IPC_GET_INPUTS = 100, @@ -28,6 +29,7 @@ enum ipc_command_type { IPC_EVENT_BARCONFIG_UPDATE = ((1<<31) | 4), IPC_EVENT_BINDING = ((1<<31) | 5), IPC_EVENT_SHUTDOWN = ((1<<31) | 6), + IPC_EVENT_TICK = ((1<<31) | 7), IPC_EVENT_MODIFIER = ((1<<31) | 16), IPC_EVENT_INPUT = ((1<<31) | 17), }; diff --git a/sway/ipc-server.c b/sway/ipc-server.c index dc6b353b..63633567 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -441,6 +441,21 @@ void ipc_event_binding(struct sway_binding *binding) { json_object_put(json); } +static void ipc_event_tick(const char *payload) { + if (!ipc_has_event_listeners(IPC_EVENT_TICK)) { + return; + } + wlr_log(WLR_DEBUG, "Sending tick event"); + + json_object *json = json_object_new_object(); + json_object_object_add(json, "first", json_object_new_boolean(false)); + json_object_object_add(json, "payload", json_object_new_string(payload)); + + const char *json_string = json_object_to_json_string(json); + ipc_send_event(json_string, IPC_EVENT_TICK); + json_object_put(json); +} + int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { struct ipc_client *client = data; @@ -582,6 +597,13 @@ void ipc_client_handle_command(struct ipc_client *client) { goto exit_cleanup; } + case IPC_SEND_TICK: + { + ipc_event_tick(buf); + ipc_send_reply(client, "{\"success\": true}", 17); + goto exit_cleanup; + } + case IPC_GET_OUTPUTS: { json_object *outputs = json_object_new_array(); @@ -628,6 +650,7 @@ void ipc_client_handle_command(struct ipc_client *client) { goto exit_cleanup; } + bool is_tick = false; // parse requested event types for (size_t i = 0; i < json_object_array_length(request); i++) { const char *event_type = json_object_get_string(json_object_array_get_idx(request, i)); @@ -645,6 +668,9 @@ void ipc_client_handle_command(struct ipc_client *client) { client->subscribed_events |= event_mask(IPC_EVENT_MODIFIER); } else if (strcmp(event_type, "binding") == 0) { client->subscribed_events |= event_mask(IPC_EVENT_BINDING); + } else if (strcmp(event_type, "tick") == 0) { + client->subscribed_events |= event_mask(IPC_EVENT_TICK); + is_tick = true; } else { client_valid = ipc_send_reply(client, "{\"success\": false}", 18); @@ -656,6 +682,10 @@ void ipc_client_handle_command(struct ipc_client *client) { json_object_put(request); client_valid = ipc_send_reply(client, "{\"success\": true}", 17); + if (is_tick) { + client->current_command = IPC_EVENT_TICK; + ipc_send_reply(client, "{\"first\": true, \"payload\": \"\"}", 30); + } goto exit_cleanup; } diff --git a/swaymsg/main.c b/swaymsg/main.c index c4141ca5..3767daf3 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c @@ -250,12 +250,16 @@ static void pretty_print(int type, json_object *resp) { if (type != IPC_COMMAND && type != IPC_GET_WORKSPACES && type != IPC_GET_INPUTS && type != IPC_GET_OUTPUTS && type != IPC_GET_VERSION && type != IPC_GET_SEATS && - type != IPC_GET_CONFIG) { + type != IPC_GET_CONFIG && type != IPC_SEND_TICK) { printf("%s\n", json_object_to_json_string_ext(resp, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); return; } + if (type == IPC_SEND_TICK) { + return; + } + if (type == IPC_GET_VERSION) { pretty_print_version(resp); return; @@ -384,6 +388,8 @@ int main(int argc, char **argv) { type = IPC_GET_BINDING_MODES; } else if (strcasecmp(cmdtype, "get_config") == 0) { type = IPC_GET_CONFIG; + } else if (strcasecmp(cmdtype, "send_tick") == 0) { + type = IPC_SEND_TICK; } else { sway_abort("Unknown message type %s", cmdtype); } diff --git a/swaymsg/swaymsg.1.scd b/swaymsg/swaymsg.1.scd index a6e279da..8cf1b222 100644 --- a/swaymsg/swaymsg.1.scd +++ b/swaymsg/swaymsg.1.scd @@ -64,3 +64,6 @@ _swaymsg_ [options...] [message] *get\_config* Gets a JSON-encoded copy of the current configuration. + +*send\_tick* + Sends a tick event to all subscribed clients. From b2ac234569ff98de583d9e7755526cadf960f772 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Wed, 18 Jul 2018 21:52:15 +0100 Subject: [PATCH 17/19] ipc: fix workspace::focus event behaviour --- sway/input/seat.c | 4 +++- sway/tree/layout.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sway/input/seat.c b/sway/input/seat.c index c85e9242..76050aa9 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -739,7 +739,9 @@ void seat_set_focus_warp(struct sway_seat *seat, if (last_focus) { if (last_workspace) { - ipc_event_workspace(last_workspace, container, "focus"); + if (last_workspace != new_workspace) { + ipc_event_workspace(last_workspace, new_workspace, "focus"); + } if (!workspace_is_visible(last_workspace) && workspace_is_empty(last_workspace)) { if (last_workspace == last_focus) { diff --git a/sway/tree/layout.c b/sway/tree/layout.c index a0f9b6de..9fbbccaf 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -598,7 +598,7 @@ void container_move(struct sway_container *container, next_ws = container_parent(next_ws, C_WORKSPACE); } if (last_ws && next_ws && last_ws != next_ws) { - ipc_event_workspace(last_ws, container, "focus"); + ipc_event_workspace(last_ws, next_ws, "focus"); workspace_detect_urgent(last_ws); workspace_detect_urgent(next_ws); } From 03eaf444a4a432e5712d40f93d849b51d2028b63 Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Wed, 18 Jul 2018 21:55:14 +0100 Subject: [PATCH 18/19] ipc: prevent emitting a workspace::focus event when moving a container to a different workspace or output When a container is moved from, say, workspace 1 to workspace 2, workspace 2 is focused in order to arrange the windows before focus is moved back to workspace 1, which caused a workspace:focus event from workspace 2 to workspace 1 to be emitted. This commit inhibits that event. --- include/sway/input/seat.h | 2 +- sway/commands/move.c | 4 ++-- sway/input/cursor.c | 6 +++--- sway/input/seat.c | 6 +++--- sway/tree/layout.c | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 07febe2c..92387601 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h @@ -99,7 +99,7 @@ void seat_configure_xcursor(struct sway_seat *seat); void seat_set_focus(struct sway_seat *seat, struct sway_container *container); void seat_set_focus_warp(struct sway_seat *seat, - struct sway_container *container, bool warp); + struct sway_container *container, bool warp, bool notify); void seat_set_focus_surface(struct sway_seat *seat, struct wlr_surface *surface, bool unfocus); diff --git a/sway/commands/move.c b/sway/commands/move.c index 1aae3838..46ebcd83 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c @@ -98,7 +98,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, container_move_to(current, destination); struct sway_container *focus = seat_get_focus_inactive( config->handler_context.seat, old_parent); - seat_set_focus(config->handler_context.seat, focus); + seat_set_focus_warp(config->handler_context.seat, focus, true, false); container_reap_empty(old_parent); container_reap_empty(destination->parent); @@ -135,7 +135,7 @@ static struct cmd_results *cmd_move_container(struct sway_container *current, struct sway_container *old_parent = current->parent; struct sway_container *old_ws = container_parent(current, C_WORKSPACE); container_move_to(current, focus); - seat_set_focus(config->handler_context.seat, old_parent); + seat_set_focus_warp(config->handler_context.seat, old_parent, true, false); container_reap_empty(old_parent); container_reap_empty(focus->parent); diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 96ac7b33..d6fdc1da 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c @@ -349,7 +349,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, output = container_parent(c, C_OUTPUT); } if (output != focus) { - seat_set_focus_warp(seat, c, false); + seat_set_focus_warp(seat, c, false, true); } } else if (c->type == C_VIEW) { // Focus c if the following are true: @@ -359,13 +359,13 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && c != prev_c && view_is_visible(c->sway_view)) { - seat_set_focus_warp(seat, c, false); + seat_set_focus_warp(seat, c, false, true); } else { struct sway_container *next_focus = seat_get_focus_inactive(seat, &root_container); if (next_focus && next_focus->type == C_VIEW && view_is_visible(next_focus->sway_view)) { - seat_set_focus_warp(seat, next_focus, false); + seat_set_focus_warp(seat, next_focus, false, true); } } } diff --git a/sway/input/seat.c b/sway/input/seat.c index 76050aa9..fe3cbc53 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c @@ -617,7 +617,7 @@ static int handle_urgent_timeout(void *data) { } void seat_set_focus_warp(struct sway_seat *seat, - struct sway_container *container, bool warp) { + struct sway_container *container, bool warp, bool notify) { if (seat->focused_layer) { return; } @@ -739,7 +739,7 @@ void seat_set_focus_warp(struct sway_seat *seat, if (last_focus) { if (last_workspace) { - if (last_workspace != new_workspace) { + if (notify && last_workspace != new_workspace) { ipc_event_workspace(last_workspace, new_workspace, "focus"); } if (!workspace_is_visible(last_workspace) @@ -779,7 +779,7 @@ void seat_set_focus_warp(struct sway_seat *seat, void seat_set_focus(struct sway_seat *seat, struct sway_container *container) { - seat_set_focus_warp(seat, container, true); + seat_set_focus_warp(seat, container, true, true); } void seat_set_focus_surface(struct sway_seat *seat, diff --git a/sway/tree/layout.c b/sway/tree/layout.c index 9fbbccaf..1f82e534 100644 --- a/sway/tree/layout.c +++ b/sway/tree/layout.c @@ -1001,13 +1001,13 @@ static void swap_focus(struct sway_container *con1, if (focus == con1 && (con2->parent->layout == L_TABBED || con2->parent->layout == L_STACKED)) { if (workspace_is_visible(ws2)) { - seat_set_focus_warp(seat, con2, false); + seat_set_focus_warp(seat, con2, false, true); } seat_set_focus(seat, ws1 != ws2 ? con2 : con1); } else if (focus == con2 && (con1->parent->layout == L_TABBED || con1->parent->layout == L_STACKED)) { if (workspace_is_visible(ws1)) { - seat_set_focus_warp(seat, con1, false); + seat_set_focus_warp(seat, con1, false, true); } seat_set_focus(seat, ws1 != ws2 ? con1 : con2); } else if (ws1 != ws2) { From 46cfa8ff56acff0139b2e24300cbc3ea19da723f Mon Sep 17 00:00:00 2001 From: Ian Fan Date: Wed, 1 Aug 2018 16:22:06 +0100 Subject: [PATCH 19/19] ipc: remove extraneous values Removes IPC_EVENT_MODIFIER and IPC_EVENT_INPUT, which were sway-specific and unused --- include/ipc.h | 2 -- sway/ipc-server.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/include/ipc.h b/include/ipc.h index 2138d3fa..a3f60e19 100644 --- a/include/ipc.h +++ b/include/ipc.h @@ -30,8 +30,6 @@ enum ipc_command_type { IPC_EVENT_BINDING = ((1<<31) | 5), IPC_EVENT_SHUTDOWN = ((1<<31) | 6), IPC_EVENT_TICK = ((1<<31) | 7), - IPC_EVENT_MODIFIER = ((1<<31) | 16), - IPC_EVENT_INPUT = ((1<<31) | 17), }; #endif diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 63633567..7d2d8969 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -664,8 +664,6 @@ void ipc_client_handle_command(struct ipc_client *client) { client->subscribed_events |= event_mask(IPC_EVENT_SHUTDOWN); } else if (strcmp(event_type, "window") == 0) { client->subscribed_events |= event_mask(IPC_EVENT_WINDOW); - } else if (strcmp(event_type, "modifier") == 0) { - client->subscribed_events |= event_mask(IPC_EVENT_MODIFIER); } else if (strcmp(event_type, "binding") == 0) { client->subscribed_events |= event_mask(IPC_EVENT_BINDING); } else if (strcmp(event_type, "tick") == 0) {