mirror of
https://codeberg.org/dnkl/yambar.git
synced 2025-04-23 12:35:41 +02:00
Merge branch 'i3-expose-window-title'
This commit is contained in:
commit
236511db88
1 changed files with 136 additions and 14 deletions
150
modules/i3.c
150
modules/i3.c
|
@ -7,8 +7,11 @@
|
||||||
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#if defined(ENABLE_X11)
|
#if defined(ENABLE_X11)
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
@ -45,6 +48,12 @@ struct workspace {
|
||||||
bool visible;
|
bool visible;
|
||||||
bool focused;
|
bool focused;
|
||||||
bool urgent;
|
bool urgent;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char *title;
|
||||||
|
char *application;
|
||||||
|
pid_t pid;
|
||||||
|
} window;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct private {
|
struct private {
|
||||||
|
@ -108,6 +117,7 @@ workspace_from_json(const struct json_object *json, struct workspace *ws)
|
||||||
.visible = json_object_get_boolean(visible),
|
.visible = json_object_get_boolean(visible),
|
||||||
.focused = json_object_get_boolean(focused),
|
.focused = json_object_get_boolean(focused),
|
||||||
.urgent = json_object_get_boolean(urgent),
|
.urgent = json_object_get_boolean(urgent),
|
||||||
|
.window = {.title = NULL, .pid = -1},
|
||||||
};
|
};
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -118,6 +128,8 @@ workspace_free(struct workspace ws)
|
||||||
{
|
{
|
||||||
free(ws.name);
|
free(ws.name);
|
||||||
free(ws.output);
|
free(ws.output);
|
||||||
|
free(ws.window.title);
|
||||||
|
free(ws.window.application);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -377,6 +389,96 @@ handle_workspace_event(struct private *m, const struct json_object *json)
|
||||||
return true;
|
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_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);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If PID has changed, update application name from /proc/<pid>/comm */
|
||||||
|
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);
|
||||||
|
|
||||||
|
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)
|
#if defined(ENABLE_X11)
|
||||||
static bool
|
static bool
|
||||||
get_socket_address_x11(struct sockaddr_un *addr)
|
get_socket_address_x11(struct sockaddr_un *addr)
|
||||||
|
@ -435,11 +537,14 @@ get_socket_address(struct sockaddr_un *addr)
|
||||||
|
|
||||||
const char *sway_sock = getenv("SWAYSOCK");
|
const char *sway_sock = getenv("SWAYSOCK");
|
||||||
if (sway_sock == NULL) {
|
if (sway_sock == NULL) {
|
||||||
|
sway_sock = getenv("I3SOCK");
|
||||||
|
if (sway_sock == NULL) {
|
||||||
#if defined(ENABLE_X11)
|
#if defined(ENABLE_X11)
|
||||||
return get_socket_address_x11(addr);
|
return get_socket_address_x11(addr);
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
strncpy(addr->sun_path, sway_sock, sizeof(addr->sun_path) - 1);
|
strncpy(addr->sun_path, sway_sock, sizeof(addr->sun_path) - 1);
|
||||||
|
@ -469,8 +574,8 @@ run(struct module *mod)
|
||||||
}
|
}
|
||||||
|
|
||||||
send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_VERSION, NULL);
|
send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_VERSION, NULL);
|
||||||
|
send_pkg(sock, I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[\"workspace\", \"window\"]");
|
||||||
send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
|
send_pkg(sock, I3_IPC_MESSAGE_TYPE_GET_WORKSPACES, NULL);
|
||||||
send_pkg(sock, I3_IPC_MESSAGE_TYPE_SUBSCRIBE, "[\"workspace\"]");
|
|
||||||
|
|
||||||
/* Initial reply typically requires a couple of KB. But we often
|
/* Initial reply typically requires a couple of KB. But we often
|
||||||
* need more later. For example, switching workspaces can result
|
* need more later. For example, switching workspaces can result
|
||||||
|
@ -580,9 +685,13 @@ run(struct module *mod)
|
||||||
need_bar_refresh = true;
|
need_bar_refresh = true;
|
||||||
break;
|
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_OUTPUT:
|
||||||
case I3_IPC_EVENT_MODE:
|
case I3_IPC_EVENT_MODE:
|
||||||
case I3_IPC_EVENT_WINDOW:
|
|
||||||
case I3_IPC_EVENT_BARCONFIG_UPDATE:
|
case I3_IPC_EVENT_BARCONFIG_UPDATE:
|
||||||
case I3_IPC_EVENT_BINDING:
|
case I3_IPC_EVENT_BINDING:
|
||||||
case I3_IPC_EVENT_SHUTDOWN:
|
case I3_IPC_EVENT_SHUTDOWN:
|
||||||
|
@ -651,9 +760,10 @@ content(struct module *mod)
|
||||||
|
|
||||||
mtx_lock(&mod->lock);
|
mtx_lock(&mod->lock);
|
||||||
|
|
||||||
struct exposable *particles[m->workspaces.count];
|
|
||||||
|
|
||||||
size_t particle_count = 0;
|
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++) {
|
for (size_t i = 0; i < m->workspaces.count; i++) {
|
||||||
const struct workspace *ws = &m->workspaces.v[i];
|
const struct workspace *ws = &m->workspaces.v[i];
|
||||||
const struct ws_content *template = NULL;
|
const struct ws_content *template = NULL;
|
||||||
|
@ -667,11 +777,6 @@ content(struct module *mod)
|
||||||
template = ws_content_for_name(m, "");
|
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 =
|
const char *state =
|
||||||
ws->urgent ? "urgent" :
|
ws->urgent ? "urgent" :
|
||||||
ws->visible ? ws->focused ? "focused" : "unfocused" :
|
ws->visible ? ws->focused ? "focused" : "unfocused" :
|
||||||
|
@ -684,16 +789,33 @@ content(struct module *mod)
|
||||||
tag_new_bool(mod, "focused", ws->focused),
|
tag_new_bool(mod, "focused", ws->focused),
|
||||||
tag_new_bool(mod, "urgent", ws->urgent),
|
tag_new_bool(mod, "urgent", ws->urgent),
|
||||||
tag_new_string(mod, "state", state),
|
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(
|
if (ws->focused) {
|
||||||
template->content, &tags);
|
const struct ws_content *cur = ws_content_for_name(m, "current");
|
||||||
|
current = cur->content->instantiate(cur->content, &tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
tag_set_destroy(&tags);
|
tag_set_destroy(&tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (current != NULL)
|
||||||
|
particles[particle_count++] = current;
|
||||||
|
|
||||||
mtx_unlock(&mod->lock);
|
mtx_unlock(&mod->lock);
|
||||||
return dynlist_exposable_new(
|
return dynlist_exposable_new(
|
||||||
particles, particle_count, m->left_spacing, m->right_spacing);
|
particles, particle_count, m->left_spacing, m->right_spacing);
|
||||||
|
|
Loading…
Add table
Reference in a new issue