CTWM
Loading...
Searching...
No Matches
/usr/src/RPM/BUILD/ctwm-4.1.0/captive.c
Go to the documentation of this file.
1/*
2 * Captive ctwm handling bits.
3 *
4 * Captive support makes use of several X properties on various windows.
5 *
6 * The WM_CTWMSLIST property is set on the root window (of the
7 * appropriate Screen) containing a \0-separated list of the names of the
8 * captive windows inside that ctwm. So this would show up in the root
9 * window of a captive ctwm as well, if it had more captives inside it.
10 *
11 * A WM_CTWM_ROOT_<captive_name> property is set on the root window (see
12 * previous) for each of the captive ctwm's, holding the Window XID for
13 * that captive's internal root window. The combination of WM_CTWMSLIST
14 * and WM_CTWM_ROOT_<name> can be used to find the windows each of the
15 * captive ctwms inside us.
16 *
17 * A WM_CTWM_ROOT is set by the captive ctwm on its created root window,
18 * holding the XID of itself. The same property is also set by the
19 * 'outside' ctwm on the frame of that window. These are used in the
20 * f.hypermove process, to find the window ID to move stuff into. I'm
21 * not quite sure why we're setting it on both; perhaps so the border
22 * counts as part of the inner window.
23 */
24
25#include "ctwm.h"
26
27#include <stdio.h>
28#include <string.h>
29#include <stdlib.h>
30
31#include <X11/Xatom.h>
32#include <X11/Xmu/WinUtil.h>
33
34#include "captive.h"
35#include "events.h"
36#include "screen.h"
37#include "ctwm_atoms.h"
38#include "util.h"
39#include "vscreen.h"
40
41
42static char **GetCaptivesList(int scrnum);
43static void SetCaptivesList(int scrnum, char **clist);
44static void freeCaptivesList(char **clist);
46static bool DontRedirect(Window window);
47
49
50/* XXX Share with occupation.c? */
52 {"-xrm", NULL, XrmoptionResArg, (XPointer) NULL},
53};
54
55
56/*
57 * Reparent a window over to a captive ctwm, if we should.
58 */
59bool
61{
62 unsigned long nitems, bytesafter;
64 int actual_format;
66 char *str_type;
67 XrmValue value;
68 bool ret;
69 char *atomname;
71
72 /* NOREDIRECT property set? Leave it alone. */
73 if(DontRedirect(window)) {
74 return false;
75 }
76
77 /* Figure out what sort of -xrm stuff it might have */
78 {
79 char **cliargv = NULL;
80 int cliargc;
81
82 /* Get its command-line */
83 if(!XGetCommand(dpy, window, &cliargv, &cliargc)) {
84 /* Can't tell, bail */
85 return false;
86 }
87
88 XrmParseCommand(&db, table, 1, "ctwm", &cliargc, cliargv);
89 if(cliargv) {
91 }
92 }
93
94 /* Bail if we didn't get any info */
95 if(db == NULL) {
96 return false;
97 }
98
99 ret = false;
100
101 /*
102 * Check "-xrm ctwm.redirect" to see if that says what to do. It
103 * should contain a captive name. e.g., what ctwm was started with
104 * via --name, or an autogen'd name if no --name was given.
105 * */
106 status = XrmGetResource(db, "ctwm.redirect", "Ctwm.Redirect", &str_type,
107 &value);
108 if((status == True) && (value.size != 0)) {
109 /* Yep, we're asked for one. Find it. */
110 Window *prop;
112 int gpret;
113
114 asprintf(&atomname, "WM_CTWM_ROOT_%s", value.addr);
115 /*
116 * Set only_if_exists to True: the atom for the requested
117 * captive ctwm won't exist if the captive ctwm itself does not exist.
118 * There is no reason to go and create random atoms just to
119 * check.
120 */
122 free(atomname);
123
124 /*
125 * Got the atom? Lookup the property it keys for, which holds a
126 * Window identifier.
127 * */
128 gpret = !Success;
129 prop = NULL;
132 0L, 1L, False, AnyPropertyType,
135 (unsigned char **)&prop);
136 }
137
138 /*
139 * Got the property? Make sure it's the right type. If so, make
140 * sure the window it points at exists.
141 */
142 if(gpret == Success
143 && actual_type == XA_WINDOW && actual_format == 32 &&
144 nitems == 1 /*&& bytesafter == 0*/) {
147
149 /* Well, it must be where we should redirect to, so do it */
150 XReparentWindow(dpy, window, newroot, 0, 0);
151 XMapWindow(dpy, window);
152 ret = true;
153 }
154 }
155 if(prop != NULL) {
156 XFree(prop);
157 }
158
159 /* XXX Should we return here if we did the Reparent? */
160 }
161
162
163 /*
164 * Check ctwm.rootWindow; it may contain a (hex) X window identifier,
165 * which we should parent into.
166 * */
167 status = XrmGetResource(db, "ctwm.rootWindow", "Ctwm.RootWindow", &str_type,
168 &value);
169 if((status == True) && (value.size != 0)) {
170 char rootw [32];
171 unsigned long int scanned;
172
173 safe_strncpy(rootw, value.addr, sizeof(rootw));
174 if(sscanf(rootw, "%lx", &scanned) == 1) {
177
179 XReparentWindow(dpy, window, newroot, 0, 0);
180 XMapWindow(dpy, window);
181 ret = true;
182 }
183 }
184 }
185
186 /* Cleanup xrm bits */
188
189 /* Whatever we found */
190 return ret;
191}
192
193
194/*
195 * Get the list of captive ctwm's we know about on a screen.
196 *
197 * Use freeCaptivesList() to clean up the return value.
198 */
199static char **
201{
202 unsigned char *prop, *p;
203 unsigned long bytesafter;
204 unsigned long len;
206 int actual_format;
207 char **ret;
208 int count;
209 int i, l;
210 Window root;
211
215 &bytesafter, &prop) != Success) {
216 return NULL;
217 }
218 if(len == 0) {
219 return NULL;
220 }
221
222 count = 0;
223 p = prop;
224 l = 0;
225 while(l < len) {
226 l += strlen((char *)p) + 1;
227 p += strlen((char *)p) + 1;
228 count++;
229 }
230 ret = calloc(count + 1, sizeof(char *));
231
232 p = prop;
233 l = 0;
234 i = 0;
235 while(l < len) {
236 ret [i++] = strdup((char *) p);
237 l += strlen((char *)p) + 1;
238 p += strlen((char *)p) + 1;
239 }
240 ret [i] = NULL;
241 XFree(prop);
242
243 return ret;
244}
245
246
247/*
248 * Free GetCaptivesList() return.
249 */
250static void
252{
253 if(clist == NULL) {
254 return;
255 }
256
257 for(char **tmp = clist ; *tmp != NULL ; tmp++) {
258 free(*tmp);
259 }
260
261 free(clist);
262}
263
264
265/*
266 * Set the WM_CTWMSLIST property with a set of captive ctwm's, so it can
267 * be retrieved from there later (say, by a GetCaptivesList() call).
268 */
269static void
271{
272 unsigned long len;
273 char **cl;
274 char *s, *slist;
276
277 cl = clist;
278 len = 0;
279 while(*cl) {
280 len += strlen(*cl++) + 1;
281 }
282 if(len == 0) {
284 return;
285 }
286 slist = calloc(len, sizeof(char));
287 cl = clist;
288 s = slist;
289 while(*cl) {
290 strcpy(s, *cl);
291 s += strlen(*cl);
292 *s++ = '\0';
293 cl++;
294 }
296 PropModeReplace, (unsigned char *) slist, len);
297 free(slist);
298}
299
300
301/*
302 * Add ourselves to the list of captive ctwms. Called during startup
303 * when --window is given. Returns the captive name, because we may not
304 * have been given one explicitly (in cptname), and so it may have been
305 * autogen'd.
306 */
307char *
309{
310 int i, count;
311 char **clist, **cl, **newclist;
312 int busy [32];
313 char *atomname;
314 int scrnum = Scr->screen;
315 Window croot = Scr->Root;
316 Window root;
317 char *rcname;
318
319 for(i = 0; i < 32; i++) {
320 busy [i] = 0;
321 }
322
323 /*
324 * Go through our current captives to see what's taken
325 */
327 cl = clist;
328 count = 0;
329 while(cl && *cl) {
330 count++;
331
332 /*
333 * If we're not given a cptname, we use this loop to mark up
334 * which auto-gen'd names have been used.
335 */
336 if(!cptname) {
337 if(!strncmp(*cl, "ctwm-", 5)) {
338 int r, n;
339 r = sscanf(*cl, "ctwm-%d", &n);
340 cl++;
341 if(r != 1) {
342 continue;
343 }
344 if((n < 0) || (n > 31)) {
345 continue;
346 }
347 busy [n] = 1;
348 }
349 else {
350 cl++;
351 }
352 continue;
353 }
354
355 /*
356 * If we do have a cptname, and a captive already has the
357 * requested name, bomb
358 */
359 if(!strcmp(*cl, cptname)) {
360 fprintf(stderr, "A captive ctwm with name %s is already running\n",
361 cptname);
362 exit(1);
363 }
364 cl++;
365 }
366
367
368 /*
369 * If we weren't given a name, find an available autogen one. If we
370 * were, just dup it for our return value.
371 */
372 if(!cptname) {
373 for(i = 0; i < 32; i++) {
374 if(!busy [i]) {
375 break;
376 }
377 }
378 if(i == 32) { /* no one can tell we didn't try hard */
379 fprintf(stderr, "Cannot find a suitable name for captive ctwm\n");
380 exit(1);
381 }
382 asprintf(&rcname, "ctwm-%d", i);
383 }
384 else {
386 if(rcname == NULL) {
387 fprintf(stderr, "strdup() for rcname failed!\n");
388 abort();
389 }
390 }
391
392
393 /* Put together new list of captives */
394 newclist = calloc(count + 2, sizeof(char *));
395 for(i = 0; i < count; i++) {
396 newclist[i] = strdup(clist[i]);
397 }
398 newclist[count] = strdup(rcname);
399 newclist[count + 1] = NULL;
403
404 /* Stash property/atom of our captivename */
406 asprintf(&atomname, "WM_CTWM_ROOT_%s", rcname);
408 free(atomname);
410 PropModeReplace, (unsigned char *) &croot, 1);
411
412 /*
413 * Tell our caller the name we wound up with, in case they didn't
414 * give us one we could use.
415 */
416 return rcname;
417}
418
419
420/*
421 * Take something (in practice, always ourselves) out of the list of
422 * running captives. Called during shutdown.
423 */
424void
426{
427 char **clist;
428 int scrnum = Scr->screen;
430
431 /* If we're not apparently captive, there's nothing to do */
433 return;
434 }
435
436 /* Take us out of the captives list in WM_CTWMSLIST */
438 if(clist && *clist) {
439 char **cl = clist;
440 char **newclist;
441 int count;
442 bool found;
443
444 /* How many are there? */
445 count = 0;
446 found = false;
447 while(*cl) {
448 if(strcmp(*cl, cptname) == 0) {
449 found = true;
450 }
451 count++;
452 cl++;
453 }
454
455 /* If we weren't there, there's nothing to do */
456 if(!found) {
458 return;
459 }
460
461 /*
462 * Make a new list without cptname in it. A list with (count)
463 * items needs (count+1) for the trailing NULL, but we know we're
464 * in it and removing ourself, so we only need ((count-1)+1).
465 *
466 * Note that we're _not_ strdup()'ing into newclist, just
467 * sticking a pointer to the existing string inside clist. Then
468 * we only have to free() newclist itself, because there's
469 * nothing new inside it. We explicitly do _NOT_ want to
470 * freeCaptivesList() it, since that would free the internals,
471 * and then when we fCL(clist) it would try to double-free them.
472 */
473 newclist = calloc(count, sizeof(char *));
474 cl = clist;
475 count = 0;
476 while(*cl) {
477 if(!strcmp(*cl, cptname)) {
478 cl++;
479 continue;
480 }
481 newclist [count++] = *cl;
482 cl++;
483 }
484 newclist [count] = NULL;
486 free(newclist);
487 }
489
490 /* And delete our CTWM_ROOT_x property */
492}
493
494
495/*
496 * Call from AddWindow() on the 'outside'; if this new window is a
497 * captive ctwm running inside us, copy its WM_CTWM_ROOT property to the
498 * frame window we're creating around it. It's a little unclear why
499 * we're doing this; x-ref comment at top of file.
500 */
501void
503{
504 Window window = win->w;
505 Window frame = win->frame;
506
507 if(!CaptiveCtwmRootWindow(window)) {
508 return;
509 }
510
512 PropModeReplace, (unsigned char *) &window, 1);
513}
514
515
516/*
517 * Get the WM_CTWM_ROOT property of a window; that tells us whether it
518 * thinks it's a captive ctwm, and if so, what it thinks its root window
519 * is.
520 */
521static Window
523{
524 Window *prop;
525 Window w;
526 unsigned long bytesafter;
527 unsigned long len;
529 int actual_format;
530
531 if(XGetWindowProperty(dpy, window, XA_WM_CTWM_ROOT, 0L, 1L,
533 &bytesafter, (unsigned char **)&prop) != Success) {
534 return ((Window)0);
535 }
536 if(len == 0) {
537 return ((Window)0);
538 }
539 w = *prop;
540 XFree(prop);
541 return w;
542}
543
544
545/*
546 * Get info about the captive CTWM instance under the cursor. Called
547 * during the f.hypermove process.
548 */
551{
552 Window root;
555 char *rname;
556
557 root = RootWindow(dpy, Scr->screen);
558 while(1) {
560 &JunkX, &JunkY, &JunkX, &JunkY, &JunkMask);
562 root = croot;
563 continue;
564 }
565 cctwm.root = root;
566
567 /*
568 * We indirect through the extra var here for probably
569 * unnecessary reasons; X resources (like that from XFetchName)
570 * are specified to be freed via XFree(), not via free(). And we
571 * don't want our callers to have to know that (or worse, know to
572 * do it SOMEtimes, since we also might create it ourselves with
573 * strdup()). So eat the extra allocation/copy and insulate
574 * callers.
575 */
577 if(rname) {
578 cctwm.name = strdup(rname);
579 XFree(rname);
580 }
581 else {
582 cctwm.name = strdup("Root");
583 }
584
585 return (cctwm);
586 }
587}
588
589
590/*
591 * We set a NOREDIRECT property on windows in certain situations as a
592 * result of a f.hypermove. That gets checked during
593 * RedirectToCaptive(), causing it to to not mess with the window.
594 *
595 * XXX I'm not sure this actually makes any sense; RTC() only gets called
596 * at the beginning of AddWindow(), only if ctwm isn't running captive.
597 * So the upshot is that this causes AddWindow() to do nothing and return
598 * NULL, in the case that a window was hypermoved from a captive ctwm
599 * into a non-captive ctwm.
600 *
601 * That's OK I think, because all the AddWindow() stuff would have
602 * already been done for it, so there's nothing to do? But this suggests
603 * that there's leakage happening; we keep a TwmWindow struct around in
604 * the "old" ctwm when it's moved into a new one, and since AddWindow()
605 * only does the condition if we're a non-captive ctwm, it means the
606 * _captive_ ctwm recreates a new one every time it's hypermoved in?
607 */
608void
610{
612 PropModeReplace, (unsigned char *) "Yes", 4);
613}
614
615static bool
617{
618 unsigned char *prop;
619 unsigned long bytesafter;
620 unsigned long len;
622 int actual_format;
623
624 if(XGetWindowProperty(dpy, window, XA_WM_NOREDIRECT, 0L, 1L,
626 &bytesafter, &prop) != Success) {
627 return false;
628 }
629 if(len == 0) {
630 return false;
631 }
632 XFree(prop);
633 return true;
634}
635
636
637/*
638 * Handling of a ConfigureNotify for a captive root window.
639 */
640void
642{
644 int x, y;
645 unsigned int w, h, bw, d, oldw, oldh;
646
647 /* Guard */
648 if(!CLarg.is_captive) {
649 fprintf(stderr, "BUG: %s(): Shouldn't get called unless captive.\n",
650 __func__);
651 return;
652 }
653
654 XGetGeometry(dpy, Scr->CaptiveRoot, &root, &x, &y, &w, &h, &bw, &d);
655 XTranslateCoordinates(dpy, Scr->CaptiveRoot, root, 0, 0, &Scr->crootx,
656 &Scr->crooty, &child);
657
658 oldw = Scr->crootw;
659 oldh = Scr->crooth;
660 Scr->crootw = ev->xconfigure.width;
661 Scr->crooth = ev->xconfigure.height;
662#if 0
663 fprintf(stderr, "%s(): cx = %d, cy = %d, cw = %d, ch = %d\n",
664 __func__, Scr->crootx, Scr->crooty, Scr->crootw, Scr->crooth);
665#endif
666 if(Scr->currentvs) {
667 Scr->rootx = Scr->crootx + Scr->currentvs->x;
668 Scr->rooty = Scr->crooty + Scr->currentvs->y;
669 }
670 Scr->rootw = Scr->crootw;
671 Scr->rooth = Scr->crooth;
672
673 /*
674 * XXX This is a little weird, and in my experience _always_ triggers
675 * when a captive window starts up. So what's the point?
676 */
677 if((Scr->crootw != oldw) || (Scr->crooth != oldh)) {
678 fprintf(stderr, "%s: You cannot change root window geometry "
679 "with virtual screens active,\n"
680 "from now on, the ctwm behaviour is unpredictable.\n",
682 }
683}
684
685
686/*
687 * Adopt a window into the calling captive ctwm. Backend for
688 * f.adoptwindow function.
689 */
690void AdoptWindow(void)
691{
692 unsigned long data [2];
693 Window localroot, w;
694 unsigned char *prop;
695 unsigned long bytesafter;
696 unsigned long len;
698 int actual_format;
701 unsigned int nchildren, key_buttons;
702 int root_x, root_y, win_x, win_y;
703 int ret;
705
706 localroot = w = RootWindow(dpy, Scr->screen);
710 None, Scr->SelectCursor, CurrentTime);
711
713 child = event.xbutton.subwindow;
714 while(1) {
715 if(child == (Window) 0) {
716 break;
717 }
718
722 &bytesafter, &prop);
723 XFree(prop); /* Don't ever do anything with it */
724 if(ret != Success) {
725 break;
726 }
727 if(len == 0) { /* it is not a local root window */
728 break; /* it is not a local root window */
729 }
730 localroot = w;
732 &win_x, &win_y, &key_buttons);
733 }
736
737 if(localroot == Scr->Root) {
738 return;
739 }
740 if(w == localroot) { /* try to not adopt an ancestor */
742 while(parent != (Window) 0) {
744 if(w == parent) {
745 return;
746 }
748 }
750 if(w == root) {
751 return;
752 }
753 }
754 if(localroot == RootWindow(dpy, Scr->screen)) {
755 XWithdrawWindow(dpy, w, Scr->screen);
756 }
757 else {
758 XUnmapWindow(dpy, w);
759 }
760 XReparentWindow(dpy, w, Scr->Root, 0, 0);
761
762 data [0] = (unsigned long) NormalState;
763 data [1] = (unsigned long) None;
764
766 PropModeReplace, (unsigned char *) data, 2);
767 XFlush(dpy);
768 /*
769 * We don't want to "restore" the occupation that the window had
770 * in its former environment. For one, the names of the workspaces
771 * may be different. And if not, the window will initially be
772 * shown in the current workspace, which may be at odds with that
773 * occupation (and confusion ensues).
774 *
775 * Hypermove has the same problem, but that is a "push" operation
776 * (initiated by the originating window manager) so we don't know
777 * when it happens...
778 */
780 RestartPreviousState = false;
783 return;
784}
static int PlaceX
Definition add_window.c:82
void SetPropsIfCaptiveCtwm(TwmWindow *win)
Definition captive.c:502
static XrmOptionDescRec table[]
Definition captive.c:51
static void freeCaptivesList(char **clist)
Definition captive.c:251
static bool DontRedirect(Window window)
Definition captive.c:616
void RemoveFromCaptiveList(const char *cptname)
Definition captive.c:425
void ConfigureCaptiveRootWindow(XEvent *ev)
Definition captive.c:641
bool RedirectToCaptive(Window window)
Definition captive.c:60
void SetNoRedirect(Window window)
Definition captive.c:609
void AdoptWindow(void)
Definition captive.c:690
static char ** GetCaptivesList(int scrnum)
Definition captive.c:200
static void SetCaptivesList(int scrnum, char **clist)
Definition captive.c:270
static Window CaptiveCtwmRootWindow(Window window)
Definition captive.c:522
char * AddToCaptiveList(const char *cptname)
Definition captive.c:308
static Atom XA_WM_CTWM_ROOT_our_name
Definition captive.c:48
CaptiveCTWM GetCaptiveCTWMUnderPointer(void)
Definition captive.c:550
ctwm_cl_args CLarg
Definition clargs.c:27
bool RestartPreviousState
Definition ctwm_main.c:151
int JunkY
Definition ctwm.h:358
char * ProgramName
Definition ctwm_main.c:146
Window JunkRoot
Definition ctwm_main.c:142
int JunkX
Definition ctwm_main.c:143
Display * dpy
Definition ctwm_main.c:84
unsigned int JunkMask
Definition ctwm.h:359
#define Scr
void SimulateMapRequest(Window w)
Window frame
The X window for the overall frame.
int y
Definition menus.c:70
int x
Definition menus.c:69
static int len
Definition parse.c:75
MenuRoot * root
Definition parse_yacc.c:26
Info and control for every X Window we take over.
Window w
The actual X Window handle.
void safe_strncpy(char *dest, const char *src, size_t size)
Definition util.c:586