util  Check-in [795f87aa54]

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: 795f87aa54562a21d8fc2831a6efeac93cf0efa0345bbf8c78af9f89ee7d4bfc
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"