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 | #include <stdio.h> |
39 | #include <stdlib.h> |
40 | #include <ctype.h> |
41 | |
42 | #include <X11/Xos.h> |
43 | #include <X11/Xlib.h> |
44 | #include <X11/cursorfont.h> |
45 | #include <X11/Xproto.h> |
46 | |
47 | #include <X11/Xmu/WinUtil.h> |
48 | |
49 | static Display *dpy = NULL((void*)0); |
50 | static char *ProgramName; |
51 | |
52 | #define SelectButtonAny(-1) (-1) |
53 | #define SelectButtonFirst(-2) (-2) |
54 | |
55 | static int parse_button ( char *s, int *buttonp ); |
56 | static XID parse_id ( char *s ); |
57 | static XID get_window_id ( Display *dpy, int screen, int button, char *msg ); |
58 | static int catch_window_errors ( Display *dpy, XErrorEvent *ev ); |
59 | static int kill_all_windows ( Display *dpy, int screenno, Boolint top ); |
60 | static int verify_okay_to_kill ( Display *dpy, int screenno ); |
61 | static Boolint wm_state_set ( Display *dpy, Window win ); |
62 | static Boolint wm_running ( Display *dpy, int screenno ); |
63 | |
64 | static void |
65 | Exit(int code) |
66 | { |
67 | if (dpy) { |
68 | XCloseDisplay (dpy); |
69 | } |
70 | exit (code); |
71 | } |
72 | |
73 | static void |
74 | usage(void) |
75 | { |
76 | const char *options = |
77 | "where options include:\n" |
78 | " -display displayname X server to contact\n" |
79 | " -id resource resource whose client is to be killed\n" |
80 | " -frame don't ignore window manager frames\n" |
81 | " -button number specific button to be pressed to select window\n" |
82 | " -all kill all clients with top level windows\n" |
83 | "\n"; |
84 | char **cpp; |
85 | |
86 | fprintf (stderrstderr, "usage: %s [-option ...]\n%s", |
87 | ProgramName, options); |
88 | Exit (1); |
89 | } |
90 | |
91 | int |
92 | main(int argc, char *argv[]) |
93 | { |
94 | int i; |
95 | char *displayname = NULL((void*)0); |
96 | int screenno; |
97 | XID id = None0L; |
98 | char *button_name = NULL((void*)0); |
99 | int button; |
100 | Boolint kill_all = False0; |
101 | Boolint top = False0; |
102 | |
103 | ProgramName = argv[0]; |
104 | button = SelectButtonFirst(-2); |
105 | |
106 | for (i = 1; i < argc; i++) { |
| 1 | Assuming 'i' is >= 'argc' |
|
| 2 | Loop condition is false. Execution continues on line 137 |
|
107 | char *arg = argv[i]; |
108 | |
109 | if (arg[0] == '-') { |
110 | switch (arg[1]) { |
111 | case 'd': |
112 | if (++i >= argc) usage (); |
113 | displayname = argv[i]; |
114 | continue; |
115 | case 'i': |
116 | if (++i >= argc) usage (); |
117 | id = parse_id (argv[i]); |
118 | continue; |
119 | case 'b': |
120 | if (++i >= argc) usage (); |
121 | button_name = argv[i]; |
122 | continue; |
123 | case 'f': |
124 | top = True1; |
125 | continue; |
126 | case 'a': |
127 | kill_all = True1; |
128 | continue; |
129 | default: |
130 | usage (); |
131 | } |
132 | } else { |
133 | usage (); |
134 | } |
135 | } |
136 | |
137 | dpy = XOpenDisplay (displayname); |
138 | if (!dpy) { |
| |
| |
139 | fprintf (stderrstderr, "%s: unable to open display \"%s\"\n", |
140 | ProgramName, XDisplayName (displayname)); |
141 | Exit (1); |
142 | } |
143 | screenno = DefaultScreen (dpy)(((_XPrivDisplay)dpy)->default_screen); |
| 5 | Within the expansion of the macro 'DefaultScreen':
|
a | Access to field 'default_screen' results in a dereference of a null pointer (loaded from variable 'dpy') |
|
144 | |
145 | if (kill_all) { |
146 | if (verify_okay_to_kill (dpy, screenno)) |
147 | kill_all_windows (dpy, screenno, top); |
148 | Exit (0); |
149 | } |
150 | |
151 | |
152 | |
153 | |
154 | |
155 | if (id == None0L) { |
156 | if (!button_name) |
157 | button_name = XGetDefault (dpy, ProgramName, "Button"); |
158 | |
159 | if (button_name && !parse_button (button_name, &button)) { |
160 | fprintf (stderrstderr, "%s: invalid button specification \"%s\"\n", |
161 | ProgramName, button_name); |
162 | Exit (1); |
163 | } |
164 | |
165 | if (button >= 0 || button == SelectButtonFirst(-2)) { |
166 | unsigned char pointer_map[256]; |
167 | int count, j; |
168 | unsigned int ub = (unsigned int) button; |
169 | |
170 | |
171 | count = XGetPointerMapping (dpy, pointer_map, 256); |
172 | if (count <= 0) { |
173 | fprintf (stderrstderr, |
174 | "%s: no pointer mapping, can't select window\n", |
175 | ProgramName); |
176 | Exit (1); |
177 | } |
178 | |
179 | if (button >= 0) { |
180 | for (j = 0; j < count; j++) { |
181 | if (ub == (unsigned int) pointer_map[j]) break; |
182 | } |
183 | if (j == count) { |
184 | fprintf (stderrstderr, |
185 | "%s: no button number %u in pointer map, can't select window\n", |
186 | ProgramName, ub); |
187 | Exit (1); |
188 | } |
189 | } else { |
190 | button = (int) ((unsigned int) pointer_map[0]); |
191 | } |
192 | } |
193 | if ((id = get_window_id (dpy, screenno, button, |
194 | "the window whose client you wish to kill"))) { |
195 | if (id == RootWindow(dpy,screenno)((&((_XPrivDisplay)dpy)->screens[screenno])->root)) id = None0L; |
196 | else if (!top) { |
197 | XID indicated = id; |
198 | if ((id = XmuClientWindow(dpy, indicated)) == indicated) { |
199 | |
200 | |
201 | |
202 | |
203 | |
204 | if (! wm_state_set(dpy, id) && wm_running(dpy, screenno)) |
205 | id = None0L; |
206 | |
207 | } |
208 | } |
209 | } |
210 | } |
211 | |
212 | if (id != None0L) { |
213 | printf ("%s: killing creator of resource 0x%lx\n", ProgramName, id); |
214 | XSync (dpy, 0); |
215 | XKillClient (dpy, id); |
216 | XSync (dpy, 0); |
217 | } |
218 | |
219 | Exit (0); |
220 | |
221 | return 0; |
222 | } |
223 | |
224 | static int |
225 | parse_button(char *s, int *buttonp) |
226 | { |
227 | register char *cp; |
228 | |
229 | |
230 | for (cp = s; *cp; cp++) { |
231 | if (isascii (*cp)(((*cp) & ~0x7f) == 0) && isupper (*cp)((*__ctype_b_loc ())[(int) ((*cp))] & (unsigned short int ) _ISupper)) { |
232 | #ifdef _tolower |
233 | *cp = _tolower (*cp)((int) (*__ctype_tolower_loc ())[(int) (*cp)]); |
234 | #else |
235 | *cp = tolower (*cp); |
236 | #endif /* _tolower */ |
237 | } |
238 | } |
239 | |
240 | if (strcmp (s, "any") == 0) { |
241 | *buttonp = SelectButtonAny(-1); |
242 | return (1); |
243 | } |
244 | |
245 | |
246 | for (cp = s; *cp; cp++) { |
247 | if (!(isascii (*cp)(((*cp) & ~0x7f) == 0) && isdigit (*cp)((*__ctype_b_loc ())[(int) ((*cp))] & (unsigned short int ) _ISdigit))) return (0); |
248 | } |
249 | |
250 | *buttonp = atoi (s); |
251 | return (1); |
252 | } |
253 | |
254 | |
255 | static XID |
256 | parse_id(char *s) |
257 | { |
258 | XID retval = None0L; |
259 | char *fmt = "%ld"; |
260 | |
261 | if (s) { |
262 | if (*s == '0') s++, fmt = "%lo"; |
263 | if (*s == 'x' || *s == 'X') s++, fmt = "%lx"; |
264 | sscanf (s, fmt, &retval); |
265 | } |
266 | return (retval); |
267 | } |
268 | |
269 | static XID |
270 | get_window_id(Display *dpy, int screen, int button, char *msg) |
271 | { |
272 | Cursor cursor; |
273 | Window root; |
274 | Window retwin = None0L; |
275 | int retbutton = -1; |
276 | int pressed = 0; |
277 | |
278 | #define MASK((1L<<2) | (1L<<3)) (ButtonPressMask(1L<<2) | ButtonReleaseMask(1L<<3)) |
279 | |
280 | root = RootWindow (dpy, screen)((&((_XPrivDisplay)dpy)->screens[screen])->root); |
281 | cursor = XCreateFontCursor (dpy, XC_pirate88); |
282 | if (cursor == None0L) { |
283 | fprintf (stderrstderr, "%s: unable to create selection cursor\n", |
284 | ProgramName); |
285 | Exit (1); |
286 | } |
287 | |
288 | printf ("Select %s with ", msg); |
289 | if (button == -1) |
290 | printf ("any button"); |
291 | else |
292 | printf ("button %d", button); |
293 | printf ("....\n"); |
294 | XSync (dpy, 0); |
295 | |
296 | if (XGrabPointer (dpy, root, False0, MASK((1L<<2) | (1L<<3)), GrabModeSync0, GrabModeAsync1, |
297 | None0L, cursor, CurrentTime0L) != GrabSuccess0) { |
298 | fprintf (stderrstderr, "%s: unable to grab cursor\n", ProgramName); |
299 | Exit (1); |
300 | } |
301 | |
302 | |
303 | while (retwin == None0L || pressed != 0) { |
304 | XEvent event; |
305 | |
306 | XAllowEvents (dpy, SyncPointer1, CurrentTime0L); |
307 | XWindowEvent (dpy, root, MASK((1L<<2) | (1L<<3)), &event); |
308 | switch (event.type) { |
309 | case ButtonPress4: |
310 | if (retwin == None0L) { |
311 | retbutton = event.xbutton.button; |
312 | retwin = ((event.xbutton.subwindow != None0L) ? |
313 | event.xbutton.subwindow : root); |
314 | } |
315 | pressed++; |
316 | continue; |
317 | case ButtonRelease5: |
318 | if (pressed > 0) pressed--; |
319 | continue; |
320 | } |
321 | } |
322 | |
323 | XUngrabPointer (dpy, CurrentTime0L); |
324 | XFreeCursor (dpy, cursor); |
325 | XSync (dpy, 0); |
326 | |
327 | return ((button == -1 || retbutton == button) ? retwin : None0L); |
328 | } |
329 | |
330 | |
331 | static int |
332 | catch_window_errors(Display *dpy, XErrorEvent *ev) |
333 | { |
334 | return 0; |
335 | } |
336 | |
337 | static int |
338 | kill_all_windows(Display *dpy, int screenno, Boolint top) |
339 | { |
340 | Window root = RootWindow (dpy, screenno)((&((_XPrivDisplay)dpy)->screens[screenno])->root); |
341 | Window dummywindow; |
342 | Window *children; |
343 | unsigned int nchildren; |
344 | unsigned int i; |
345 | XWindowAttributes attr; |
346 | |
347 | XSync (dpy, 0); |
348 | XSetErrorHandler (catch_window_errors); |
349 | |
350 | nchildren = 0; |
351 | XQueryTree (dpy, root, &dummywindow, &dummywindow, &children, &nchildren); |
352 | if (!top) { |
353 | for (i = 0; i < nchildren; i++) { |
354 | if (XGetWindowAttributes(dpy, children[i], &attr) && |
355 | (attr.map_state == IsViewable2)) |
356 | children[i] = XmuClientWindow(dpy, children[i]); |
357 | else |
358 | children[i] = 0; |
359 | } |
360 | } |
361 | for (i = 0; i < nchildren; i++) { |
362 | if (children[i]) |
363 | XKillClient (dpy, children[i]); |
364 | } |
365 | XFree ((char *)children); |
366 | |
367 | XSync (dpy, 0); |
368 | XSetErrorHandler (NULL((void*)0)); |
369 | |
370 | return 0; |
371 | } |
372 | |
373 | |
374 | |
375 | |
376 | static int |
377 | verify_okay_to_kill(Display *dpy, int screenno) |
378 | { |
379 | unsigned char pointer_map[256]; |
380 | int count = XGetPointerMapping (dpy, pointer_map, 256); |
381 | int i; |
382 | int button; |
383 | static char *msg = "the root window"; |
384 | Window root = RootWindow (dpy, screenno)((&((_XPrivDisplay)dpy)->screens[screenno])->root); |
385 | int okay = 0; |
386 | |
387 | for (i = 0; i < count; i++) { |
388 | button = (int) pointer_map[i]; |
389 | if (button == 0) continue; |
390 | if (get_window_id (dpy, screenno, button, msg) != root) { |
391 | okay = 0; |
392 | break; |
393 | } |
394 | okay++; |
395 | } |
396 | if (okay) { |
397 | return 1; |
398 | } else { |
399 | printf ("Aborting.\n"); |
400 | return 0; |
401 | } |
402 | } |
403 | |
404 | |
405 | |
406 | |
407 | static Boolint |
408 | wm_state_set(Display *dpy, Window win) |
409 | { |
410 | Atom wm_state; |
411 | Atom actual_type; |
412 | int success; |
413 | int actual_format; |
414 | unsigned long nitems, remaining; |
415 | unsigned char* prop = NULL((void*)0); |
416 | |
417 | wm_state = XInternAtom(dpy, "WM_STATE", True1); |
418 | if (wm_state == None0L) return False0; |
419 | success = XGetWindowProperty(dpy, win, wm_state, 0L, 0L, False0, |
420 | AnyPropertyType0L, &actual_type, &actual_format, |
421 | &nitems, &remaining, &prop); |
422 | if (prop) XFree((char *) prop); |
423 | return (success == Success0 && actual_type != None0L && actual_format); |
424 | } |
425 | |
426 | |
427 | |
428 | |
429 | |
430 | static Boolint |
431 | wm_running(Display *dpy, int screenno) |
432 | { |
433 | XWindowAttributes xwa; |
434 | Statusint status; |
435 | |
436 | status = XGetWindowAttributes(dpy, RootWindow(dpy, screenno)((&((_XPrivDisplay)dpy)->screens[screenno])->root), &xwa); |
437 | return (status && |
438 | ((xwa.all_event_masks & SubstructureRedirectMask(1L<<20)) || |
439 | (xwa.all_event_masks & SubstructureNotifyMask(1L<<19)))); |
440 | } |