From 5ed6e0acbcc39956c0b874c04b1637a8eeeca5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 9 Feb 2019 12:02:05 +0100 Subject: [PATCH 01/10] module/i3: look for I3SOCK env variable before reading X properties --- modules/i3.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index 7869693..0c59d58 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -435,11 +435,14 @@ get_socket_address(struct sockaddr_un *addr) const char *sway_sock = getenv("SWAYSOCK"); if (sway_sock == NULL) { + sway_sock = getenv("I3SOCK"); + if (sway_sock == NULL) { #if defined(ENABLE_X11) - return get_socket_address_x11(addr); + return get_socket_address_x11(addr); #else - return false; + return false; #endif + } } strncpy(addr->sun_path, sway_sock, sizeof(addr->sun_path) - 1); From d565fbe2f06a16a6a6771077bbd564dfaff12619 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 9 Feb 2019 12:31:06 +0100 Subject: [PATCH 02/10] module/i3: track active window title and application name This is done on a per-workspace basis. Note that the initial state is currently not detected. I.e. we retrieve the initial workspace list, but we don't get the currently focused window. --- modules/i3.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 111 insertions(+), 3 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index 0c59d58..9a525a7 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -7,8 +7,11 @@ #include +#include +#include #include #include +#include #if defined(ENABLE_X11) #include @@ -45,6 +48,12 @@ struct workspace { bool visible; bool focused; bool urgent; + + struct { + char *title; + char *application; + pid_t pid; + } window; }; struct private { @@ -108,6 +117,7 @@ workspace_from_json(const struct json_object *json, struct workspace *ws) .visible = json_object_get_boolean(visible), .focused = json_object_get_boolean(focused), .urgent = json_object_get_boolean(urgent), + .window = {.title = NULL, .pid = -1}, }; return true; @@ -118,6 +128,8 @@ workspace_free(struct workspace ws) { free(ws.name); free(ws.output); + free(ws.window.title); + free(ws.window.application); } static void @@ -377,6 +389,95 @@ handle_workspace_event(struct private *m, const struct json_object *json) return true; } +static bool +handle_window_event(struct private *m, const struct json_object *json) +{ + struct workspace *ws = NULL; + size_t focused = 0; + for (size_t i = 0; i < m->workspaces.count; i++) { + if (m->workspaces.v[i].focused) { + ws = &m->workspaces.v[i]; + focused++; + } + } + + assert(focused == 1); + assert(ws != NULL); + + if (!json_object_is_type(json, json_type_object)) { + LOG_ERR("'window' event is not of type 'object'"); + return false; + } + + struct json_object *change = json_object_object_get(json, "change"); + if (change == NULL || !json_object_is_type(change, json_type_string)) { + LOG_ERR("'window' event did not contain a 'change' string value"); + return false; + } + + const char *change_str = json_object_get_string(change); + + if (strcmp(change_str, "close") == 0 || strcmp(change_str, "new") == 0) { + free(ws->window.title); + free(ws->window.application); + + ws->window.title = ws->window.application = NULL; + ws->window.pid = -1; + return true; + } + + const struct json_object *container = json_object_object_get(json, "container"); + if (container == NULL || !json_object_is_type(container, json_type_object)) { + LOG_ERR("'window' event (%s) did not contain a 'container' object", change_str); + return false; + } + + struct json_object *name = json_object_object_get(container, "name"); + if (name == NULL || !json_object_is_type(name, json_type_string)) { + LOG_ERR( + "'window' event (%s) did not contain a 'container.name' string value", + change_str); + return false; + } + + free(ws->window.title); + ws->window.title = strdup(json_object_get_string(name)); + + const struct json_object *pid = json_object_object_get(container, "pid"); + if (pid == NULL || !json_object_is_type(pid, json_type_int)) { + LOG_ERR( + "'window' event (%s) did not contain a 'container.pid' integer value", + change_str); + return false; + } + + /* If PID has changed, update application name from /proc//comm */ + if (ws->window.pid != json_object_get_int(pid)) { + ws->window.pid = json_object_get_int(pid); + + char path[64]; + snprintf(path, sizeof(path), "/proc/%u/comm", ws->window.pid); + + int fd = open(path, O_RDONLY); + if (fd == -1) { + /* Application may simply have terminated */ + free(ws->window.application); ws->window.application = NULL; + ws->window.pid = -1; + return true; + } + + char application[128]; + ssize_t bytes = read(fd, application, sizeof(application)); + assert(bytes >= 0); + + application[bytes - 1] = '\0'; + ws->window.application = strdup(application); + close(fd); + } + + return true; +} + #if defined(ENABLE_X11) static bool get_socket_address_x11(struct sockaddr_un *addr) @@ -473,7 +574,7 @@ run(struct module *mod) send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_VERSION, NULL); send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); - send_pkg(sock, I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[\"workspace\"]"); + send_pkg(sock, I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[\"workspace\", \"window\"]"); /* Initial reply typically requires a couple of KB. But we often * need more later. For example, switching workspaces can result @@ -583,9 +684,13 @@ run(struct module *mod) need_bar_refresh = true; break; + case I3_IPC_EVENT_WINDOW: + handle_window_event(m, json); + need_bar_refresh = true; + break; + case I3_IPC_EVENT_OUTPUT: case I3_IPC_EVENT_MODE: - case I3_IPC_EVENT_WINDOW: case I3_IPC_EVENT_BARCONFIG_UPDATE: case I3_IPC_EVENT_BINDING: case I3_IPC_EVENT_SHUTDOWN: @@ -687,8 +792,11 @@ content(struct module *mod) tag_new_bool(mod, "focused", ws->focused), tag_new_bool(mod, "urgent", ws->urgent), tag_new_string(mod, "state", state), + + tag_new_string(mod, "application", ws->window.application), + tag_new_string(mod, "title", ws->window.title), }, - .count = 5, + .count = 7, }; particles[particle_count++] = template->content->instantiate( From 4100922b7a96c3bdabd8880d772cb06a2ae8f07f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 9 Feb 2019 13:06:36 +0100 Subject: [PATCH 03/10] module/i3: allow 'content' to also contain a regular 'label' Previously, the 'content' of i3 was a map, where the keys where i3 workspace names, mapping to a particle template. Now, that configuration type is still allowed. But we also allow a variant where the 'content' is a list, of either 1 or 2 entries. Both entries *must* be dictionaries. The key is either 'dynlist', which is the same as the dictionary-only type of configuration. I.e. it maps to a dictionary where the keys are workspace names, mapping to particle templates. If the key is *not* dynlist, then it is assumed to be a particle name, and we treat that as a "regular" label, that will be appended after the workspace dynlist when instantiating the content. This particle will be instantiated with, for now, the title and application of the _currently focused_ workspace. --- modules/i3.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 120 insertions(+), 12 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index 9a525a7..5d805e4 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -69,6 +69,8 @@ struct private { struct workspace *v; size_t count; } workspaces; + + struct particle *label; }; static bool @@ -736,6 +738,9 @@ destroy(struct module *mod) free(m->ws_content.v); workspaces_free(m); + if (m->label != NULL) + m->label->destroy(m->label); + free(m); module_default_destroy(mod); } @@ -759,7 +764,7 @@ content(struct module *mod) mtx_lock(&mod->lock); - struct exposable *particles[m->workspaces.count]; + struct exposable *particles[m->workspaces.count + (m->label != NULL)]; size_t particle_count = 0; for (size_t i = 0; i < m->workspaces.count; i++) { @@ -805,6 +810,32 @@ content(struct module *mod) tag_set_destroy(&tags); } + /* Find currently focused workspace */ + const struct workspace *ws = NULL; + size_t count = 0; + for (size_t i = 0; i < m->workspaces.count; i++) { + if (m->workspaces.v[i].focused) { + ws = &m->workspaces.v[i]; + count++; + } + } + + assert(count <= 1); + assert(count == 0 || ws != NULL); + + if (ws != NULL && m->label != NULL) { + struct tag_set tags = { + .tags = (struct tag *[]){ + tag_new_string(mod, "application", ws->window.application), + tag_new_string(mod, "title", ws->window.title), + }, + .count = 2, + }; + + particles[particle_count++] = m->label->instantiate(m->label, &tags); + tag_set_destroy(&tags); + } + mtx_unlock(&mod->lock); return dynlist_exposable_new( particles, particle_count, m->left_spacing, m->right_spacing); @@ -818,7 +849,7 @@ struct i3_workspaces { static struct module * i3_new(struct i3_workspaces workspaces[], size_t workspace_count, - int left_spacing, int right_spacing) + struct particle *label, int left_spacing, int right_spacing) { struct private *m = calloc(1, sizeof(*m)); @@ -833,6 +864,8 @@ i3_new(struct i3_workspaces workspaces[], size_t workspace_count, m->ws_content.v[i].content = workspaces[i].content; } + m->label = label; + struct module *mod = module_common_new(); mod->private = m; mod->run = &run; @@ -854,10 +887,37 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) int right = spacing != NULL ? yml_value_as_int(spacing) : right_spacing != NULL ? yml_value_as_int(right_spacing) : 0; - struct i3_workspaces workspaces[yml_dict_length(c)]; + const struct yml_node *ws_root_node = NULL; + struct particle *label = NULL; + + if (yml_is_dict(c)) { + ws_root_node = c; + } else { + for (struct yml_list_iter it = yml_list_iter(c); + it.node != NULL; + yml_list_next(&it)) + { + assert(yml_is_dict(it.node)); + assert(yml_dict_length(it.node) == 1); + + const struct yml_dict_iter item = yml_dict_iter(it.node); + const char *key = yml_value_as_string(item.key); + + if (strcmp(key, "dynlist") == 0) { + ws_root_node = item.value; + } else { + assert(label == NULL); + label = conf_to_particle(it.node, inherited); + } + } + } + + assert(yml_is_dict(ws_root_node)); + const size_t ws_count = yml_dict_length(ws_root_node); + struct i3_workspaces workspaces[ws_count]; size_t idx = 0; - for (struct yml_dict_iter it = yml_dict_iter(c); + for (struct yml_dict_iter it = yml_dict_iter(ws_root_node); it.key != NULL; yml_dict_next(&it), idx++) { @@ -865,18 +925,13 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) workspaces[idx].content = conf_to_particle(it.value, inherited); } - return i3_new(workspaces, yml_dict_length(c), left, right); + return i3_new(workspaces, ws_count, label, left, right); } static bool -verify_content(keychain_t *chain, const struct yml_node *node) +verify_content_dynlist(keychain_t *chain, const struct yml_node *node) { - if (!yml_is_dict(node)) { - LOG_ERR( - "%s: must be a dictionary of workspace-name: particle mappings", - conf_err_prefix(chain, node)); - return false; - } + assert(yml_is_dict(node)); for (struct yml_dict_iter it = yml_dict_iter(node); it.key != NULL; @@ -898,6 +953,59 @@ verify_content(keychain_t *chain, const struct yml_node *node) return true; } +static bool +verify_content(keychain_t *chain, const struct yml_node *node) +{ + if (!yml_is_dict(node) && !yml_is_list(node)) { + LOG_ERR( + "%s: must be a dictionary of workspace-name: particle mappings", + conf_err_prefix(chain, node)); + return false; + } + + if (yml_is_dict(node)) + return verify_content_dynlist(chain, node); + + if (yml_list_length(node) > 2) { + LOG_ERR("%s: must be a list of at most 2 entries", + conf_err_prefix(chain, node)); + return false; + } + + for (struct yml_list_iter it = yml_list_iter(node); + it.node != NULL; + yml_list_next(&it)) + { + if (!yml_is_dict(it.node) || yml_dict_length(it.node) != 1) { + LOG_ERR( + "%s: item must be a dictionary with a single item; " + "either a 'dynlist', or a particle name", + conf_err_prefix(chain, it.node)); + return false; + } + + const struct yml_dict_iter item = yml_dict_iter(it.node); + const char *key = yml_value_as_string(item.key); + if (key == NULL) { + LOG_ERR("%s: key must be a string; either 'dynlist', or a particle name", + conf_err_prefix(chain, item.key)); + return false; + } + + if (strcmp(key, "dynlist") == 0) { + if (!verify_content_dynlist(chain_push(chain, key), item.value)) + return false; + chain_pop(chain); + } else { + if (!conf_verify_particle(chain, it.node)) + return false; + } + + } + + return true; +} + static bool verify_conf(keychain_t *chain, const struct yml_node *node) { From be4765fadd9977ef6753fddc2d29d95a0f4b8b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 9 Feb 2019 13:12:07 +0100 Subject: [PATCH 04/10] module/i3: 'dynlist' -> 'workspaces' --- modules/i3.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index 5d805e4..b7ef8a7 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -903,7 +903,7 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) const struct yml_dict_iter item = yml_dict_iter(it.node); const char *key = yml_value_as_string(item.key); - if (strcmp(key, "dynlist") == 0) { + if (strcmp(key, "workspaces") == 0) { ws_root_node = item.value; } else { assert(label == NULL); @@ -979,7 +979,7 @@ verify_content(keychain_t *chain, const struct yml_node *node) if (!yml_is_dict(it.node) || yml_dict_length(it.node) != 1) { LOG_ERR( "%s: item must be a dictionary with a single item; " - "either a 'dynlist', or a particle name", + "either a 'workspaces', or a particle name", conf_err_prefix(chain, it.node)); return false; } @@ -987,12 +987,13 @@ verify_content(keychain_t *chain, const struct yml_node *node) const struct yml_dict_iter item = yml_dict_iter(it.node); const char *key = yml_value_as_string(item.key); if (key == NULL) { - LOG_ERR("%s: key must be a string; either 'dynlist', or a particle name", - conf_err_prefix(chain, item.key)); + LOG_ERR( + "%s: key must be a string; either 'workspaces', or a particle name", + conf_err_prefix(chain, item.key)); return false; } - if (strcmp(key, "dynlist") == 0) { + if (strcmp(key, "workspaces") == 0) { if (!verify_content_dynlist(chain_push(chain, key), item.value)) return false; chain_pop(chain); From 83db675e01ecc6dd49682de5b330adff478080c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 9 Feb 2019 13:14:08 +0100 Subject: [PATCH 05/10] module/i3: subscribe *before* requesting initial workspace list This ensures we don't have a race, where we might miss workspace changes between the initial list and subscribing. --- modules/i3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/i3.c b/modules/i3.c index b7ef8a7..6e7fa75 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -575,8 +575,8 @@ run(struct module *mod) } send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_VERSION, NULL); - send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); send_pkg(sock, I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[\"workspace\", \"window\"]"); + send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL); /* Initial reply typically requires a couple of KB. But we often * need more later. For example, switching workspaces can result From a3be2839e5da1ba780b63a0956c44c18c51c1343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 9 Feb 2019 16:58:08 +0100 Subject: [PATCH 06/10] module/i3: avoid calling json_object_get_int() multiple times --- modules/i3.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index 6e7fa75..c672ae0 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -445,8 +445,8 @@ handle_window_event(struct private *m, const struct json_object *json) free(ws->window.title); ws->window.title = strdup(json_object_get_string(name)); - const struct json_object *pid = json_object_object_get(container, "pid"); - if (pid == NULL || !json_object_is_type(pid, json_type_int)) { + const struct json_object *pid_node = json_object_object_get(container, "pid"); + if (pid_node == NULL || !json_object_is_type(pid_node, json_type_int)) { LOG_ERR( "'window' event (%s) did not contain a 'container.pid' integer value", change_str); @@ -454,8 +454,9 @@ handle_window_event(struct private *m, const struct json_object *json) } /* If PID has changed, update application name from /proc//comm */ - if (ws->window.pid != json_object_get_int(pid)) { - ws->window.pid = json_object_get_int(pid); + pid_t pid = json_object_get_int(pid_node); + if (ws->window.pid != pid) { + ws->window.pid = pid; char path[64]; snprintf(path, sizeof(path), "/proc/%u/comm", ws->window.pid); From 330ad48dfd1f637664e2906af95f1fce979de2d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 9 Feb 2019 21:48:28 +0100 Subject: [PATCH 07/10] module/i3: handle 'label' like an extra workspace called 'current' --- modules/i3.c | 114 ++++++++------------------------------------------- 1 file changed, 17 insertions(+), 97 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index c672ae0..ff71629 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -69,8 +69,6 @@ struct private { struct workspace *v; size_t count; } workspaces; - - struct particle *label; }; static bool @@ -739,9 +737,6 @@ destroy(struct module *mod) free(m->ws_content.v); workspaces_free(m); - if (m->label != NULL) - m->label->destroy(m->label); - free(m); module_default_destroy(mod); } @@ -765,7 +760,7 @@ content(struct module *mod) mtx_lock(&mod->lock); - struct exposable *particles[m->workspaces.count + (m->label != NULL)]; + struct exposable *particles[m->workspaces.count + 1]; size_t particle_count = 0; for (size_t i = 0; i < m->workspaces.count; i++) { @@ -824,7 +819,9 @@ content(struct module *mod) assert(count <= 1); assert(count == 0 || ws != NULL); - if (ws != NULL && m->label != NULL) { + const struct ws_content *template = ws_content_for_name(m, "current"); + + if (ws != NULL && template != NULL) { struct tag_set tags = { .tags = (struct tag *[]){ tag_new_string(mod, "application", ws->window.application), @@ -833,7 +830,8 @@ content(struct module *mod) .count = 2, }; - particles[particle_count++] = m->label->instantiate(m->label, &tags); + particles[particle_count++] = template->content->instantiate( + template->content, &tags); tag_set_destroy(&tags); } @@ -850,7 +848,7 @@ struct i3_workspaces { static struct module * i3_new(struct i3_workspaces workspaces[], size_t workspace_count, - struct particle *label, int left_spacing, int right_spacing) + int left_spacing, int right_spacing) { struct private *m = calloc(1, sizeof(*m)); @@ -865,8 +863,6 @@ i3_new(struct i3_workspaces workspaces[], size_t workspace_count, m->ws_content.v[i].content = workspaces[i].content; } - m->label = label; - struct module *mod = module_common_new(); mod->private = m; mod->run = &run; @@ -888,37 +884,10 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) int right = spacing != NULL ? yml_value_as_int(spacing) : right_spacing != NULL ? yml_value_as_int(right_spacing) : 0; - const struct yml_node *ws_root_node = NULL; - struct particle *label = NULL; - - if (yml_is_dict(c)) { - ws_root_node = c; - } else { - for (struct yml_list_iter it = yml_list_iter(c); - it.node != NULL; - yml_list_next(&it)) - { - assert(yml_is_dict(it.node)); - assert(yml_dict_length(it.node) == 1); - - const struct yml_dict_iter item = yml_dict_iter(it.node); - const char *key = yml_value_as_string(item.key); - - if (strcmp(key, "workspaces") == 0) { - ws_root_node = item.value; - } else { - assert(label == NULL); - label = conf_to_particle(it.node, inherited); - } - } - } - - assert(yml_is_dict(ws_root_node)); - const size_t ws_count = yml_dict_length(ws_root_node); - struct i3_workspaces workspaces[ws_count]; + struct i3_workspaces workspaces[yml_dict_length(c)]; size_t idx = 0; - for (struct yml_dict_iter it = yml_dict_iter(ws_root_node); + for (struct yml_dict_iter it = yml_dict_iter(c); it.key != NULL; yml_dict_next(&it), idx++) { @@ -926,13 +895,18 @@ from_conf(const struct yml_node *node, struct conf_inherit inherited) workspaces[idx].content = conf_to_particle(it.value, inherited); } - return i3_new(workspaces, ws_count, label, left, right); + return i3_new(workspaces, yml_dict_length(c), left, right); } static bool -verify_content_dynlist(keychain_t *chain, const struct yml_node *node) +verify_content(keychain_t *chain, const struct yml_node *node) { - assert(yml_is_dict(node)); + if (!yml_is_dict(node)) { + LOG_ERR( + "%s: must be a dictionary of workspace-name: particle mappings", + conf_err_prefix(chain, node)); + return false; + } for (struct yml_dict_iter it = yml_dict_iter(node); it.key != NULL; @@ -954,60 +928,6 @@ verify_content_dynlist(keychain_t *chain, const struct yml_node *node) return true; } -static bool -verify_content(keychain_t *chain, const struct yml_node *node) -{ - if (!yml_is_dict(node) && !yml_is_list(node)) { - LOG_ERR( - "%s: must be a dictionary of workspace-name: particle mappings", - conf_err_prefix(chain, node)); - return false; - } - - if (yml_is_dict(node)) - return verify_content_dynlist(chain, node); - - if (yml_list_length(node) > 2) { - LOG_ERR("%s: must be a list of at most 2 entries", - conf_err_prefix(chain, node)); - return false; - } - - for (struct yml_list_iter it = yml_list_iter(node); - it.node != NULL; - yml_list_next(&it)) - { - if (!yml_is_dict(it.node) || yml_dict_length(it.node) != 1) { - LOG_ERR( - "%s: item must be a dictionary with a single item; " - "either a 'workspaces', or a particle name", - conf_err_prefix(chain, it.node)); - return false; - } - - const struct yml_dict_iter item = yml_dict_iter(it.node); - const char *key = yml_value_as_string(item.key); - if (key == NULL) { - LOG_ERR( - "%s: key must be a string; either 'workspaces', or a particle name", - conf_err_prefix(chain, item.key)); - return false; - } - - if (strcmp(key, "workspaces") == 0) { - if (!verify_content_dynlist(chain_push(chain, key), item.value)) - return false; - chain_pop(chain); - } else { - if (!conf_verify_particle(chain, it.node)) - return false; - } - - } - - return true; -} - static bool verify_conf(keychain_t *chain, const struct yml_node *node) { From d631e47a5e7fd6a19ba27c1c75c257f3138c0e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sat, 9 Feb 2019 21:55:08 +0100 Subject: [PATCH 08/10] module/i3: detect 'current' workspace while iterating workspaces --- modules/i3.c | 50 ++++++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index ff71629..91ffc82 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -763,6 +763,8 @@ content(struct module *mod) struct exposable *particles[m->workspaces.count + 1]; size_t particle_count = 0; + struct exposable *current = NULL; + for (size_t i = 0; i < m->workspaces.count; i++) { const struct workspace *ws = &m->workspaces.v[i]; const struct ws_content *template = NULL; @@ -776,11 +778,6 @@ content(struct module *mod) template = ws_content_for_name(m, ""); } - if (template == NULL) { - LOG_WARN("no ws template for %s, and no default template available", ws->name); - continue; - } - const char *state = ws->urgent ? "urgent" : ws->visible ? ws->focused ? "focused" : "unfocused" : @@ -800,41 +797,26 @@ content(struct module *mod) .count = 7, }; - particles[particle_count++] = template->content->instantiate( - template->content, &tags); - - tag_set_destroy(&tags); - } - - /* Find currently focused workspace */ - const struct workspace *ws = NULL; - size_t count = 0; - for (size_t i = 0; i < m->workspaces.count; i++) { - if (m->workspaces.v[i].focused) { - ws = &m->workspaces.v[i]; - count++; + if (ws->focused) { + const struct ws_content *cur = ws_content_for_name(m, "current"); + current = cur->content->instantiate(cur->content, &tags); } - } - assert(count <= 1); - assert(count == 0 || ws != NULL); + if (template == NULL) { + LOG_WARN( + "no ws template for %s, and no default template available", + ws->name); + } else { + particles[particle_count++] = template->content->instantiate( + template->content, &tags); + } - const struct ws_content *template = ws_content_for_name(m, "current"); - - if (ws != NULL && template != NULL) { - struct tag_set tags = { - .tags = (struct tag *[]){ - tag_new_string(mod, "application", ws->window.application), - tag_new_string(mod, "title", ws->window.title), - }, - .count = 2, - }; - - particles[particle_count++] = template->content->instantiate( - template->content, &tags); tag_set_destroy(&tags); } + if (current != NULL) + particles[particle_count++] = current; + mtx_unlock(&mod->lock); return dynlist_exposable_new( particles, particle_count, m->left_spacing, m->right_spacing); From 97ff63044f08cbda16c5d7bd6f67c8f9bea8e1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Sun, 10 Feb 2019 12:15:23 +0100 Subject: [PATCH 09/10] module/i3: cleanup --- modules/i3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/i3.c b/modules/i3.c index 91ffc82..14cb8b8 100644 --- a/modules/i3.c +++ b/modules/i3.c @@ -760,9 +760,8 @@ content(struct module *mod) mtx_lock(&mod->lock); - struct exposable *particles[m->workspaces.count + 1]; - size_t particle_count = 0; + struct exposable *particles[m->workspaces.count + 1]; struct exposable *current = NULL; for (size_t i = 0; i < m->workspaces.count; i++) { From 0e41c6560b33edbbc407ca0a5e3fb52c91bf1ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 12 Feb 2019 22:12:35 +0100 Subject: [PATCH 10/10] cmake: install header files --- CMakeLists.txt | 20 +++++++++++++++++++- bar/CMakeLists.txt | 2 ++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b94966d..ee33aa3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ if (ENABLE_X11) set_property(TARGET xcb-stuff PROPERTY POSITION_INDEPENDENT_CODE 1) endif () + install(FILES xcb.h DESTINATION include/f00bar) endif () if (ENABLE_WAYLAND) @@ -64,8 +65,9 @@ endif () add_subdirectory(bar) add_executable(f00bar - config.c config.h + color.h config-verify.c config-verify.h + config.c config.h decoration.h font.c font.h log.c log.h @@ -74,6 +76,7 @@ add_executable(f00bar particle.c particle.h plugin.c plugin.h tag.c tag.h + tllist.h yml.c yml.h ) @@ -90,6 +93,21 @@ set_property(TARGET f00bar PROPERTY BUILD_RPATH "\$ORIGIN/modules;\$ORIGIN/particles;\$ORIGIN/decorations") install(TARGETS f00bar DESTINATION bin) +install(FILES + color.h + config.h + config-verify.h + decoration.h + font.h + log.h + module.h + particle.h + tag.h + tllist.h + yml.h + + DESTINATION include/f00bar +) set(enabled_modules "") set(enabled_particles "") diff --git a/bar/CMakeLists.txt b/bar/CMakeLists.txt index 9ee2d33..f47de2d 100644 --- a/bar/CMakeLists.txt +++ b/bar/CMakeLists.txt @@ -64,3 +64,5 @@ target_link_libraries(bar $<$:bar-wayland> ${CMAKE_THREAD_LIBS_INIT} ) + +install(FILES bar.h DESTINATION include/f00bar/bar)