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