util  Diff

Differences From Artifact [d7a13fcb31]:

To Artifact [54b90bee6d]:

  • 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   }