Overview
Comment: | rewrite safekill to use X properties instead of hacking a flag into the window class |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
795f87aa54562a21d8fc2831a6efeac9 |
User & Date: | lexi on 2019-04-14 03:07:41 |
Other Links: | manifest | tags |
Context
2019-04-17
| ||
16:52 | add shit, updates check-in: 196f94b613 user: lexi tags: trunk | |
2019-04-14
| ||
03:07 | rewrite safekill to use X properties instead of hacking a flag into the window class check-in: 795f87aa54 user: lexi tags: trunk | |
2019-04-13
| ||
13:44 | fix typo check-in: ee4f58caef user: lexi tags: trunk | |
Changes
Modified safekill.c from [95fcf40cb0] to [59e57157c0].
1 1 /* [ʞ] safekill.c <c.hale.su/lexi/util> 2 2 * ~ lexi hale <lexi@hale.su> 3 - * $ cc -Ofast safekill.c -lX11 -lc -osafekill 3 + * $ cc -Ofast safekill.c -lX11 -osafekill 4 4 * © affero general public license 5 5 6 6 * a utility to make it harder to accidentally nuke 7 - * important windows on i3wm or whatever. */ 7 + * important windows on i3wm or whatever. 8 + 9 + TODO add option to run as daemon that listens for 10 + key chords, for wms that don't have built-in 11 + support for user keybindings */ 8 12 9 13 #include <X11/Xlib.h> 10 14 #include <X11/Xutil.h> 11 15 #include <X11/Xatom.h> 12 16 #include <stdio.h> 13 17 #include <stdlib.h> 14 18 #include <string.h> 15 19 #include <errno.h> 16 20 typedef enum { false, true } bool; 17 -char* isvital(char* str) { 18 - start: // tail calls for dipshits 19 - if (*str != '{') { 20 - if (*str == 0) return 0; 21 - ++str; goto start; 22 - } else { 23 - if (str[1] == 'V' && str[2] == '}') 24 - return str; 25 - else { ++str; goto start; } 26 - } 27 -} 28 21 29 22 Display *display; 23 +Atom xvital; 24 + 25 +bool isvital(Window w) { 26 + unsigned char* value; 27 + int _i; long _l; 28 + Atom type; 29 + XGetWindowProperty(display,w, xvital, 0,1,False,xvital, 30 + &type,&_i,&_l,&_l, &value); 31 + return type != None; 32 +} 30 33 31 34 void killwin(Window w) { 32 35 XEvent ev; 33 36 long mask = SubstructureRedirectMask | SubstructureNotifyMask; 34 37 ev.xclient.type = ClientMessage; 35 38 ev.xclient.serial = 0; 36 39 ev.xclient.send_event = True; ................................................................................ 48 51 fprintf(stderr,"\n"); 49 52 } else { 50 53 fprintf(stderr," falling back to XDestroyWindow, but this may wreck your shit - lots of multi-win apps do *not* like it.\n"); 51 54 XDestroyWindow(display,w); 52 55 } 53 56 } 54 57 } 58 + 59 +bool isnum(const char* str) { 60 + // is the string passed something strtoul can interpret as a 61 + // number? decimal, hex, or octal? 62 + if (*str == '0' && str[1] == 0) return true; 63 + 64 + enum { hex, dec, oct } mode; 65 + if (*str == '0' && str[1] == 'x') mode = hex, str += 2; 66 + else if (*str == '0') mode = oct, str += 1; 67 + else mode = dec; 68 + bool first = true; 69 + eval: if(*str == 0) return !first; 70 + first = false; 71 + if(*str >= '0' && *str <= '7') { 72 + ++ str; goto eval; 73 + } else if ((mode == dec || mode == hex) && *str >= '0' && *str <= '9') { 74 + ++ str; goto eval; 75 + } else if (mode == hex && ( 76 + (*str >= 'a' && *str <= 'f') || 77 + (*str >= 'A' && *str <= 'F'))) { 78 + ++ str; goto eval; 79 + } else return false; 80 +} 81 + 82 +int bad(Display* d, XErrorEvent* e) { 83 + printf("\x1b[1merror:\x1b[m no such window\n"); 84 + exit(1); 85 +} 86 + 55 87 int main(const int argc, const char** argv) { 56 88 Window focus; 57 89 int revert; 58 90 59 91 bool active; 60 92 enum { vitalize, devitalize, hardkill, softkill } op; 61 93 62 - if (argc > 3) goto usage; 63 - if (argc == 1) 94 + const char* winp = argv[2]; 95 + if (argc > 3) goto usage; // nope 96 + if (argc == 1) // no parameters, implied softkill on active win 64 97 op = softkill, active = true; 65 98 else { 66 - if (argc == 2) active = true; 67 - else active = false; 99 + if (argc == 2) { // single argument; what kind is it? 100 + if (isnum(argv[1])) { // single numeric argument = win id 101 + active = false; // window is specified for us 102 + op = softkill; // implied softkill 103 + winp = argv[1]; // interpret argv[1] as window id 104 + goto go_go_go; // skip the rest of this nonsense; 105 + // we already know there's no switch 106 + } else { 107 + active = true; // no number passed, so it's either a 108 + // switch with an implied active window or bad syntax 109 + // now we need to figure out which 110 + } 111 + } else if (argc == 3) active = false; // win id AND opt 68 112 113 + // determine mission parameters 69 114 if (argv[1][0] == '-' && argv[1][2] == 0) { // opt is short switch 70 115 switch (argv[1][1]) { // opt char 71 - 72 116 // make window mission-critical 73 117 case 'v': op = vitalize; break; 74 118 75 119 // make window acceptable loss 76 120 case 'c': op = devitalize; break; 77 121 78 122 // liquidate by any means necessary ................................................................................ 80 124 81 125 // with all due respect sir what the fuck 82 126 default: goto usage; 83 127 } 84 128 } else goto usage; 85 129 } 86 130 131 +go_go_go: 87 132 display = XOpenDisplay(NULL); 133 + xvital = XInternAtom(display, "_k_vital", False); 134 + XSetErrorHandler(bad); 88 135 89 136 if (active) { 90 137 XGetInputFocus(display, &focus, &revert); 91 138 } else { 92 - unsigned long temp = strtoul(argv[2], NULL, 0); 139 + unsigned long temp = strtoul(winp, NULL, 0); 93 140 if (errno == EINVAL || errno == ERANGE) goto usage; 94 141 if (temp == 0) goto usage; 95 142 focus = (Window)temp; 96 143 } 97 144 98 145 if(op == hardkill) { 99 146 killwin(focus); 100 147 XSync(display,false); 101 148 return 0; 102 149 } 103 150 104 - XClassHint xclh; 105 - if (XGetClassHint(display,focus,&xclh)) { 106 - char* v; 107 - if(v = isvital(xclh.res_class)) { 108 - 109 - if (op == vitalize) return 0; // nothing need be done 110 - else if (op == devitalize) { 111 - strcpy(v, v+3); 112 - XSetClassHint(display,focus,&xclh); 113 - XSync(display,false); 114 - } else if (op == softkill) { 115 - fprintf(stderr, "softkill forbidden\n"); 116 - return 1; // ACCESS DENIED 117 - } 118 - } else { 119 - if (op == vitalize) { 120 - size_t sz=strlen(xclh.res_class); // TODO: remove double-walk 121 - xclh.res_class=realloc(xclh.res_class, sz+4); 122 - xclh.res_class[sz]='{'; 123 - xclh.res_class[sz+1]='V'; 124 - xclh.res_class[sz+2]='}'; 125 - xclh.res_class[sz+3]=0; 126 - XSetClassHint(display,focus,&xclh); 127 - XSync(display,false); 128 - } else if (op == devitalize) return 0; 129 - else if (op == softkill) { 130 - // ice that motherfucker 131 - killwin(focus); 132 - XSync(display,false); 133 - return 3; 134 - } 151 + char* v; 152 + if(isvital(focus)) { 153 + if (op == vitalize) return 0; // nothing need be done 154 + else if (op == devitalize) { 155 + XDeleteProperty(display, focus, xvital); 156 + XSync(display,false); 157 + } else if (op == softkill) { 158 + fprintf(stderr, "softkill forbidden\n"); 159 + return 1; // ACCESS DENIED 135 160 } 136 161 } else { 137 - fprintf(stderr,"\x1b[1merror:\x1b[m bad window\n"); 138 - goto usage; 162 + if (op == vitalize) { 163 + char* yes="\01"; //arbitrary 164 + XChangeProperty(display,focus, xvital,xvital,8,PropModeReplace, yes, 1); 165 + XSync(display,false); 166 + } else if (op == devitalize) return 0; 167 + else if (op == softkill) { 168 + // ice that motherfucker 169 + killwin(focus); 170 + XSync(display,false); 171 + return 3; 172 + } 139 173 } 140 174 141 175 return 0; 142 176 143 177 usage: 144 178 #define info "\x1b[34m-- " 145 179 #define param "\x1b[32m"