Index: safekill.c ================================================================== --- safekill.c +++ safekill.c @@ -5,10 +5,11 @@ * a utility to make it harder to accidentally nuke * important windows on i3wm or whatever. */ #include #include +#include #include #include #include #include typedef enum { false, true } bool; @@ -21,12 +22,38 @@ if (str[1] == 'V' && str[2] == '}') return str; else { ++str; goto start; } } } + +Display *display; + +void killwin(Window w) { + XEvent ev; + long mask = SubstructureRedirectMask | SubstructureNotifyMask; + ev.xclient.type = ClientMessage; + ev.xclient.serial = 0; + ev.xclient.send_event = True; + ev.xclient.message_type = XInternAtom(display, "_NET_CLOSE_WINDOW", False); + ev.xclient.window = w; + ev.xclient.format = 32; + + if(!XSendEvent(display, DefaultRootWindow(display), False, mask, &ev)) { + char* fallback = getenv("k_safekill_fallback"); + bool nofb = (*fallback == '0' && fallback[1] == 0); + + fprintf(stderr,"\x1b[1mwarning:\x1b[m cannot send _NET_CLOSE_WINDOW event to root window; is your window manager okay?"); + + if (nofb) { + fprintf(stderr,"\n"); + } else { + fprintf(stderr," falling back to XDestroyWindow, but this may wreck your shit - lots of multi-win apps do *not* like it.\n"); + XDestroyWindow(display,w); + } + } +} int main(const int argc, const char** argv) { - Display *display; Window focus; int revert; bool active; enum { vitalize, devitalize, hardkill, softkill } op; @@ -66,11 +93,11 @@ if (temp == 0) goto usage; focus = (Window)temp; } if(op == hardkill) { - XDestroyWindow(display,focus); + killwin(focus); XSync(display,false); return 0; } XClassHint xclh; @@ -82,11 +109,11 @@ else if (op == devitalize) { strcpy(v, v+3); XSetClassHint(display,focus,&xclh); XSync(display,false); } else if (op == softkill) { - printf("softkill forbidden\n"); + fprintf(stderr, "softkill forbidden\n"); return 1; // ACCESS DENIED } } else { if (op == vitalize) { size_t sz=strlen(xclh.res_class); // TODO: remove double-walk @@ -98,17 +125,17 @@ XSetClassHint(display,focus,&xclh); XSync(display,false); } else if (op == devitalize) return 0; else if (op == softkill) { // ice that motherfucker - XDestroyWindow(display,focus); + killwin(focus); XSync(display,false); return 3; } } } else { - printf("\x1b[1merror:\x1b[m bad window\n"); + fprintf(stderr,"\x1b[1merror:\x1b[m bad window\n"); goto usage; } return 0; @@ -116,12 +143,12 @@ #define info "\x1b[34m-- " #define param "\x1b[32m" #define eol "\x1b[m\n" #define bold "\x1b[1m" #define nl " " - printf(bold "usage:\x1b[0m %s " " " info "kill active window if non-vital" eol + fprintf(stderr, bold "usage:\x1b[0m %s " " " info "kill active window if non-vital" eol nl "%1$s -v " param "[id] " info "make [id] or active window vital" eol nl "%1$s -c " param "[id] " info "clear vital flag on [id] or active window" eol nl "%1$s -q " param "[id] " info "'emergency' kill w/o reference to vital flag" eol, argv[0]); return 1; }