A native WM_DELETE_WINDOW reproduction completed the frontend drain and then failed with "window.destroy not allowed". All three windows lacked the destroy permission used by Tauri's onCloseRequested wrapper. Removing the listener had previously let a second click bypass that denied IPC; retaining the listener made every click fail. The frontend was not stuck waiting on its own listener. Grant window destruction to the three configured application windows. Keep the existing frontend drains, early peer cancellation, and final runtime/task joins. Test the application's actual generated RuntimeAuthority, including expanded plugin defaults, instead of assuming a mocked successful destroy proves access. Explicitly include generated capabilities and ACL manifests in the context constructor's rustc dependencies. The configured compiler cache reused the old library after a permission-only edit because Tauri's macro reads these files without recording compiler dependencies. A remove/restore native probe now rebuilds with the correct permission in both directions. Document the complete ownership chain and failure evidence. Add a PID-checked X11 WM_DELETE_WINDOW helper for repeatable close-button probes without killing the process or bypassing the frontend boundary. Test Plan: - Native baseline: destroy denied and process remained alive after one request. - Resolved-ACL regression failed before the permission fix and passes afterward. - Native main/companion close probes: one request per window; normal process exit. - Permission-only rebuild with compiler cache: normal exit in 197 ms. - Production executable: normal exit in 43 ms; QUIC port released and rebound. - just test: 797 passed on unchanged rerun after one initial subprocess fixture startup-marker timeout, before that test exercised cancellation. - just frontend-test: 99 passed. - just fmt, just clippy, just build, and git diff --cached --check: passed. - Native helper compiled with -Wall -Wextra -Werror. - Native probes ran on Linux X11/XWayland; Windows/macOS were not measured.
75 lines
2.5 KiB
C
75 lines
2.5 KiB
C
/* Send the close-button protocol to one PID-checked X11 window. */
|
|
#include <X11/Xatom.h>
|
|
#include <X11/Xlib.h>
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
static unsigned long parse_id(const char *text) {
|
|
char *end;
|
|
errno = 0;
|
|
unsigned long value = strtoul(text, &end, 0);
|
|
if (errno || *end || end == text || !value || *text == '-') {
|
|
fprintf(stderr, "Invalid positive window ID or PID: %s\n", text);
|
|
exit(2);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
if (argc != 3) {
|
|
fprintf(stderr, "Usage: %s WINDOW_ID EXPECTED_PID\n", argv[0]);
|
|
return 2;
|
|
}
|
|
Window window = parse_id(argv[1]);
|
|
unsigned long expected_pid = parse_id(argv[2]);
|
|
Display *display = XOpenDisplay(NULL);
|
|
if (!display) {
|
|
fprintf(stderr, "Cannot open DISPLAY\n");
|
|
return 1;
|
|
}
|
|
|
|
Atom type;
|
|
int format;
|
|
unsigned long count, remaining;
|
|
unsigned char *data = NULL;
|
|
int result = XGetWindowProperty(display, window,
|
|
XInternAtom(display, "_NET_WM_PID", False), 0, 1, False, XA_CARDINAL,
|
|
&type, &format, &count, &remaining, &data);
|
|
int matches = result == Success && type == XA_CARDINAL && format == 32 &&
|
|
count == 1 && data && *(unsigned long *)data == expected_pid;
|
|
if (data) XFree(data);
|
|
if (!matches) {
|
|
fprintf(stderr, "Window does not belong to expected PID %lu\n", expected_pid);
|
|
XCloseDisplay(display);
|
|
return 1;
|
|
}
|
|
|
|
Atom protocol = XInternAtom(display, "WM_DELETE_WINDOW", False);
|
|
Atom *protocols = NULL;
|
|
int protocol_count = 0, supports_close = 0;
|
|
if (XGetWMProtocols(display, window, &protocols, &protocol_count)) {
|
|
for (int i = 0; i < protocol_count; i++)
|
|
supports_close |= protocols[i] == protocol;
|
|
XFree(protocols);
|
|
}
|
|
if (!supports_close) {
|
|
fprintf(stderr, "Window does not advertise WM_DELETE_WINDOW\n");
|
|
XCloseDisplay(display);
|
|
return 1;
|
|
}
|
|
|
|
XEvent event = {0};
|
|
event.xclient.type = ClientMessage;
|
|
event.xclient.window = window;
|
|
event.xclient.message_type = XInternAtom(display, "WM_PROTOCOLS", False);
|
|
event.xclient.format = 32;
|
|
event.xclient.data.l[0] = protocol;
|
|
event.xclient.data.l[1] = CurrentTime;
|
|
int sent = XSendEvent(display, window, False, NoEventMask, &event);
|
|
XSync(display, False);
|
|
XCloseDisplay(display);
|
|
printf("WM_DELETE_WINDOW sent=%d window=%lu pid=%lu\n", sent, window, expected_pid);
|
|
return sent ? 0 : 1;
|
|
}
|