diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 7617f49..8e17b2c 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -39,6 +39,8 @@ * window_move records WM-assigned x,y in the view struct. * Phase 56: prop_set/get_wm_state persist WM state (workspace, miniaturized, * shaded, etc.) in the view struct so wWindowGetSavedState works correctly. + * Phase 57: icccm_set/get/free_command store WM_COMMAND in the view struct; + * misc.c getCommandForWindow uses the vtable on the Wayland path. */ #ifdef HAVE_CONFIG_H @@ -92,6 +94,8 @@ struct wl_toplevel_view { int x, y; /* Phase 55: WM-assigned position */ long *wm_state; /* Phase 56: saved WM state or NULL */ int wm_state_n; /* Phase 56: element count */ + char **wm_command; /* Phase 57: WM_COMMAND argv or NULL */ + int wm_command_n; /* Phase 57: argument count */ struct wl_list link; /* wl_state.toplevel_list */ }; @@ -281,6 +285,12 @@ handle_toplevel_destroy(struct wl_listener *listener, void *data) wl_list_remove(&view->link); wl_state.managed_surface_count--; if (view->wm_state) wfree(view->wm_state); /* Phase 56 */ + if (view->wm_command) { /* Phase 57 */ + int ci; + for (ci = 0; ci < view->wm_command_n; ci++) + wfree(view->wm_command[ci]); + wfree(view->wm_command); + } wfree(view); } @@ -1064,9 +1074,50 @@ wl_coords_translate(WNativeWindow src, WNativeWindow dst, static void wl_icccm_set_wm_hints(WNativeWindow win, const WWMHints *hints) { (void)win; (void)hints; } static void wl_icccm_set_class_hint(WNativeWindow win, const char *wm_class, const char *wm_instance) { (void)win; (void)wm_class; (void)wm_instance; } static void wl_icccm_set_class_hint_if_absent(WNativeWindow win, const char *wm_class, const char *wm_instance) { (void)win; (void)wm_class; (void)wm_instance; } -static void wl_icccm_set_command(WNativeWindow win, char **argv, int argc) { (void)win; (void)argv; (void)argc; } -static int wl_icccm_get_command(WNativeWindow win, char ***argv_out, int *argc_out) { (void)win; *argv_out = NULL; *argc_out = 0; return 0; } -static void wl_icccm_free_command(char **argv) { (void)argv; } +static void +wl_icccm_set_command(WNativeWindow win, char **argv, int argc) +{ + /* Phase 57: store WM_COMMAND in the view struct. */ + struct wl_toplevel_view *v = wl_find_view_by_id(win); + int i; + if (!v || !argv || argc <= 0) return; + /* free previous command if any */ + if (v->wm_command) { + for (i = 0; i < v->wm_command_n; i++) wfree(v->wm_command[i]); + wfree(v->wm_command); + } + v->wm_command = wmalloc((size_t)argc * sizeof(char *)); + for (i = 0; i < argc; i++) + v->wm_command[i] = wstrdup(argv[i] ? argv[i] : ""); + v->wm_command_n = argc; +} + +static int +wl_icccm_get_command(WNativeWindow win, char ***argv_out, int *argc_out) +{ + /* Phase 57: return a NULL-terminated copy of the stored WM_COMMAND. + * Caller frees with wl_icccm_free_command. */ + struct wl_toplevel_view *v = wl_find_view_by_id(win); + int i; + if (!v || !v->wm_command) { *argv_out = NULL; *argc_out = 0; return 0; } + /* Allocate n+1 entries (NULL-terminated for free_command iteration). */ + *argv_out = wmalloc((size_t)(v->wm_command_n + 1) * sizeof(char *)); + for (i = 0; i < v->wm_command_n; i++) + (*argv_out)[i] = wstrdup(v->wm_command[i]); + (*argv_out)[v->wm_command_n] = NULL; + *argc_out = v->wm_command_n; + return 1; +} + +static void +wl_icccm_free_command(char **argv) +{ + /* Phase 57: free NULL-terminated argv returned by wl_icccm_get_command. */ + int i; + if (!argv) return; + for (i = 0; argv[i] != NULL; i++) wfree(argv[i]); + wfree(argv); +} /* ------------------------------------------------------------------ */ /* Fake leader */ diff --git a/src/misc.c b/src/misc.c index b6fa113..ec91158 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1072,7 +1072,22 @@ static char *getCommandForWindow(Window win, int elements) char **argv, *command = NULL; int argc; - if (!dpy) return NULL; /* Wayland: no X11 WM_COMMAND property */ + if (!dpy) { + /* Wayland: read WM_COMMAND from the vtable-backed store. */ + if (!wm_backend->icccm_get_command((WNativeWindow)win, &argv, &argc)) + return NULL; + if (argc > 0 && argv != NULL) { + if (elements == 0) + elements = argc; + command = wtokenjoin(argv, WMIN(argc, elements)); + if (command[0] == 0) { + wfree(command); + command = NULL; + } + } + wm_backend->icccm_free_command(argv); + return command; + } if (XGetCommand(dpy, win, &argv, &argc)) { if (argc > 0 && argv != NULL) {