From 586b07cb98e3c4cacac781ccd6c27b1e8134a369 Mon Sep 17 00:00:00 2001 From: Andrej Novikov Date: Tue, 16 Dec 2025 17:04:40 +0200 Subject: [PATCH] feat: mmsg -W flag to list all windows with details Extends IPC protocol with window_info event and list_windows request to query all windows instead of just the focused one. The new -W flag outputs title, appid, geometry, floating/fullscreen state, and tags for each window. Usage: mmsg -g -W --- mmsg/mmsg.c | 28 +++++++++++++++++++++++++-- protocols/dwl-ipc-unstable-v2.xml | 21 ++++++++++++++++++++ src/ext-protocol/dwl-ipc.h | 32 ++++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index 2bbe870e..daece092 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -42,6 +42,7 @@ static int eflag; static int kflag; static int bflag; static int Aflag; +static int Wflag; static uint32_t occ, seltags, total_clients, urg; @@ -288,6 +289,19 @@ static void dwl_ipc_output_keymode(void *data, printf("keymode %s\n", keymode); } +static void dwl_ipc_output_window_info(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + const char *title, const char *appid, + int32_t x, int32_t y, + int32_t width, int32_t height, + uint32_t floating, uint32_t fullscreen, + uint32_t tags) { + if (!Wflag) + return; + printf("window: title=\"%s\" appid=\"%s\" x=%d y=%d width=%d height=%d floating=%u fullscreen=%u tags=%u\n", + title, appid, x, y, width, height, floating, fullscreen, tags); +} + static void dwl_ipc_output_fullscreen(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output, uint32_t is_fullscreen) { @@ -427,6 +441,7 @@ static const struct zdwl_ipc_output_v2_listener dwl_ipc_output_listener = { .kb_layout = dwl_ipc_output_kb_layout, .keymode = dwl_ipc_output_keymode, .scalefactor = dwl_ipc_output_scalefactor, + .window_info = dwl_ipc_output_window_info, .frame = dwl_ipc_output_frame, }; @@ -447,6 +462,9 @@ static void wl_output_name(void *data, struct wl_output *output, zdwl_ipc_manager_v2_get_output(dwl_ipc_manager, output); zdwl_ipc_output_v2_add_listener(dwl_ipc_output, &dwl_ipc_output_listener, output_name ? NULL : strdup(name)); + if (Wflag && mode & GET) { + zdwl_ipc_output_v2_list_windows(dwl_ipc_output); + } } static const struct wl_output_listener output_listener = { @@ -504,7 +522,7 @@ static void usage(void) { "\t%s [-OTLq]\n" "\t%s [-o ] -s [-t ] [-l ] [-c ] [-d " ",,,,,]\n" - "\t%s [-o ] (-g | -w) [-OotlcvmfxekbA]\n", + "\t%s [-o ] (-g | -w) [-OotlcvmfxekbAW]\n", argv0, argv0, argv0); exit(2); } @@ -752,6 +770,12 @@ int main(int argc, char *argv[]) { usage(); mode |= GET; break; + case 'W': + Wflag = 1; + if (mode == SET) + usage(); + mode |= GET; + break; default: fprintf(stderr, "bad option %c\n", ARGC()); usage(); @@ -762,7 +786,7 @@ int main(int argc, char *argv[]) { if (mode & GET && !output_name && !(oflag || tflag || lflag || Oflag || Tflag || Lflag || cflag || vflag || mflag || fflag || xflag || eflag || kflag || bflag || - Aflag || dflag)) + Aflag || Wflag || dflag)) oflag = tflag = lflag = cflag = vflag = mflag = fflag = xflag = eflag = kflag = bflag = Aflag = 1; diff --git a/protocols/dwl-ipc-unstable-v2.xml b/protocols/dwl-ipc-unstable-v2.xml index 5852107e..6a2a2a14 100644 --- a/protocols/dwl-ipc-unstable-v2.xml +++ b/protocols/dwl-ipc-unstable-v2.xml @@ -248,6 +248,27 @@ I would probably just submit raphi's patchset but I don't think that would be po + + + Sent for each window when listing all windows. + + + + + + + + + + + + + + + Request the compositor to send window_info events for all windows. + + + diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index eda3f49f..2e5e64ba 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -28,6 +28,8 @@ static void dwl_ipc_output_dispatch(struct wl_client *client, const char *dispatch, const char *arg1, const char *arg2, const char *arg3, const char *arg4, const char *arg5); +static void dwl_ipc_output_list_windows(struct wl_client *client, + struct wl_resource *resource); static void dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource); @@ -41,7 +43,8 @@ static struct zdwl_ipc_output_v2_interface dwl_output_implementation = { .quit = dwl_ipc_output_quit, .dispatch = dwl_ipc_output_dispatch, .set_layout = dwl_ipc_output_set_layout, - .set_client_tags = dwl_ipc_output_set_client_tags}; + .set_client_tags = dwl_ipc_output_set_client_tags, + .list_windows = dwl_ipc_output_list_windows}; void dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { @@ -303,6 +306,33 @@ void dwl_ipc_output_dispatch(struct wl_client *client, free(arg.v3); } +void dwl_ipc_output_list_windows(struct wl_client *client, + struct wl_resource *resource) { + Client *c = NULL; + const char *title, *appid; + + wl_list_for_each(c, &clients, link) { + if (!client_surface(c)->mapped || client_is_unmanaged(c)) + continue; + + title = client_get_title(c); + appid = client_get_appid(c); + + zdwl_ipc_output_v2_send_window_info( + resource, + title ? title : "", + appid ? appid : "", + c->geom.x, + c->geom.y, + c->geom.width, + c->geom.height, + c->isfloating, + c->isfullscreen, + c->tags); + } + wl_resource_post_event(resource, ZDWL_IPC_OUTPUT_V2_FRAME); +} + void dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource);