Differences From
Artifact [d7a13fcb31]:
- File
safekill.c
— part of check-in
[12c34052e4]
at
2019-04-12 00:49:13
on branch trunk
— make safekill use _NET_CLOSE_WINDOW extension where available instead of XDestroyWindow, which is super unfriendly and frequently crashes or hard-locks multi-window applications. XDestroyWindow is still available as a fallback if the extension fails; `export k_safekill_fallback=0` to stop this
(user:
lexi,
size: 4139)
[annotate]
[blame]
[check-ins using]
3 3 * $ cc -Ofast safekill.c -lX11 -lc -osafekill
4 4 * © affero general public license
5 5 * a utility to make it harder to accidentally nuke
6 6 * important windows on i3wm or whatever. */
7 7
8 8 #include <X11/Xlib.h>
9 9 #include <X11/Xutil.h>
10 +#include <X11/Xatom.h>
10 11 #include <stdio.h>
11 12 #include <stdlib.h>
12 13 #include <string.h>
13 14 #include <errno.h>
14 15 typedef enum { false, true } bool;
15 16 char* isvital(char* str) {
16 17 start: // tail calls for dipshits
................................................................................
19 20 ++str; goto start;
20 21 } else {
21 22 if (str[1] == 'V' && str[2] == '}')
22 23 return str;
23 24 else { ++str; goto start; }
24 25 }
25 26 }
27 +
28 +Display *display;
29 +
30 +void killwin(Window w) {
31 + XEvent ev;
32 + long mask = SubstructureRedirectMask | SubstructureNotifyMask;
33 + ev.xclient.type = ClientMessage;
34 + ev.xclient.serial = 0;
35 + ev.xclient.send_event = True;
36 + ev.xclient.message_type = XInternAtom(display, "_NET_CLOSE_WINDOW", False);
37 + ev.xclient.window = w;
38 + ev.xclient.format = 32;
39 +
40 + if(!XSendEvent(display, DefaultRootWindow(display), False, mask, &ev)) {
41 + char* fallback = getenv("k_safekill_fallback");
42 + bool nofb = (*fallback == '0' && fallback[1] == 0);
43 +
44 + fprintf(stderr,"\x1b[1mwarning:\x1b[m cannot send _NET_CLOSE_WINDOW event to root window; is your window manager okay?");
45 +
46 + if (nofb) {
47 + fprintf(stderr,"\n");
48 + } else {
49 + fprintf(stderr," falling back to XDestroyWindow, but this may wreck your shit - lots of multi-win apps do *not* like it.\n");
50 + XDestroyWindow(display,w);
51 + }
52 + }
53 +}
26 54 int main(const int argc, const char** argv) {
27 - Display *display;
28 55 Window focus;
29 56 int revert;
30 57
31 58 bool active;
32 59 enum { vitalize, devitalize, hardkill, softkill } op;
33 60
34 61 if (argc > 3) goto usage;
................................................................................
64 91 unsigned long temp = strtoul(argv[2], NULL, 0);
65 92 if (errno == EINVAL || errno == ERANGE) goto usage;
66 93 if (temp == 0) goto usage;
67 94 focus = (Window)temp;
68 95 }
69 96
70 97 if(op == hardkill) {
71 - XDestroyWindow(display,focus);
98 + killwin(focus);
72 99 XSync(display,false);
73 100 return 0;
74 101 }
75 102
76 103 XClassHint xclh;
77 104 if (XGetClassHint(display,focus,&xclh)) {
78 105 char* v;
................................................................................
80 107
81 108 if (op == vitalize) return 0; // nothing need be done
82 109 else if (op == devitalize) {
83 110 strcpy(v, v+3);
84 111 XSetClassHint(display,focus,&xclh);
85 112 XSync(display,false);
86 113 } else if (op == softkill) {
87 - printf("softkill forbidden\n");
114 + fprintf(stderr, "softkill forbidden\n");
88 115 return 1; // ACCESS DENIED
89 116 }
90 117 } else {
91 118 if (op == vitalize) {
92 119 size_t sz=strlen(xclh.res_class); // TODO: remove double-walk
93 120 xclh.res_class=realloc(xclh.res_class, sz+4);
94 121 xclh.res_class[sz]='{';
................................................................................
96 123 xclh.res_class[sz+2]='}';
97 124 xclh.res_class[sz+3]=0;
98 125 XSetClassHint(display,focus,&xclh);
99 126 XSync(display,false);
100 127 } else if (op == devitalize) return 0;
101 128 else if (op == softkill) {
102 129 // ice that motherfucker
103 - XDestroyWindow(display,focus);
130 + killwin(focus);
104 131 XSync(display,false);
105 132 return 3;
106 133 }
107 134 }
108 135 } else {
109 - printf("\x1b[1merror:\x1b[m bad window\n");
136 + fprintf(stderr,"\x1b[1merror:\x1b[m bad window\n");
110 137 goto usage;
111 138 }
112 139
113 140 return 0;
114 141
115 142 usage:
116 143 #define info "\x1b[34m-- "
117 144 #define param "\x1b[32m"
118 145 #define eol "\x1b[m\n"
119 146 #define bold "\x1b[1m"
120 147 #define nl " "
121 - printf(bold "usage:\x1b[0m %s " " " info "kill active window if non-vital" eol
148 + fprintf(stderr, bold "usage:\x1b[0m %s " " " info "kill active window if non-vital" eol
122 149 nl "%1$s -v " param "[id] " info "make [id] or active window vital" eol
123 150 nl "%1$s -c " param "[id] " info "clear vital flag on [id] or active window" eol
124 151 nl "%1$s -q " param "[id] " info "'emergency' kill w/o reference to vital flag" eol,
125 152 argv[0]);
126 153 return 1;
127 154 }