From 0ca2527af33fb2ffb676edc799e60af0b752c70f Mon Sep 17 00:00:00 2001 From: Gal Buki Date: Thu, 5 Mar 2026 21:21:47 +0200 Subject: [PATCH] mmsg-all-windows watch-all-windows --- mmsg/mmsg.c | 111 +++++++++++++++++++++++++++++- protocols/dwl-ipc-unstable-v2.xml | 26 +++++++ src/ext-protocol/dwl-ipc.h | 40 ++++++++++- 3 files changed, 174 insertions(+), 3 deletions(-) diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index 4e0e1d8c..fb4e6642 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -42,6 +42,7 @@ static int32_t eflag; static int32_t kflag; static int32_t bflag; static int32_t Aflag; +static int32_t aflag; static uint32_t occ, seltags, total_clients, urg; @@ -64,6 +65,17 @@ struct output { }; static DYNARR_DEF(struct output) outputs; +struct window { + int32_t x, y, width, height; + char *output; + char *appid; + char *title; +}; +static DYNARR_DEF(struct window) windows; + +static int32_t completed_outputs = 0; +static int32_t total_outputs = 0; + static struct wl_display *display; static struct zdwl_ipc_manager_v2 *dwl_ipc_manager; @@ -310,6 +322,72 @@ static void dwl_ipc_output_floating(void *data, printf("floating %u\n", is_floating); } +static void dwl_ipc_output_window(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + const char *output, + int32_t x, int32_t y, int32_t width, + int32_t height, const char *appid, + const char *title) { + char *out_str, *appid_str, *title_str; + + if (!aflag) + return; + + if (data && strcmp(data, output) != 0) + return; + + out_str = strdup(output); + appid_str = strdup(appid ? appid : ""); + title_str = strdup(title ? title : ""); + + if (!out_str || !appid_str || !title_str) { + free(out_str); + free(appid_str); + free(title_str); + return; + } + + struct window w = { + .x = x, + .y = y, + .width = width, + .height = height, + .output = out_str, + .appid = appid_str, + .title = title_str + }; + DYNARR_PUSH(&windows, w); +} + +static void dwl_ipc_output_windows_end(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output) { + if (!aflag) + return; + + completed_outputs++; + + if (completed_outputs >= total_outputs) { + for (size_t i = 0; i < windows.len; i++) { + struct window *w = &windows.arr[i]; + printf("%s %d,%d %dx%d \"%s\" \"%s\"\n", + w->output, w->x, w->y, w->width, w->height, + w->appid, w->title); + free(w->output); + free(w->appid); + free(w->title); + } + DYNARR_FINI(&windows); + + if (!(mode & WATCH)) + exit(0); + + completed_outputs = 0; + windows.arr = NULL; + windows.len = windows.cap = 0; + DYNARR_INIT(&windows); + } +} + static void dwl_ipc_output_frame(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output) { if (mode & SET) { @@ -407,6 +485,11 @@ static void dwl_ipc_output_frame(void *data, } } fflush(stdout); + + if ((mode & WATCH) && aflag) { + zdwl_ipc_output_v2_get_windows(dwl_ipc_output); + wl_display_flush(display); + } } static const struct zdwl_ipc_output_v2_listener dwl_ipc_output_listener = { @@ -427,6 +510,8 @@ 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 = dwl_ipc_output_window, + .windows_end = dwl_ipc_output_windows_end, .frame = dwl_ipc_output_frame, }; @@ -447,6 +532,12 @@ 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 (aflag) { + total_outputs++; + zdwl_ipc_output_v2_get_windows(dwl_ipc_output); + wl_display_flush(display); + } } static const struct wl_output_listener output_listener = { @@ -506,7 +597,7 @@ static void usage(void) { "\tmmsg [-OTLq]\n" "\tmmsg [-o ] -s [-t ] [-l ] [-c ] [-d " ",,,,,]\n" - "\tmmsg [-o ] (-g | -w) [-OotlcvmfxekbA]\n" + "\tmmsg [-o ] (-g | -w) [-OotlcvmfxekbAa]\n" "\n" "OPERATION MODES:\n" "\t-g Get values (tags, layout, focused client)\n" @@ -534,6 +625,7 @@ static void usage(void) { "\t-k Get current keyboard layout\n" "\t-b Get current keybind mode\n" "\t-A Get scale factor of monitor\n" + "\t-a Get all visible windows\n" "\n" "SET OPTIONS (used with -s):\n" "\t-o Select output (monitor)\n" @@ -788,6 +880,12 @@ int32_t main(int32_t argc, char *argv[]) { usage(); mode |= GET; break; + case 'a': + aflag = 1; + if (mode == SET) + usage(); + mode |= GET; + break; default: fprintf(stderr, "bad option %c\n", ARGC()); usage(); @@ -795,10 +893,15 @@ int32_t main(int32_t argc, char *argv[]) { ARGEND if (mode == NONE) usage(); + if (aflag) { + DYNARR_INIT(&windows); + completed_outputs = 0; + total_outputs = 0; + } if (mode & GET && !output_name && !(oflag || tflag || lflag || Oflag || Tflag || Lflag || cflag || vflag || mflag || fflag || xflag || eflag || kflag || bflag || - Aflag || dflag)) + Aflag || dflag || aflag)) oflag = tflag = lflag = cflag = vflag = mflag = fflag = xflag = eflag = kflag = bflag = Aflag = 1; @@ -817,6 +920,10 @@ int32_t main(int32_t argc, char *argv[]) { wl_display_roundtrip(display); + if (aflag) { + wl_display_roundtrip(display); + } + if (mode == WATCH) while (wl_display_dispatch(display) != -1) ; diff --git a/protocols/dwl-ipc-unstable-v2.xml b/protocols/dwl-ipc-unstable-v2.xml index 5852107e..cdadb918 100644 --- a/protocols/dwl-ipc-unstable-v2.xml +++ b/protocols/dwl-ipc-unstable-v2.xml @@ -177,6 +177,32 @@ I would probably just submit raphi's patchset but I don't think that would be po + + + Requests a list of all visible windows on this output. + The compositor will reply with window events followed by windows_end. + + + + + + Information about a visible window. + + + + + + + + + + + + + Sent after all window events to indicate the list is complete. + + + diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index ab0bdb8d..618003d9 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_get_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,9 @@ 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, + .get_windows = dwl_ipc_output_get_windows, +}; void dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) { @@ -307,3 +311,37 @@ void dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource) { wl_resource_destroy(resource); } + +void dwl_ipc_output_get_windows(struct wl_client *client, + struct wl_resource *resource) { + DwlIpcOutput *ipc_output; + Monitor *monitor; + Client *c; + const char *appid, *title, *output_name; + + ipc_output = wl_resource_get_user_data(resource); + if (!ipc_output) + return; + + monitor = ipc_output->mon; + output_name = monitor->wlr_output->name; + + wl_list_for_each(c, &clients, link) { + if (!VISIBLEON(c, monitor)) + continue; + + appid = client_get_appid(c); + title = client_get_title(c); + + zdwl_ipc_output_v2_send_window(resource, + output_name, + c->geom.x, + c->geom.y, + c->geom.width, + c->geom.height, + appid ? appid : broken, + title ? title : broken); + } + + zdwl_ipc_output_v2_send_windows_end(resource); +}