From bbd2394601918653f8f21cad57f5694f9b3da26a Mon Sep 17 00:00:00 2001 From: Timur Celik Date: Mon, 5 Jul 2021 17:38:04 +0200 Subject: [PATCH 1/4] modules: Implement workspace rename event A renamed workspace caused yambar to abort in a failed assertion, because workspace lookup was done by name and the `rename` event was not implemented. To resolve this issue this patch implements the `rename` event and as a necessity changes workspace_lookup() to use ids instead of names. --- modules/i3.c | 75 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 23 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index e036f97..3e33f95 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -29,6 +29,7 @@ struct ws_content { }; struct workspace { + int id; char *name; int name_as_int; /* -1 if name is not a decimal number */ bool persistent; @@ -103,8 +104,9 @@ static bool workspace_from_json(const struct json_object *json, struct workspace *ws) { /* Always present */ - struct json_object *name, *output; - if (!json_object_object_get_ex(json, "name", &name) || + struct json_object *id, *name, *output; + if (!json_object_object_get_ex(json, "id", &id) || + !json_object_object_get_ex(json, "name", &name) || !json_object_object_get_ex(json, "output", &output)) { LOG_ERR("workspace reply/event without 'name' and/or 'output' " @@ -132,6 +134,7 @@ workspace_from_json(const struct json_object *json, struct workspace *ws) int name_as_int = workspace_name_as_int(name_as_string); *ws = (struct workspace) { + .id = json_object_get_int(id), .name = strdup(name_as_string), .name_as_int = name_as_int, .persistent = false, @@ -222,12 +225,12 @@ workspace_add(struct private *m, struct workspace ws) } static void -workspace_del(struct private *m, const char *name) +workspace_del(struct private *m, int id) { tll_foreach(m->workspaces, it) { struct workspace *ws = &it->item; - if (strcmp(ws->name, name) != 0) + if (ws->id != id) continue; workspace_free(ws); @@ -237,11 +240,11 @@ workspace_del(struct private *m, const char *name) } static struct workspace * -workspace_lookup(struct private *m, const char *name) +workspace_lookup(struct private *m, int id) { tll_foreach(m->workspaces, it) { struct workspace *ws = &it->item; - if (strcmp(ws->name, name) == 0) + if (ws->id == id) return ws; } return NULL; @@ -280,12 +283,12 @@ handle_subscribe_reply(int type, const struct json_object *json, void *_m) static bool workspace_update_or_add(struct private *m, const struct json_object *ws_json) { - struct json_object *name; - if (!json_object_object_get_ex(ws_json, "name", &name)) + struct json_object *_id; + if (!json_object_object_get_ex(ws_json, "id", &_id)) return false; - const char *name_as_string = json_object_get_string(name); - struct workspace *already_exists = workspace_lookup(m, name_as_string); + const int id = json_object_get_int(_id); + struct workspace *already_exists = workspace_lookup(m, id); if (already_exists != NULL) { bool persistent = already_exists->persistent; @@ -350,6 +353,7 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) bool is_init = strcmp(change_str, "init") == 0; bool is_empty = strcmp(change_str, "empty") == 0; bool is_focused = strcmp(change_str, "focus") == 0; + bool is_rename = strcmp(change_str, "rename") == 0; bool is_urgent = strcmp(change_str, "urgent") == 0; bool is_reload = strcmp(change_str, "reload") == 0; @@ -358,15 +362,15 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) return true; } - struct json_object *current, *_current_name; + struct json_object *current, *_current_id; if (!json_object_object_get_ex(json, "current", ¤t) || - !json_object_object_get_ex(current, "name", &_current_name)) + !json_object_object_get_ex(current, "id", &_current_id)) { - LOG_ERR("workspace event without 'current' and/or 'name' properties"); + LOG_ERR("workspace event without 'current' and/or 'id' properties"); return false; } - const char *current_name = json_object_get_string(_current_name); + int current_id = json_object_get_int(_current_id); mtx_lock(&mod->lock); @@ -376,23 +380,22 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) } else if (is_empty) { - struct workspace *ws = workspace_lookup(m, current_name); + struct workspace *ws = workspace_lookup(m, current_id); assert(ws != NULL); if (!ws->persistent) - workspace_del(m, current_name); + workspace_del(m, current_id); else { workspace_free(ws); - ws->name = strdup(current_name); ws->empty = true; assert(ws->persistent); } } else if (is_focused) { - struct json_object *old, *_old_name, *urgent; + struct json_object *old, *_old_id, *urgent; if (!json_object_object_get_ex(json, "old", &old) || - !json_object_object_get_ex(old, "name", &_old_name) || + !json_object_object_get_ex(old, "id", &_old_id) || !json_object_object_get_ex(current, "urgent", &urgent)) { LOG_ERR("workspace 'focused' event without 'old', 'name' and/or 'urgent' property"); @@ -400,7 +403,7 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) return false; } - struct workspace *w = workspace_lookup(m, current_name); + struct workspace *w = workspace_lookup(m, current_id); assert(w != NULL); LOG_DBG("w: %s", w->name); @@ -417,12 +420,38 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) w->visible = true; /* Old workspace is no longer focused */ - const char *old_name = json_object_get_string(_old_name); - struct workspace *old_w = workspace_lookup(m, old_name); + int old_id = json_object_get_int(_old_id); + struct workspace *old_w = workspace_lookup(m, old_id); if (old_w != NULL) old_w->focused = false; } + else if (is_rename) { + struct workspace *w = workspace_lookup(m, current_id); + assert(w != NULL); + + struct json_object *_current_name; + if (!json_object_object_get_ex(current, "name", &_current_name)) { + LOG_ERR("workspace 'rename' event without 'name' property"); + mtx_unlock(&mod->lock); + return false; + } + + free(w->name); + w->name = strdup(json_object_get_string(_current_name)); + w->name_as_int = workspace_name_as_int(w->name); + + /* Re-add the workspace to ensure correct sorting */ + struct workspace ws = *w; + tll_foreach(m->workspaces, it) { + if (it->item.id == current_id) { + tll_remove(m->workspaces, it); + break; + } + } + workspace_add(m, ws); + } + else if (is_urgent) { struct json_object *urgent; if (!json_object_object_get_ex(current, "urgent", &urgent)) { @@ -431,7 +460,7 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) return false; } - struct workspace *w = workspace_lookup(m, current_name); + struct workspace *w = workspace_lookup(m, current_id); w->urgent = json_object_get_boolean(urgent); } From 8f89545b32fa3ba1bba8accdaff9abc7c28b978c Mon Sep 17 00:00:00 2001 From: Timur Celik Date: Tue, 6 Jul 2021 11:05:17 +0200 Subject: [PATCH 2/4] modules: Warn for all unknown workspace events --- modules/i3.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index 3e33f95..f970b0a 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -355,12 +355,6 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) bool is_focused = strcmp(change_str, "focus") == 0; bool is_rename = strcmp(change_str, "rename") == 0; bool is_urgent = strcmp(change_str, "urgent") == 0; - bool is_reload = strcmp(change_str, "reload") == 0; - - if (is_reload) { - LOG_WARN("unimplemented: 'reload' event"); - return true; - } struct json_object *current, *_current_id; if (!json_object_object_get_ex(json, "current", ¤t) || @@ -464,6 +458,10 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) w->urgent = json_object_get_boolean(urgent); } + else { + LOG_WARN("unimplemented workspace event '%s'", change_str); + } + m->dirty = true; mtx_unlock(&mod->lock); return true; From 24a3b90a01068819297055ed277cf8d78b9130ee Mon Sep 17 00:00:00 2001 From: Timur Celik Date: Tue, 6 Jul 2021 12:06:49 +0200 Subject: [PATCH 3/4] modules: Implement workspace move event Implementing the move event required to pass the IPC socket to `i3_ipc_callback_t`, because we won't get notified about any visibility changes of other workspaces. That's why we query all workspaces again after a focused workspace was moved. --- modules/i3-common.c | 2 +- modules/i3-common.h | 2 +- modules/i3.c | 36 ++++++++++++++++++++++++++++++------ modules/sway-xkb.c | 4 ++-- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/modules/i3-common.c b/modules/i3-common.c index 589bfb8..a0769f2 100644 --- a/modules/i3-common.c +++ b/modules/i3-common.c @@ -309,7 +309,7 @@ i3_receive_loop(int abort_fd, int sock, } if (pkt_handler != NULL) - err = !pkt_handler(hdr->type, json, data); + err = !pkt_handler(sock, hdr->type, json, data); else LOG_DBG("no handler for reply/event %d; ignoring", hdr->type); diff --git a/modules/i3-common.h b/modules/i3-common.h index e3d94d1..0cbfa3e 100644 --- a/modules/i3-common.h +++ b/modules/i3-common.h @@ -11,7 +11,7 @@ bool i3_get_socket_address(struct sockaddr_un *addr); bool i3_send_pkg(int sock, int cmd, char *data); -typedef bool (*i3_ipc_callback_t)(int type, const struct json_object *json, void *data); +typedef bool (*i3_ipc_callback_t)(int sock, int type, const struct json_object *json, void *data); struct i3_ipc_callbacks { void (*burst_done)(void *data); diff --git a/modules/i3.c b/modules/i3.c index f970b0a..160913b 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -251,7 +251,7 @@ workspace_lookup(struct private *m, int id) } static bool -handle_get_version_reply(int type, const struct json_object *json, void *_m) +handle_get_version_reply(int sock, int type, const struct json_object *json, void *_m) { struct json_object *version; if (!json_object_object_get_ex(json, "human_readable", &version)) { @@ -264,7 +264,7 @@ handle_get_version_reply(int type, const struct json_object *json, void *_m) } static bool -handle_subscribe_reply(int type, const struct json_object *json, void *_m) +handle_subscribe_reply(int sock, int type, const struct json_object *json, void *_m) { struct json_object *success; if (!json_object_object_get_ex(json, "success", &success)) { @@ -310,7 +310,7 @@ workspace_update_or_add(struct private *m, const struct json_object *ws_json) } static bool -handle_get_workspaces_reply(int type, const struct json_object *json, void *_mod) +handle_get_workspaces_reply(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; @@ -337,7 +337,7 @@ err: } static bool -handle_workspace_event(int type, const struct json_object *json, void *_mod) +handle_workspace_event(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; @@ -354,6 +354,7 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) bool is_empty = strcmp(change_str, "empty") == 0; bool is_focused = strcmp(change_str, "focus") == 0; bool is_rename = strcmp(change_str, "rename") == 0; + bool is_move = strcmp(change_str, "move") == 0; bool is_urgent = strcmp(change_str, "urgent") == 0; struct json_object *current, *_current_id; @@ -446,6 +447,29 @@ handle_workspace_event(int type, const struct json_object *json, void *_mod) workspace_add(m, ws); } + else if (is_move) { + struct workspace *w = workspace_lookup(m, current_id); + assert(w != NULL); + + struct json_object *_current_output; + if (!json_object_object_get_ex(current, "output", &_current_output)) { + LOG_ERR("workspace 'move' event without 'output' property"); + mtx_unlock(&mod->lock); + return false; + } + + free(w->output); + w->output = strdup(json_object_get_string(_current_output)); + + /* + * If the moved workspace was focused, schedule a full update because + * visibility for other workspaces may have changed. + */ + if (w->focused) { + i3_send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); + } + } + else if (is_urgent) { struct json_object *urgent; if (!json_object_object_get_ex(current, "urgent", &urgent)) { @@ -472,7 +496,7 @@ err: } static bool -handle_window_event(int type, const struct json_object *json, void *_mod) +handle_window_event(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; @@ -606,7 +630,7 @@ handle_window_event(int type, const struct json_object *json, void *_mod) } static bool -handle_mode_event(int type, const struct json_object *json, void *_mod) +handle_mode_event(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; diff --git a/modules/sway-xkb.c b/modules/sway-xkb.c index 3f2e965..269df24 100644 --- a/modules/sway-xkb.c +++ b/modules/sway-xkb.c @@ -94,7 +94,7 @@ content(struct module *mod) } static bool -handle_input_reply(int type, const struct json_object *json, void *_mod) +handle_input_reply(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; @@ -162,7 +162,7 @@ handle_input_reply(int type, const struct json_object *json, void *_mod) } static bool -handle_input_event(int type, const struct json_object *json, void *_mod) +handle_input_event(int sock, int type, const struct json_object *json, void *_mod) { struct module *mod = _mod; struct private *m = mod->private; From 266a2efbb6f654d095e1c571bc0d25b0ced4ee10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 13 Dec 2022 16:25:55 +0100 Subject: [PATCH 4/4] =?UTF-8?q?changelog:=20sway:=20workspace=20=E2=80=98m?= =?UTF-8?q?ove=E2=80=99=20and=20=E2=80=98rename=E2=80=99=20events?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1f345f..ddde62d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ * pipewire: add a new module for pipewire ([#224][224]) * on-click: support `next`/`previous` mouse buttons ([#228][228]). * dwl: add a new module for DWL ([#218][218]) +* sway: support for workspace ‘rename’ and ‘move’ events + ([#216][216]). [153]: https://codeberg.org/dnkl/yambar/issues/153 [159]: https://codeberg.org/dnkl/yambar/issues/159 @@ -43,6 +45,7 @@ [223]: https://codeberg.org/dnkl/yambar/pulls/223 [224]: https://codeberg.org/dnkl/yambar/pulls/224 [228]: https://codeberg.org/dnkl/yambar/pulls/228 +[216]: https://codeberg.org/dnkl/yambar/issues/216 ### Changed