/* xclass: WM_CLASS set-then-delete probe. * * Maps a titled X11 window with NO class, then sets WM_CLASS, then deletes * it: the delete emits set_class with class==NULL while the title is set. * The compositor must mirror "" (not raw NULL) onto the taskbar handles -- * passing NULL into the foreign-toplevel set_app_id/update_state calls * segfaults inside wlroots' strdup (regression test for that crash). * * usage: xclass (total runtime ~= 4 + max(hold-4, 0)) */ #define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include int main(int argc, char **argv) { int hold = argc > 1 ? atoi(argv[1]) : 6; Display *d = XOpenDisplay(NULL); if (!d) { fprintf(stderr, "xclass: cannot open display\n"); return 1; } int scr = DefaultScreen(d); Window w = XCreateSimpleWindow(d, RootWindow(d, scr), 0, 0, 400, 300, 0, BlackPixel(d, scr), 0x804020UL); XStoreName(d, w, "xclass-frame"); pid_t pid = getpid(); Atom apid = XInternAtom(d, "_NET_WM_PID", False); XChangeProperty(d, w, apid, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1); /* NOTE: no WM_CLASS yet (class == NULL server-side). */ XMapWindow(d, w); XFlush(d); fprintf(stderr, "[xclass] mapped, no class\n"); sleep(2); XClassHint *ch = XAllocClassHint(); ch->res_name = "xclass-probe"; ch->res_class = "XClassProbe"; XSetClassHint(d, w, ch); XFree(ch); XFlush(d); fprintf(stderr, "[xclass] class set\n"); sleep(2); Atom wmclass = XInternAtom(d, "WM_CLASS", False); XDeleteProperty(d, w, wmclass); XFlush(d); fprintf(stderr, "[xclass] class deleted (NULL)\n"); sleep(hold > 4 ? (unsigned)(hold - 4) : 0); return 0; }