CTWM
Loading...
Searching...
No Matches
/usr/src/RPM/BUILD/ctwm-4.1.0/ewmh.c
Go to the documentation of this file.
1/*
2 * Copyright 2014 Olaf Seibert
3 */
4
5/*
6 * Implements some of the Extended Window Manager Hints, as (extremely
7 * poorly) documented at
8 * http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html .
9 * In fact, the wiki page that refers to that as being the current version
10 * (http://www.freedesktop.org/wiki/Specifications/wm-spec/)
11 * neglects to tell us there are newer versions 1.4 and 1.5 at
12 * http://standards.freedesktop.org/wm-spec/wm-spec-1.5.html
13 * (which has a listable directory that I discovered by accident).
14 * The same wiki page also has lots of dead links to a CVS repository.
15 * Nevertheless, it is where one ends up if one starts at
16 * http://www.freedesktop.org/wiki/Specifications/ .
17 *
18 * EWMH is an extension to the ICCCM (Inter-Client Communication
19 * Conventions Manual).
20 * http://tronche.com/gui/x/icccm/
21 *
22 * To fill in lots of details, the source code of other window managers
23 * has been consulted.
24 */
25
26#include "ctwm.h"
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <time.h>
31#include <stdint.h>
32#include <assert.h>
33
34#include <X11/Xatom.h>
35#include <X11/extensions/shape.h>
36
37#include "ctwm_atoms.h"
38#include "ctwm_shutdown.h"
39#include "ewmh_atoms.h"
40#include "screen.h"
41#include "events.h"
42#include "event_handlers.h"
43#include "functions_defs.h"
44#include "icons.h"
45#include "otp.h"
46#include "image.h"
47#include "list.h"
48#include "functions.h"
49#include "occupation.h"
50#include "r_layout.h"
51#include "util.h"
52#include "vscreen.h"
53#include "win_iconify.h"
54#include "win_ops.h"
55#include "win_resize.h"
56#include "win_utils.h"
57#include "workspace_utils.h"
58
59/* #define DEBUG_EWMH */
60
62
63#define NET_WM_STATE_REMOVE 0 /* remove/unset property */
64#define NET_WM_STATE_ADD 1 /* add/set property */
65#define NET_WM_STATE_TOGGLE 2 /* toggle property */
66
67#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0
68#define _NET_WM_MOVERESIZE_SIZE_TOP 1
69#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2
70#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3
71#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
72#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5
73#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
74#define _NET_WM_MOVERESIZE_SIZE_LEFT 7
75#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */
76#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */
77#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */
78#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */
79
80static Image *ExtractIcon(ScreenInfo *scr, unsigned long *prop, int width,
81 int height);
88static unsigned long EwmhGetWindowProperty(Window w, Atom name, Atom type);
89static void EwmhGetStrut(TwmWindow *twm_win, bool update);
90static void EwmhRemoveStrut(TwmWindow *twm_win);
91static void EwmhSet_NET_WORKAREA(ScreenInfo *scr);
92static int EwmhGet_NET_WM_STATE(TwmWindow *twm_win);
94 int newVal);
95
96#define ALL_WORKSPACES 0xFFFFFFFFU
97
100 long l0, long l1, long l2, long l3, long l4,
101 long mask)
102{
103 XEvent e;
104
105 e.xclient.type = ClientMessage;
106 e.xclient.message_type = messagetype;
107 e.xclient.display = dpy;
108 e.xclient.window = about;
109 e.xclient.format = 32;
110 e.xclient.data.l[0] = l0;
111 e.xclient.data.l[1] = l1;
112 e.xclient.data.l[2] = l2;
113 e.xclient.data.l[3] = l3;
114 e.xclient.data.l[4] = l4;
115
116 XSendEvent(dpy, to, False, mask, &e);
117}
118
123
124static bool caughtError;
125
127{
128 caughtError = true;
129 return 0;
130}
131
132void EwmhInit(void)
133{
135}
136
137/*
138 * Force-generate some event, so that we know the current time.
139 *
140 * Suggested in the ICCCM:
141 * http://tronche.com/gui/x/icccm/sec-2.html#s-2.1
142 */
143
145{
147 struct timespec tosleep;
148 int timeout = 200; /* 0.2 seconds in ms */
149 int found;
150
151 /* Sleep in 10ms chunks */
152 tosleep.tv_sec = 0;
153 tosleep.tv_nsec = (10 * 1000 * 1000);
154
155 if(EventTime > 0) {
156 return;
157 }
158
159 XChangeProperty(dpy, scr->icccm_Window,
161 8, PropModeAppend, NULL, 0);
162
163 while(timeout > 0) {
164 found = XCheckTypedWindowEvent(dpy, scr->icccm_Window, PropertyNotify, &event);
165 if(found) {
166 break;
167 }
169 timeout -= 10;
170 }
171
172 if(found) {
173#ifdef DEBUG_EWMH
174 fprintf(stderr, "GenerateTimestamp: time = %ld, timeout left = %d\n",
175 event.xproperty.time, timeout);
176#endif /* DEBUG_EWMH */
177 if(EventTime < event.xproperty.time) {
178 EventTime = event.xproperty.time;
179 }
180 }
181}
182
183/*
184 * Perform the "replace the window manager" protocol, as vaguely hinted
185 * at by the ICCCM section 4.3.
186 * http://tronche.com/gui/x/icccm/sec-4.html#s-4.3
187 *
188 * We do want to run through this even if we're not running with
189 * --replace ourselves, because it also sets up the bits for other
190 * invocations to --replace us.
191 *
192 * TODO: convert the selection to atom VERSION.
193 */
194static bool EwmhReplaceWM(ScreenInfo *scr)
195{
196 char atomname[32];
197 Atom wmAtom;
199
200 snprintf(atomname, sizeof(atomname), "WM_S%d", scr->screen);
202
204 if(selectionOwner == scr->icccm_Window) {
206 }
207
208 if(selectionOwner != None) {
210
211 /*
212 * Check if that owner still exists, and if it does, we want
213 * StructureNotify-kind events from it.
214 */
215 caughtError = false;
217
219 XSync(dpy, False);
220
222
223 if(caughtError) {
225 }
226 }
227
228 /*
229 * If something else is owning things and we're not running
230 * --replace, give up now and return failure.
231 */
232 if(selectionOwner != None && !CLarg.ewmh_replace) {
233#ifdef DEBUG_EWMH
234 fprintf(stderr, "A window manager is already running on screen %d\n",
235 scr->screen);
236#endif
237 return false;
238 }
239
240 /* We're asked to --replace, so try to do so */
241 XSetSelectionOwner(dpy, wmAtom, scr->icccm_Window, CurrentTime);
242
243 if(XGetSelectionOwner(dpy, wmAtom) != scr->icccm_Window) {
244 fprintf(stderr, "Did not get window manager selection on screen %d\n",
245 scr->screen);
246 return false;
247 }
248
249 /*
250 * If there was a previous selection owner, wait for it
251 * to go away.
252 */
253
254 if(selectionOwner != None) {
255 int timeout = 10 * 1000; /* 10 seconds in ms */
257 struct timespec tosleep;
258
259 /* Sleep in 100ms chunks */
260 tosleep.tv_sec = 0;
261 tosleep.tv_nsec = (100 * 1000 * 1000);
262
263 while(timeout > 0) {
264
266 if(found) {
267 break;
268 }
270 timeout -= 100;
271 }
272
273 if(timeout <= 0) {
274 fprintf(stderr, "Timed out waiting for other window manager "
275 "on screen %d to quit\n",
276 scr->screen);
277 return false;
278 }
279 }
280
281 /*
282 * Send a message to confirm we're now managing the screen.
283 * ICCCM, end of chapter 2, section "Manager Selections".
284 * http://tronche.com/gui/x/icccm/sec-2.html#s-2.8
285 *
286 * ICCCM says StructureNotifyMask,
287 * OpenBox says SubstructureNotifyMask.
288 */
289
291
293 XA_MANAGER, EventTime, wmAtom, scr->icccm_Window, 0, 0,
295
296 return true;
297}
298
299/*
300 * This function is called very early in initialisation.
301 *
302 * Only scr->screen and scr->XineramaRoot are valid: we want to know if
303 * it makes sense to continue with the full initialisation.
304 *
305 * Create the ICCCM window that owns the WM_Sn selection.
306 */
308{
310
311#ifdef DEBUG_EWMH
312 fprintf(stderr, "EwmhInitScreenEarly: XCreateWindow\n");
313#endif
314 attrib.event_mask = PropertyChangeMask;
315 attrib.override_redirect = True;
316 scr->icccm_Window = XCreateWindow(dpy, scr->XineramaRoot,
317 -100, -100, 1, 1, 0,
321 &attrib);
322
323 XMapWindow(dpy, scr->icccm_Window);
324 XLowerWindow(dpy, scr->icccm_Window);
325
326#ifdef DEBUG_EWMH
327 fprintf(stderr, "EwmhInitScreenEarly: call EwmhReplaceWM\n");
328#endif
329 if(!EwmhReplaceWM(scr)) {
330 XDestroyWindow(dpy, scr->icccm_Window);
331 scr->icccm_Window = None;
332
333#ifdef DEBUG_EWMH
334 fprintf(stderr, "EwmhInitScreenEarly: return false\n");
335#endif
336 return false;
337 }
338
339#ifdef DEBUG_EWMH
340 fprintf(stderr, "EwmhInitScreenEarly: return true\n");
341#endif
342 return true;
343}
344
345/*
346 * This initialisation is called late, when scr has been set up
347 * completely.
348 */
350{
351 long data[2];
352
353 /* Set _NET_SUPPORTING_WM_CHECK on root window */
354 data[0] = scr->icccm_Window;
357 32, PropModeReplace,
358 (unsigned char *)data, 1);
359
360 /*
361 * Set properties on the window;
362 * this also belongs with _NET_SUPPORTING_WM_CHECK
363 */
364 XChangeProperty(dpy, scr->icccm_Window,
367 (unsigned char *)"ctwm", 4);
368
369 data[0] = scr->icccm_Window;
370 XChangeProperty(dpy, scr->icccm_Window,
372 32, PropModeReplace,
373 (unsigned char *)data, 1);
374
375 /*
376 * Add supported properties to the root window.
377 */
378 data[0] = 0;
379 data[1] = 0;
382 32, PropModeReplace,
383 (unsigned char *)data, 2);
384
385 data[0] = scr->rootw;
386 data[1] = scr->rooth;
389 32, PropModeReplace,
390 (unsigned char *)data, 2);
391
393
394 if(scr->workSpaceManagerActive) {
395 data[0] = scr->workSpaceMgr.count;
396 }
397 else {
398 data[0] = 1;
399 }
400
403 32, PropModeReplace,
404 (unsigned char *)data, 1);
405
406 if(scr->workSpaceManagerActive) {
407 /* TODO: this is for the first Virtual Screen only... */
408 /*data[0] = scr->workSpaceMgr.workSpaceWindowList->currentwspc->number; */
409 data[0] = 0;
410 }
411 else {
412 data[0] = 0;
413 }
416 32, PropModeReplace,
417 (unsigned char *)data, 1);
418
420
421 long supported[30];
422 int i = 0;
423
451
454 32, PropModeReplace,
455 (unsigned char *)supported, i);
456}
457
458
459#ifdef VSCREEN
460/*
461 * Set up the _NET_VIRTUAL_ROOTS property, which indicates that we're
462 * using virtual root windows.
463 * This applies only if we have multiple virtual screens.
464 *
465 * Also record this as a supported atom in _NET_SUPPORTED.
466 *
467 * Really, our virtual screens (with their virtual root windows) don't quite
468 * fit in the EWMH idiom. Several root window properties (such as
469 * _NET_CURRENT_DESKTOP) are more appropriate on the virtual root windows. But
470 * that is not where other clients would look for them.
471 *
472 * The idea seems to be that the virtual roots as used for workspaces (desktops
473 * in EWMH terminology) are only mapped one at a time.
474 */
476{
477 int numVscreens = scr->numVscreens;
478
479 if(numVscreens > 1) {
480 long *data;
481 long d0;
482 VirtualScreen *vs;
483 int i;
484
485 data = calloc(numVscreens, sizeof(long));
486
487 for(vs = scr->vScreenList, i = 0;
488 vs != NULL && i < numVscreens;
489 vs = vs->next, i++) {
490 data[i] = vs->window;
491 }
492
495 32, PropModeReplace,
496 (unsigned char *)data, numVscreens);
497
498 /* This might fail, but what can we do about it? */
499
500 free(data);
501
505 32, PropModeAppend,
506 (unsigned char *)&d0, 1);
507 }
508}
509#endif
510
511
513{
515
516 /*
517 * Don't delete scr->icccm_Window; let it be deleted automatically
518 * when we terminate the X server connection. A replacement window
519 * manager may want to start working immediately after it has
520 * disappeared.
521 */
522}
523
524/*
525 * Clear everything that needs to be cleared before we exit.
526 */
527
529{
530 int scrnum;
531 ScreenInfo *scr;
532
533 for(scrnum = 0; scrnum < NumScreens; scrnum++) {
534 if((scr = ScreenList[scrnum]) == NULL) {
535 continue;
536 }
538 }
539}
540
541/*
542 * Event handler: lost the WM_Sn selection
543 * (that's the only selection we have).
544 */
545
547{
548#ifdef DEBUG_EWMH
549 fprintf(stderr, "sev->window = %x\n", (unsigned)sev->window);
550#endif
551 DoShutdown();
552}
553
554/*
555 * When accepting client messages to the root window,
556 * be accepting and accept both the real root window and the
557 * current virtual screen.
558 *
559 * Should perhaps also accept any other virtual screen.
560 */
562{
563 if(msg->format != 32) {
564 return false;
565 }
566
567 /* Messages regarding any window */
568 if(msg->message_type == XA__NET_WM_DESKTOP) {
570 return true;
571 }
572 else if(msg->message_type == XA__NET_WM_STATE) {
574 return true;
575 }
576 else if(msg->message_type == XA__NET_ACTIVE_WINDOW) {
578 return true;
579 }
580 else if(msg->message_type == XA__NET_WM_MOVERESIZE) {
582 return true;
583 }
584 else if(msg->message_type == XA__NET_CLOSE_WINDOW) {
586 return true;
587 }
588
589 /* Messages regarding the root window */
590 if(msg->window != Scr->XineramaRoot &&
591 msg->window != Scr->Root) {
592#ifdef DEBUG_EWMH
593 fprintf(stderr, "Received unrecognized client message: %s\n",
594 XGetAtomName(dpy, msg->message_type));
595#endif
596 return false;
597 }
598
599 if(msg->message_type == XA__NET_CURRENT_DESKTOP) {
600 GotoWorkSpaceByNumber(Scr->currentvs, msg->data.l[0]);
601 return true;
602 }
603 else if(msg->message_type == XA__NET_SHOWING_DESKTOP) {
604 ShowBackground(Scr->currentvs, msg->data.l[0] ? 1 : 0);
605 return true;
606 }
607 else {
608#ifdef DEBUG_EWMH
609 fprintf(stderr, "Received unrecognized client message about root window: %s\n",
610 XGetAtomName(dpy, msg->message_type));
611#endif
612 }
613
614 return false;
615}
616
617/*
618 * The format of the _NET_WM_ICON property is
619 *
620 * [0] width
621 * [1] height
622 * height repetitions of
623 * row, which is
624 * width repetitions of
625 * pixel: ARGB
626 * repeat for next size.
627 *
628 * Some icons can be 256x256 CARDINALs which is 65536 CARDINALS!
629 * Therefore we fetch in pieces and skip the pixels of large icons
630 * until needed.
631 *
632 * First scan all sizes. Keep a record of the closest smaller and larger
633 * size. At the end, choose from one of those.
634 * Finally, go and fetch the pixel data.
635 */
636
638{
639 int fetch_offset;
641 int actual_format;
642 unsigned long nitems, bytes_after;
643 unsigned long *prop;
644
645 int wanted_area;
646 int smaller, larger;
647 int offset;
649 int i;
650
651 int width, height;
652
653 fetch_offset = 0;
655 fetch_offset, 8 * 1024, False, XA_CARDINAL,
657 &bytes_after, (unsigned char **)&prop) != Success || nitems == 0) {
658 return NULL;
659 }
660
661 if(actual_format != 32) {
662 XFree(prop);
663 return NULL;
664 }
665
666#ifdef DEBUG_EWMH
667 fprintf(stderr, "_NET_WM_ICON data fetched\n");
668#endif
669 /*
670 * Usually the icons are square, but that is not a rule.
671 * So we measure the area instead.
672 *
673 * Approach wanted size from both directions and at the end,
674 * choose the "nearest".
675 */
676 wanted_area = Scr->PreferredIconWidth * Scr->PreferredIconHeight;
677 smaller = 0;
678 larger = 999999;
679 smaller_offset = -1;
680 larger_offset = -1;
681 i = 0;
682
683 for(;;) {
684 offset = i;
685
686 int w = prop[i++];
687 int h = prop[i++];
688 int size = w * h;
689
690 const int area = w * h;
691
692#ifdef DEBUG_EWMH
693 fprintf(stderr, "[%d+%d] w=%d h=%d\n", fetch_offset, offset, w, h);
694#endif
695
696
697 if(area == wanted_area) {
698#ifdef DEBUG_EWMH
699 fprintf(stderr, "exact match [%d+%d=%d] w=%d h=%d\n", fetch_offset, offset,
700 fetch_offset + offset, w, h);
701#endif /* DEBUG_EWMH */
703 smaller = area;
704 larger_offset = -1;
705 break;
706 }
707 else if(area < wanted_area) {
708 if(area > smaller) {
709#ifdef DEBUG_EWMH
710 fprintf(stderr, "increase smaller, was [%d]\n", smaller_offset);
711#endif /* DEBUG_EWMH */
712 smaller = area;
714 }
715 }
716 else { /* area > wanted_area */
717 if(area < larger) {
718#ifdef DEBUG_EWMH
719 fprintf(stderr, "decrease larger, was [%d]\n", larger_offset);
720#endif /* DEBUG_EWMH */
721 larger = area;
723 }
724 }
725
726 if(i + size + 2 > nitems) {
727#ifdef DEBUG_EWMH
728 fprintf(stderr, "not enough data: %d + %d > %ld \n", i, size, nitems);
729#endif /* DEBUG_EWMH */
730
731 if(i + size + 2 <= nitems + bytes_after / 4) {
732 /* we can fetch some more... */
733 XFree(prop);
734 fetch_offset += i + size;
736 fetch_offset, 8 * 1024, False, XA_CARDINAL,
738 &bytes_after, (unsigned char **)&prop) != Success) {
739 continue;
740 }
741 i = 0;
742 continue;
743 }
744 break;
745 }
746 i += size;
747 }
748
749 /*
750 * Choose which icon approximates our desired size best.
751 */
752 int area = 0;
753 ALLOW_DEAD_STORE(area); // all branches below init it
754
755 if(smaller_offset >= 0) {
756 if(larger_offset >= 0) {
757 /* choose the nearest */
758#ifdef DEBUG_EWMH
759 fprintf(stderr, "choose nearest %d %d\n", smaller, larger);
760#endif /* DEBUG_EWMH */
761 if((double)larger / wanted_area > (double)wanted_area / smaller) {
763 area = smaller;
764 }
765 else {
767 area = larger;
768 }
769 }
770 else {
771 /* choose smaller */
772#ifdef DEBUG_EWMH
773 fprintf(stderr, "choose smaller (only) %d\n", smaller);
774#endif /* DEBUG_EWMH */
776 area = smaller;
777 }
778 }
779 else if(larger_offset >= 0) {
780 /* choose larger */
781#ifdef DEBUG_EWMH
782 fprintf(stderr, "choose larger (only) %d\n", larger);
783#endif /* DEBUG_EWMH */
785 area = larger;
786 }
787 else {
788 /* no icons found at all? */
789#ifdef DEBUG_EWMH
790 fprintf(stderr, "nothing to choose from\n");
791#endif /* DEBUG_EWMH */
792 XFree(prop);
793 return NULL;
794 }
795
796 /*
797 * Now fetch the pixels.
798 */
799
800#ifdef DEBUG_EWMH
801 fprintf(stderr, "offset = %d fetch_offset = %d\n", offset, fetch_offset);
802 fprintf(stderr, "offset + 2 + area = %d fetch_offset + nitems = %ld\n",
803 offset + 2 + area, fetch_offset + nitems);
804#endif /* DEBUG_EWMH */
805 if(offset < fetch_offset ||
806 offset + 2 + area > fetch_offset + nitems) {
807 XFree(prop);
809#ifdef DEBUG_EWMH
810 fprintf(stderr, "refetching from %d\n", fetch_offset);
811#endif /* DEBUG_EWMH */
813 fetch_offset, 2 + area, False, XA_CARDINAL,
815 &bytes_after, (unsigned char **)&prop) != Success) {
816 return NULL;
817 }
818 }
819
820 i = offset - fetch_offset;
821 width = prop[i++];
822 height = prop[i++];
823#ifdef DEBUG_EWMH
824 fprintf(stderr, "Chosen [%d] w=%d h=%d area=%d\n", offset, width, height, area);
825#endif /* DEBUG_EWMH */
826 assert(width * height == area);
827
828 Image *image = ExtractIcon(scr, &prop[i], width, height);
829
830 XFree(prop);
831
832 return image;
833}
834
837
838static void convert_for_16(int w, int x, int y, int argb)
839{
840 int r = (argb >> 16) & 0xFF;
841 int g = (argb >> 8) & 0xFF;
842 int b = (argb >> 0) & 0xFF;
843 buffer_16bpp [y * w + x] = ((r >> 3) << 11) + ((g >> 2) << 5) + (b >> 3);
844}
845
846static void convert_for_32(int w, int x, int y, int argb)
847{
848 buffer_32bpp [y * w + x] = argb & 0x00FFFFFF;
849}
850
851static Image *ExtractIcon(ScreenInfo *scr, unsigned long *prop, int width,
852 int height)
853{
854 XImage *ximage;
855 void (*store_data)(int w, int x, int y, int argb);
856 int x, y, transparency;
857 int rowbytes;
858 unsigned char *maskbits;
859
860 GC gc;
862 Pixmap mask;
863 Image *image;
864 int i;
865
866 ximage = NULL;
867
868 /** XXX sort of duplicated from util.c:LoadJpegImage() */
869 if(scr->d_depth == 16) {
871 buffer_16bpp = malloc(width * height * sizeof(buffer_16bpp[0]));
874 (char *) buffer_16bpp, width, height, 16, width * 2);
875 }
876 else if(scr->d_depth == 24 || scr->d_depth == 32) {
878 buffer_32bpp = malloc(width * height * sizeof(buffer_32bpp[0]));
881 (char *) buffer_32bpp, width, height, 32, width * 4);
882 }
883 else {
884#ifdef DEBUG_EWMH
885 fprintf(stderr, "Screen unsupported depth for 32-bit icon: %d\n", scr->d_depth);
886#endif /* DEBUG_EWMH */
887 XFree(prop);
888 return NULL;
889 }
890 if(ximage == NULL) {
891#ifdef DEBUG_EWMH
892 fprintf(stderr, "cannot create image for icon\n");
893#endif /* DEBUG_EWMH */
894 XFree(prop);
895 return NULL;
896 }
897
898 transparency = 0;
899 rowbytes = (width + 7) / 8;
900 maskbits = calloc(height, rowbytes);
901
902 /*
903 * Copy all ARGB pixels to the pixmap (the RGB part), and the bitmap (the
904 * Alpha, or opaqueness part). If any pixels are transparent, we're going
905 * to need a shape.
906 */
907 i = 0;
908 for(y = 0; y < height; y++) {
909 for(x = 0; x < width; x++) {
910 unsigned long argb = prop[i++];
911 store_data(width, x, y, argb);
912 int opaque = ((argb >> 24) & 0xFF) >= 0x80; /* arbitrary cutoff */
913 if(opaque) {
914 maskbits [rowbytes * y + (x / 8)] |= 0x01 << (x % 8);
915 }
916 else {
917 transparency = 1;
918 }
919 }
920 }
921
922 gc = DefaultGC(dpy, scr->screen);
923 pixret = XCreatePixmap(dpy, scr->Root, width, height, scr->d_depth);
924 XPutImage(dpy, pixret, gc, ximage, 0, 0, 0, 0, width, height);
925 XDestroyImage(ximage); /* also frees buffer_{16,32}bpp */
926 ximage = NULL;
927
928 mask = None;
929 if(transparency) {
930 mask = XCreatePixmapFromBitmapData(dpy, scr->Root, (char *)maskbits,
931 width, height, 1, 0, 1);
932 }
933 free(maskbits);
934
935 image = AllocImage();
936 image->width = width;
937 image->height = height;
938 image->pixmap = pixret;
939 image->mask = mask;
940
941 return image;
942}
943
944/*
945 * Handle a PropertyNotify on _NET_WM_ICON.
946 */
948 TwmWindow *twm_win)
949{
950 unsigned long valuemask; /* mask for create windows */
951 XSetWindowAttributes attributes; /* attributes for create windows */
952 Icon *icon = twm_win->icon;
953 int x;
954
955#ifdef DEBUG_EWMH
956 fprintf(stderr, "EwmhHandlePropertyNotify: NET_WM_ICON\n");
957#endif /* DEBUG_EWMH */
958 /*
959 * If there is no icon yet, we'll look at this property
960 * later, if and when we do create an icon.
961 */
962 if(!icon || icon->match != match_net_wm_icon) {
963#ifdef DEBUG_EWMH
964 fprintf(stderr, "no icon, or not match_net_wm_icon\n");
965#endif /* DEBUG_EWMH */
966 return;
967 }
968
969 Image *image = EwmhGetIcon(Scr, twm_win);
970
971 /* TODO: de-duplicate with handling of XA_WM_HINTS */
972 {
973 Image *old_image = icon->image;
974 icon->image = image;
976 }
977
978
979 if(twm_win->icon->bm_w) {
980 XDestroyWindow(dpy, twm_win->icon->bm_w);
981 }
982
984 attributes.background_pixmap = image->pixmap;
985
986 x = GetIconOffset(twm_win->icon);
987 twm_win->icon->bm_w =
988 XCreateWindow(dpy, twm_win->icon->w, x, 0,
989 twm_win->icon->width,
990 twm_win->icon->height,
991 0, Scr->d_depth,
992 CopyFromParent, Scr->d_visual,
994
995 if(image->mask) {
996 XShapeCombineMask(dpy, twm_win->icon->bm_w, ShapeBounding, 0, 0, image->mask,
997 ShapeSet);
998 XShapeCombineMask(dpy, twm_win->icon->w, ShapeBounding, x, 0, image->mask,
999 ShapeSet);
1000 }
1001 else {
1003
1004 rect.x = x;
1005 rect.y = 0;
1006 rect.width = twm_win->icon->width;
1007 rect.height = twm_win->icon->height;
1009 0, &rect, 1, ShapeUnion, 0);
1010 }
1011 XMapSubwindows(dpy, twm_win->icon->w);
1012 RedoIconName(twm_win);
1013}
1014
1015/*
1016 * Handle a PropertyNotify on _NET_WM_STRUT(PARTIAL).
1017 */
1019 TwmWindow *twm_win)
1020{
1021 EwmhGetStrut(twm_win, true);
1022}
1023
1024/*
1025 * Handle a _NET_WM_STATE ClientMessage.
1026 */
1027static int atomToFlag(Atom a)
1028{
1029#ifdef DEBUG_EWMH
1030# define CRWARN(x) fprintf(stderr, "atomToFlag: ignoring " #x "\n")
1031#else
1032# define CRWARN(x) (void)0
1033#endif
1034#define CHKNRET(st) \
1035 if(a == XA__NET_WM_##st) { \
1036 if(LookInNameList(Scr->EWMHIgnore, #st)) { \
1037 CRWARN(st); \
1038 return 0; \
1039 } \
1040 return EWMH_##st; \
1041 }
1042
1043 /* Check (potentially ignoring) various flags we know */
1050
1051#undef CHKNRET
1052#undef CRWARN
1053
1054 /* Else we don't recognize it */
1055 return 0;
1056}
1057
1058
1059/*
1060 * Handle the NET_WM_STATE client message.
1061 * It can change 1 or 2 values represented in NET_WM_STATE.
1062 * The second change is allowed
1063 * specifically for (re)setting horizontal and vertical maximalisation in
1064 * one go. Treat that as a special case.
1065 */
1067{
1068 Window w = msg->window;
1069 TwmWindow *twm_win;
1071
1072 twm_win = GetTwmWindow(w);
1073
1074 if(twm_win == NULL) {
1075 return;
1076 }
1077
1078 /*
1079 * Due to EWMHIgnore, it's possible to wind up with change1=0 and
1080 * change2=something, so swap 'em if that happens.
1081 */
1082 change1 = atomToFlag(msg->data.l[1]);
1083 change2 = atomToFlag(msg->data.l[2]);
1084 if(change1 == 0 && change2 != 0) {
1085 change1 = change2;
1086 change2 = 0;
1087 }
1089
1090 switch(msg->data.l[0]) {
1092#ifdef DEBUG_EWMH
1093 printf("NET_WM_STATE_REMOVE: ");
1094#endif
1095 newValue = 0;
1096 break;
1097 case NET_WM_STATE_ADD:
1098#ifdef DEBUG_EWMH
1099 printf("NET_WM_STATE_ADD: ");
1100#endif
1101 newValue = change;
1102 break;
1104#ifdef DEBUG_EWMH
1105 printf("NET_WM_STATE_TOGGLE: ");
1106#endif
1107 newValue = ~twm_win->ewmhFlags & change;
1108 break;
1109 default:
1110#ifdef DEBUG_EWMH
1111 printf("invalid operation in NET_WM_STATE: %ld\n", msg->data.l[0]);
1112#endif
1113 return;
1114 }
1115#ifdef DEBUG_EWMH
1116 printf("%s and %s\n", XGetAtomName(dpy, msg->data.l[1]),
1117 XGetAtomName(dpy, msg->data.l[2]));
1118#endif
1119
1120 /*
1121 * Special-case the horizontal and vertical zoom.
1122 * You can turn them both on or both off, but no other combinations
1123 * are done as a unit.
1124 */
1126 (newValue == 0 || newValue == change)) {
1128 }
1129 else {
1131 if(change2 != 0) {
1133 }
1134 }
1135}
1136
1137/*
1138 * change - bitmask of settings that possibly change. Only one bit is
1139 * set in this, with the possible exception of
1140 * *MAXIMIZED_{VERT,HORIZ} which can be set together.
1141 * newValue - bits with the new values; only valid bits are the ones
1142 * in change.
1143 */
1145 int newValue)
1146{
1147 /* Now check what we need to change */
1148
1151 int newZoom = ZOOM_NONE;
1152
1153 switch(newValue) {
1154 case 0:
1155 newZoom = twm_win->zoomed; /* turn off whatever zoom */
1156 break;
1158 newZoom = F_ZOOM;
1159 break;
1162 break;
1165 break;
1168 break;
1169 }
1170 fullzoom(twm_win, newZoom);
1171 }
1172 else if(change & EWMH_STATE_SHADED) {
1173#ifdef DEBUG_EWMH
1174 printf("EWMH_STATE_SHADED: newValue: %d old: %d\n", newValue,
1175 twm_win->ewmhFlags & EWMH_STATE_SHADED);
1176#endif
1177 if((twm_win->ewmhFlags & EWMH_STATE_SHADED) ^ newValue) {
1178 /* Toggle the shade/squeeze state */
1179#ifdef DEBUG_EWMH
1180 printf("EWMH_STATE_SHADED: change it\n");
1181#endif
1182 Squeeze(twm_win);
1183 }
1184 }
1186 /*
1187 * Other changes call into ctwm code, which in turn calls back to
1188 * EWMH code to update the ewmhFlags and the property. This one
1189 * we handle completely internally.
1190 */
1191 unsigned omask = 0, oval = 0;
1192 const int prepri = OtpEffectivePriority(twm_win);
1193
1194 /* Which bits are we changing and what to? */
1195#define DOBIT(fld) do { \
1196 if(change & EWMH_STATE_##fld) { omask |= OTP_AFLAG_##fld; } \
1197 if(newValue & EWMH_STATE_##fld) { oval |= OTP_AFLAG_##fld; } \
1198 } while(0)
1199
1200 DOBIT(ABOVE);
1201 DOBIT(BELOW);
1202
1203#undef DOBIT
1204
1205 /* Update OTP as necessary */
1206 OtpSetAflagMask(twm_win, omask, oval);
1207 if(OtpEffectivePriority(twm_win) != prepri) {
1208 OtpRestackWindow(twm_win);
1209 }
1210
1211 /* Set the EWMH property back on the window */
1212 EwmhSet_NET_WM_STATE(twm_win, change);
1213 }
1214}
1215
1216/*
1217 * Handle the _NET_ACTIVE_WINDOW client message.
1218 * Pagers would send such a message to "activate" a window.
1219 *
1220 * What does "activate" really mean? It isn't properly described.
1221 *
1222 * Let's presume that it means that the window is de-iconified and gets
1223 * focus. The mouse may be moved to it (but not all window button apps
1224 * do that). But is it always raised or should that depend on the
1225 * RaiseOnWarp option?
1226 */
1228{
1229 Window w = msg->window;
1230 TwmWindow *twm_win;
1231
1232 twm_win = GetTwmWindow(w);
1233
1234 if(twm_win == NULL) {
1235 return;
1236 }
1237
1238 if(!twm_win->mapped) {
1239 DeIconify(twm_win);
1240 }
1241#if 0
1242 WarpToWindow(twm_win, Scr->RaiseOnWarp /* True ? */);
1243#else
1244 /*
1245 * Keep the mouse pointer where it is (typically the dock).
1246 * WarpToWindow() would change the current workspace if needed to go
1247 * to the window. But pagers would only send this message for
1248 * windows in the current workspace, I expect.
1249 */
1250 if(Scr->RaiseOnWarp) {
1251 AutoRaiseWindow(twm_win);
1252 }
1253 SetFocus(twm_win, msg->data.l[1]);
1254#endif
1255}
1256
1257/*
1258 * Ugly implementation of _NET_WM_MOVERESIZE.
1259 *
1260 * window = window to be moved or resized
1261 * message_type = _NET_WM_MOVERESIZE
1262 * format = 32
1263 * data.l[0] = x_root
1264 * data.l[1] = y_root
1265 * data.l[2] = direction
1266 * data.l[3] = button
1267 * data.l[4] = source indication
1268 */
1270{
1271 TwmWindow *twm_win;
1272
1273 twm_win = GetTwmWindow(msg->window);
1274
1275 if(twm_win == NULL) {
1276 return;
1277 }
1278
1279 if(!twm_win->mapped) {
1280 DeIconify(twm_win);
1281 }
1282
1283 switch(msg->data.l[2]) {
1293 /* Fake up as if we triggered f.resize on it */
1295
1296 /*
1297 * The resize won't actually start until we cross the cursor
1298 * over a border. Perhaps we should find the nearest corner,
1299 * and pre-warp the cursor there? That may be less friendly
1300 * for the user, since it might not be as predictable, and
1301 * having the cursor zoom off without warning is probably a
1302 * little surprising...
1303 */
1304 ExecuteFunction(F_RESIZE, "", twm_win->frame, twm_win,
1305 &xevent, C_WINDOW, false);
1306
1307 /*
1308 * It's not guaranteed that this actually began as a button
1309 * press, but our implementation is expecting the button to
1310 * be held down all through the move, so that
1311 * ExecuteFunction() won't actually end until there's a
1312 * button release of some kind, which will trigger
1313 * HandleButtonRelease() properly. So we don't need to call
1314 * it ourselves.
1315 */
1316
1317 break;
1318 }
1321 /* Fake up as if we triggered f.move on it */
1323 ExecuteFunction(F_MOVE, "", twm_win->frame, twm_win,
1324 &xevent, C_WINDOW, false);
1325
1326 /* X-ref HandleButtonRelease() discussion above */
1327 break;
1328 }
1330 /*
1331 * TODO: check if the twm_win is the same.
1332 * TODO: check how to make this actually work.
1333 *
1334 * As currently implemented, I don't believe we ever need to
1335 * do anything here. All the needed cleanup should happen in
1336 * our ButtonRelease handler.
1337 */
1338 break;
1339 }
1340}
1341
1342static XEvent
1344{
1345 XEvent xevent;
1346 Window root = twm_win->parent_vs->window;
1347 Window child = twm_win->w;
1348 int x_root = twm_win->frame_x;
1349 int y_root = twm_win->frame_y;
1350 int x_win = 0;
1351 int y_win = 0;
1352 unsigned int dummy_mask;
1353
1354 /* Find the pointer */
1355 XQueryPointer(dpy, twm_win->frame, &root, &child, &x_root, &y_root,
1356 &x_win, &y_win, &dummy_mask);
1357
1358 /* Synthesize a button event */
1359 xevent.type = ButtonPress;
1360 xevent.xbutton.root = root;
1361 xevent.xbutton.window = child;
1362 xevent.xbutton.x_root = x_root;
1363 xevent.xbutton.y_root = y_root;
1364 xevent.xbutton.x = x_win;
1365 xevent.xbutton.y = y_win;
1366 xevent.xbutton.time = EventTime;
1367
1368 return xevent;
1369}
1370
1371
1372/*
1373 * Implementation of _NET_CLOSE_WINDOW
1374 *
1375 * window = window to be closed
1376 * message_type = _NET_CLOSE_WINDOW
1377 * format = 32
1378 * data.l[0] = timestamp
1379 * data.l[1] = source indication:
1380 * 0 Clients that support only older version of this spec
1381 * 1 for normal applications, and
1382 * 2 for pagers and other Clients that represent direct user actions
1383 * data.l[2] = 0
1384 * data.l[3] = 0
1385 * data.l[4] = 0
1386 */
1388{
1390
1391 tmp_win = GetTwmWindow(msg->window);
1392
1393 if(tmp_win != NULL) {
1394 ButtonPressed = -1;
1396 (XEvent *)msg, C_NO_CONTEXT, 0);
1397 }
1398}
1399
1400/*
1401 * Handle any PropertyNotify.
1402 */
1404{
1405 if(event->atom == XA__NET_WM_ICON) {
1407 return 1;
1408 }
1409 else if(event->atom == XA__NET_WM_STRUT_PARTIAL ||
1410 event->atom == XA__NET_WM_STRUT) {
1412 return 1;
1413 }
1414 else if(event->atom == XA__NET_WM_NAME) {
1415 char *prop = GetWMPropertyString(twm_win->w, XA__NET_WM_NAME);
1416 if(prop == NULL) {
1417 FreeWMPropertyString(twm_win->names.net_wm_name);
1418 twm_win->names.net_wm_name = NULL;
1419 apply_window_name(twm_win);
1420 return 1;
1421 }
1422
1423 if(twm_win->names.net_wm_name != NULL
1424 && strcmp(twm_win->names.net_wm_name, prop) == 0) {
1425 /* No change, just free and skip out */
1426 free(prop);
1427 return 1;
1428 }
1429
1430 /* It's changing, free the old and bring in the new */
1431 FreeWMPropertyString(twm_win->names.net_wm_name);
1432 twm_win->names.net_wm_name = prop;
1433
1434 /* Kick the reset process */
1435 apply_window_name(twm_win);
1436 return 1;
1437 }
1438 else if(event->atom == XA__NET_WM_ICON_NAME) {
1440 if(prop == NULL) {
1441 FreeWMPropertyString(twm_win->names.net_wm_icon_name);
1442 twm_win->names.net_wm_icon_name = NULL;
1443 apply_window_icon_name(twm_win);
1444 return 1;
1445 }
1446
1447 if(twm_win->names.net_wm_icon_name != NULL
1448 && strcmp(twm_win->names.net_wm_icon_name, prop) == 0) {
1449 /* No change, just free and skip out */
1450 free(prop);
1451 return 1;
1452 }
1453
1454 /* It's changing, free the old and bring in the new */
1455 FreeWMPropertyString(twm_win->names.net_wm_icon_name);
1456 twm_win->names.net_wm_icon_name = prop;
1457
1458 /* Kick the reset process */
1459 apply_window_icon_name(twm_win);
1460 return 1;
1461 }
1462
1463 return 0;
1464}
1465
1466/*
1467 * Set the _NET_WM_DESKTOP property for the current workspace.
1468 */
1470{
1471 WorkSpace *ws;
1472
1473 VirtualScreen *vs = twm_win->vs;
1474 if(vs != NULL) {
1475 ws = vs->wsw->currentwspc;
1476 }
1477 else {
1478 ws = NULL;
1479 }
1480
1481 EwmhSet_NET_WM_DESKTOP_ws(twm_win, ws);
1482}
1483
1484/*
1485 * Set the _NET_WM_DESKTOP property for the given workspace.
1486 */
1488{
1489 unsigned long workspaces[MAXWORKSPACE];
1490 int n = 0;
1491
1492 if(!Scr->workSpaceManagerActive) {
1493 workspaces[n++] = 0;
1494 }
1495 else if(twm_win->occupation == fullOccupation) {
1497 }
1498 else {
1499 /*
1500 * Our windows can occupy multiple workspaces ("virtual desktops" in
1501 * EWMH terminology) at once. Extend the _NET_WM_DESKTOP property
1502 * by setting it to multiple CARDINALs if this occurs.
1503 * Put the currently visible workspace (if any) first, since typical
1504 * pager apps don't know about this.
1505 */
1506 int occupation = twm_win->occupation;
1507
1508 /*
1509 * Set visible workspace number.
1510 */
1511 if(ws != NULL) {
1512 int wsn = ws->number;
1513
1514 workspaces[n++] = wsn;
1515 occupation &= ~(1 << wsn);
1516 }
1517
1518 /*
1519 * Set any other workspace numbers.
1520 */
1521 if(occupation != 0) {
1522 int i;
1523 int mask = 1;
1524
1525 for(i = 0; i < MAXWORKSPACE; i++) {
1526 if(occupation & mask) {
1527 workspaces[n++] = i;
1528 }
1529 mask <<= 1;
1530 }
1531 }
1532 }
1533
1534 XChangeProperty(dpy, twm_win->w,
1536 32, PropModeReplace,
1537 (unsigned char *)workspaces, n);
1538}
1539
1540
1541static unsigned long EwmhGetWindowProperty(Window w, Atom name, Atom type)
1542{
1544 int actual_format;
1545 unsigned long nitems, bytes_after;
1546 unsigned long *prop;
1547 unsigned long value;
1548
1549 if(XGetWindowProperty(dpy, w, name,
1550 0, 1, False, type,
1552 &bytes_after, (unsigned char **)&prop) != Success) {
1553 return 0;
1554 }
1555
1556 if(actual_format == 32) {
1557 if(nitems >= 1) {
1558 value = prop[0];
1559 }
1560 else {
1561 value = 0;
1562 }
1563 }
1564 else {
1565 value = 0;
1566 }
1567
1568 XFree(prop);
1569 return value;
1570}
1571
1572/*
1573 * Simple function to get multiple properties of format 32.
1574 * If it fails, returns NULL, and *nitems_return == 0.
1575 */
1576
1577static unsigned long *EwmhGetWindowProperties(Window w, Atom name, Atom type,
1578 unsigned long *nitems_return)
1579{
1581 int actual_format;
1582 unsigned long bytes_after;
1583 unsigned long *prop;
1584
1585 if(XGetWindowProperty(dpy, w, name,
1586 0, 8192, False, type,
1588 &bytes_after, (unsigned char **)&prop) != Success) {
1589 *nitems_return = 0;
1590 return NULL;
1591 }
1592
1593 if(actual_format != 32) {
1594 XFree(prop);
1595 prop = NULL;
1596 *nitems_return = 0;
1597 }
1598
1599 return prop;
1600}
1601
1603{
1604 unsigned long nitems;
1605 unsigned long *prop;
1606 int occupation;
1607
1608 occupation = 0;
1609
1610 prop = EwmhGetWindowProperties(twm_win->w,
1612
1613 if(prop) {
1614 int i;
1615 for(i = 0; i < nitems; i++) {
1616 unsigned int val = prop[i];
1617 if(val == ALL_WORKSPACES) {
1618 occupation = fullOccupation;
1619 }
1620 else if(val < Scr->workSpaceMgr.count) {
1621 occupation |= 1 << val;
1622 }
1623 else {
1624 occupation |= 1 << (Scr->workSpaceMgr.count - 1);
1625 }
1626 }
1627
1628 occupation &= fullOccupation;
1629
1630 XFree(prop);
1631 }
1632
1633 return occupation;
1634}
1635
1636/*
1637 * The message to change the desktop of a window doesn't recognize
1638 * that it may be in more than one.
1639 *
1640 * Therefore the following heuristic is applied:
1641 * - the window is removed from the workspace where it is visible (if any);
1642 * - it is added to the given workspace;
1643 * - other occupation bits are left unchanged.
1644 *
1645 * If asked to put it on a too high numbered workspace, put it on
1646 * the highest possible.
1647 */
1649{
1650 Window w = msg->window;
1651 TwmWindow *twm_win;
1652 int occupation;
1653 VirtualScreen *vs;
1654 unsigned int val;
1655
1656 twm_win = GetTwmWindow(w);
1657
1658 if(twm_win == NULL) {
1659 return;
1660 }
1661
1662 occupation = twm_win->occupation;
1663
1664 /* Remove from visible workspace */
1665 if((vs = twm_win->vs) != NULL) {
1666 occupation &= ~(1 << vs->wsw->currentwspc->number);
1667 }
1668
1669 val = (unsigned int)msg->data.l[0];
1670
1671 /* Add to requested workspace (or to all) */
1672 if(val == ALL_WORKSPACES) {
1673 occupation = fullOccupation;
1674 }
1675 else if(val < Scr->workSpaceMgr.count) {
1676 occupation |= 1 << val;
1677 }
1678 else {
1679 occupation |= 1 << (Scr->workSpaceMgr.count - 1);
1680 }
1681
1682 ChangeOccupation(twm_win, occupation);
1683}
1684
1685/*
1686 * Delete all properties that should be removed from a withdrawn
1687 * window.
1688 */
1690{
1692}
1693
1694/*
1695 * Add a new window to _NET_CLIENT_LIST.
1696 * Newer windows are always added at the end.
1697 *
1698 * Look at new_win->iconmanagerlist as an optimization for
1699 * !LookInList(Scr->IconMgrNoShow, new_win->name, &new_win->class)).
1700 */
1702{
1703 if(Scr->ewmh_CLIENT_LIST_size == 0) {
1704 return;
1705 }
1706 if(new_win->iconmanagerlist != NULL &&
1707 !new_win->iswspmgr &&
1708 !new_win->isiconmgr) {
1709 Scr->ewmh_CLIENT_LIST_used++;
1710 if(Scr->ewmh_CLIENT_LIST_used > Scr->ewmh_CLIENT_LIST_size) {
1711 long *tp;
1712 int tsz = Scr->ewmh_CLIENT_LIST_size;
1713
1714 Scr->ewmh_CLIENT_LIST_size *= 2;
1715 tp = realloc(Scr->ewmh_CLIENT_LIST,
1716 sizeof(long) * Scr->ewmh_CLIENT_LIST_size);
1717 if(tp == NULL) {
1718 Scr->ewmh_CLIENT_LIST_size = tsz;
1719 fprintf(stderr, "Unable to allocate memory for EWMH client list.\n");
1720 return;
1721 }
1722 Scr->ewmh_CLIENT_LIST = tp;
1723 }
1724 if(Scr->ewmh_CLIENT_LIST) {
1725 Scr->ewmh_CLIENT_LIST[Scr->ewmh_CLIENT_LIST_used - 1] = new_win->w;
1726 }
1727 else {
1728 Scr->ewmh_CLIENT_LIST_size = 0;
1729 fprintf(stderr, "Unable to allocate memory for EWMH client list.\n");
1730 return;
1731 }
1733 PropModeReplace, (unsigned char *)Scr->ewmh_CLIENT_LIST,
1734 Scr->ewmh_CLIENT_LIST_used);
1735 }
1736}
1737
1739{
1740 int i;
1741
1742 if(old_win->ewmhFlags & EWMH_HAS_STRUT) {
1744 }
1745
1746 /*
1747 * Remove the window from _NET_CLIENT_LIST.
1748 */
1749 if(Scr->ewmh_CLIENT_LIST_size == 0) {
1750 return;
1751 }
1752 for(i = Scr->ewmh_CLIENT_LIST_used - 1; i >= 0; i--) {
1753 if(Scr->ewmh_CLIENT_LIST[i] == old_win->w) {
1754 memmove(&Scr->ewmh_CLIENT_LIST[i],
1755 &Scr->ewmh_CLIENT_LIST[i + 1],
1756 (Scr->ewmh_CLIENT_LIST_used - 1 - i) * sizeof(Scr->ewmh_CLIENT_LIST[0]));
1757 Scr->ewmh_CLIENT_LIST_used--;
1758 if(Scr->ewmh_CLIENT_LIST_used &&
1759 (Scr->ewmh_CLIENT_LIST_used * 3) < Scr->ewmh_CLIENT_LIST_size) {
1760 Scr->ewmh_CLIENT_LIST_size /= 2;
1761 Scr->ewmh_CLIENT_LIST = realloc(Scr->ewmh_CLIENT_LIST,
1762 sizeof((Scr->ewmh_CLIENT_LIST[0])) * Scr->ewmh_CLIENT_LIST_size);
1763 /* memory shrinking, shouldn't have problems */
1764 }
1765 break;
1766 }
1767 }
1768 /* If window was not found, there is no need to update the property. */
1769 if(i >= 0) {
1771 PropModeReplace, (unsigned char *)Scr->ewmh_CLIENT_LIST,
1772 Scr->ewmh_CLIENT_LIST_used);
1773 }
1774}
1775
1776/*
1777 * Similar to EwmhAddClientWindow() and EwmhDeleteClientWindow(),
1778 * but the windows are in stacking order.
1779 * Therefore we look at the OTPs, which are by definition in the correct order.
1780 */
1781
1783{
1784 int size;
1785 unsigned long *prop;
1786 TwmWindow *twm_win;
1787 int i;
1788
1789 /* Expect the same number of windows as in the _NET_CLIENT_LIST */
1790 size = Scr->ewmh_CLIENT_LIST_used + 10;
1791 prop = calloc(size, sizeof(unsigned long));
1792 if(prop == NULL) {
1793 return;
1794 }
1795
1796 i = 0;
1797 for(twm_win = OtpBottomWin();
1798 twm_win != NULL;
1799 twm_win = OtpNextWinUp(twm_win)) {
1800 if(twm_win->iconmanagerlist != NULL &&
1801 !twm_win->iswspmgr &&
1802 !twm_win->isiconmgr) {
1803 prop[i] = twm_win->w;
1804 i++;
1805 if(i > size) {
1806 fprintf(stderr, "Too many stacked windows\n");
1807 break;
1808 }
1809 }
1810 }
1811
1812 if(i != Scr->ewmh_CLIENT_LIST_used) {
1813 fprintf(stderr, "Incorrect number of stacked windows: %d (expected %d)\n",
1814 i, Scr->ewmh_CLIENT_LIST_used);
1815 }
1816
1818 PropModeReplace, (unsigned char *)prop, i);
1819
1820 free(prop);
1821}
1822
1824{
1825 unsigned long prop[1];
1826
1827 prop[0] = w;
1828
1830 PropModeReplace, (unsigned char *)prop, 1);
1831}
1832
1833/*
1834 * Get window properties as relevant when the window is initially mapped.
1835 *
1836 * So far, only NET_WM_WINDOW_TYPE and _NET_WM_STRUT_PARTIAL.
1837 * In particular, most of the initial value of _NET_WM_STATE is ignored. TODO.
1838 *
1839 * Also do any generic initialisation needed to EWMH-specific fields
1840 * in a TwmWindow.
1841 */
1843{
1844 twm_win->ewmhFlags = 0;
1845
1847
1848 if(type == XA__NET_WM_WINDOW_TYPE_DESKTOP) {
1849 twm_win->ewmhWindowType = wt_Desktop;
1850 }
1851 else if(type == XA__NET_WM_WINDOW_TYPE_DOCK) {
1852 twm_win->ewmhWindowType = wt_Dock;
1853 }
1854 else {
1855 twm_win->ewmhWindowType = wt_Normal;
1856 }
1857 EwmhGetStrut(twm_win, false);
1858 /* Only the 3 listed states are supported for now */
1859 twm_win->ewmhFlags |= EwmhGet_NET_WM_STATE(twm_win) &
1861}
1862
1863/* Only used in initially mapping a window */
1865{
1866 switch(twm_win->ewmhWindowType) {
1867 case wt_Desktop:
1868 return EWMH_PRI_DESKTOP;
1869 case wt_Dock:
1870 return EWMH_PRI_DOCK;
1871 default:
1872 return 0;
1873 }
1874}
1875
1877{
1878 switch(twm_win->ewmhWindowType) {
1879 case wt_Desktop:
1880 case wt_Dock:
1881 return false;
1882 default:
1883 return true;
1884 }
1885}
1886
1888{
1889 switch(twm_win->ewmhWindowType) {
1890 case wt_Desktop:
1891 case wt_Dock:
1892 return false;
1893 default:
1894 return true;
1895 }
1896}
1897
1899{
1900 switch(twm_win->ewmhWindowType) {
1901 case wt_Desktop:
1902 case wt_Dock:
1903 return false;
1904 default:
1905 return true;
1906 }
1907}
1908
1909/*
1910 * Recalculate the effective border values from the remembered struts.
1911 * Interestingly it is not documented how to do that.
1912 * Usually only one dock is present on each side, so it shouldn't matter
1913 * too much, but I presume that maximizing the values is the thing to do.
1914 */
1915static void EwmhRecalculateStrut(void)
1916{
1917 int left = 0;
1918 int right = 0;
1919 int top = 0;
1920 int bottom = 0;
1921 EwmhStrut *strut = Scr->ewmhStruts;
1922
1923 while(strut != NULL) {
1924 left = max(left, strut->left);
1925 right = max(right, strut->right);
1926 top = max(top, strut->top);
1927 bottom = max(bottom, strut->bottom);
1928
1929 strut = strut->next;
1930 }
1931
1932 Scr->BorderLeft = left;
1933 Scr->BorderRight = right;
1934 Scr->BorderTop = top;
1935 Scr->BorderBottom = bottom;
1936
1937 // Bordered layout may have changed
1938 Scr->BorderedLayout = RLayoutCopyCropped(Scr->Layout,
1939 left, right, top, bottom);
1940 if(Scr->BorderedLayout == NULL) {
1941 Scr->BorderedLayout = Scr->Layout; // nothing to crop
1942 }
1943
1945}
1946/*
1947 * Check _NET_WM_STRUT_PARTIAL or _NET_WM_STRUT.
1948 * These are basically automatic settings for Border{Left,Right,Top,Bottom}.
1949 *
1950 * If any values are found, collect them in a list of strut values
1951 * belonging to Scr. When a window is added or removed that has struts,
1952 * the new effective value must be calculated. The expectation is that
1953 * at most a handful of windows will have struts.
1954 *
1955 * If update is true, this is called as an update for an existing window.
1956 */
1957static void EwmhGetStrut(TwmWindow *twm_win, bool update)
1958{
1959 unsigned long nitems;
1960 unsigned long *prop;
1962
1963 prop = EwmhGetWindowProperties(twm_win->w,
1965 &nitems);
1966 if(prop == NULL) {
1967 prop = EwmhGetWindowProperties(twm_win->w,
1969 if(prop == NULL) {
1970 return;
1971 }
1972 }
1973
1974
1975 if(nitems < 4) {
1976#ifdef DEBUG_EWMH
1977 /* This happens a lot, despite returning Success ??? */
1978 printf("struts: prop = %p, nitems = %ld\n", prop, nitems);
1979#endif
1980 XFree(prop);
1981 return;
1982 }
1983#ifdef DEBUG_EWMH
1984 printf("struts: left %ld, right %ld, top %ld, bottom %ld\n",
1985 prop[0], prop[1], prop[2], prop[3]);
1986#endif
1987
1988 /*
1989 * If there were no struts before, the user configured margins are set
1990 * in Border{Left,Right,Top,Bottom}. In order not to lose those values
1991 * when recalculating them, convert them to struts for a dummy window.
1992 */
1993
1994 if(Scr->ewmhStruts == NULL &&
1995 (Scr->BorderLeft |
1996 Scr->BorderRight |
1997 Scr->BorderTop |
1998 Scr->BorderBottom) != 0) {
1999 strut = calloc(1, sizeof(EwmhStrut));
2000 if(strut == NULL) {
2001 XFree(prop);
2002 return;
2003 }
2004
2005 strut->next = NULL;
2006 strut->win = NULL;
2007 strut->left = Scr->BorderLeft;
2008 strut->right = Scr->BorderRight;
2009 strut->top = Scr->BorderTop;
2010 strut->bottom = Scr->BorderBottom;
2011
2012 Scr->ewmhStruts = strut;
2013 }
2014
2015 strut = NULL;
2016
2017 /*
2018 * Find the struts of the window that we're supposed to be updating.
2019 * If not found, there is no problem: we'll just allocate a new
2020 * record.
2021 */
2022
2023 if(update) {
2024 strut = Scr->ewmhStruts;
2025
2026 while(strut != NULL) {
2027 if(strut->win == twm_win) {
2028 break;
2029 }
2030 strut = strut->next;
2031 }
2032 }
2033
2034 /*
2035 * If needed, allocate a new struts record and link it in.
2036 */
2037 if(strut == NULL) {
2038 strut = calloc(1, sizeof(EwmhStrut));
2039 if(strut == NULL) {
2040 XFree(prop);
2041 return;
2042 }
2043
2044 strut->next = Scr->ewmhStruts;
2045 Scr->ewmhStruts = strut;
2046 }
2047
2048 strut->win = twm_win;
2049 strut->left = prop[0];
2050 strut->right = prop[1];
2051 strut->top = prop[2];
2052 strut->bottom = prop[3];
2053
2054 XFree(prop);
2055
2056 /*
2057 * Mark this window as having contributed some struts.
2058 * This can be checked and undone when the window is deleted.
2059 */
2060 twm_win->ewmhFlags |= EWMH_HAS_STRUT;
2061
2063}
2064
2065/*
2066 * Remove the struts associated with the given window from the
2067 * remembered list. If found, recalculate the effective borders.
2068 */
2069static void EwmhRemoveStrut(TwmWindow *twm_win)
2070{
2071 EwmhStrut **prev = &Scr->ewmhStruts;
2072 EwmhStrut *strut = Scr->ewmhStruts;
2073
2074 while(strut != NULL) {
2075 if(strut->win == twm_win) {
2076 twm_win->ewmhFlags &= ~EWMH_HAS_STRUT;
2077
2078 *prev = strut->next;
2079 free(strut);
2080
2082
2083 break;
2084 }
2085 prev = &strut->next;
2086 strut = strut->next;
2087 }
2088}
2089
2090
2091/**
2092 * Set _NET_FRAME_EXTENTS property.
2093 * This tells the client how much space is being taken up by the window
2094 * decorations. Some clients may need this information to position other
2095 * windows on top of themselves. e.g., Firefox's form autofill and
2096 * context menu will be positioned a bit wrong (high, by the height of
2097 * the titlebar) without this.
2098 */
2100{
2101 long data[4];
2102 const long w = twm_win->frame_bw3D + twm_win->frame_bw;
2103
2104 data[0] = w; // left
2105 data[1] = w; // right
2106 data[2] = twm_win->title_height + w; // top
2107 data[3] = w; // bottom
2108
2109 XChangeProperty(dpy, twm_win->w,
2111 32, PropModeReplace,
2112 (unsigned char *)data, 4);
2113}
2114
2115
2117{
2118 unsigned long prop[1];
2119
2120 prop[0] = state;
2121
2123 32,
2124 PropModeReplace, (unsigned char *)prop, 1);
2125}
2126
2127/*
2128 * Set _NET_WM_STATE.
2129 *
2130 * TwmWindow.ewmhFlags keeps track of the atoms that should be in
2131 * the list, so that we don't have to fetch or recalculate them all.
2132 *
2133 * XXX It's not clear that the theoretical performance gain and edge-case
2134 * bug avoidance of the 'changes' arg is worth the complexity and
2135 * edge-case bug creation it brings. Consider removing it.
2136 */
2138{
2139 unsigned long prop[10];
2140 int flags;
2141 int i;
2142
2144 int newFlags = 0;
2145
2146 switch(twm_win->zoomed) {
2147 case F_FULLZOOM:
2150 break;
2151 case F_ZOOM:
2152 case F_LEFTZOOM:
2153 case F_RIGHTZOOM:
2155 break;
2156 case F_HORIZOOM:
2157 case F_TOPZOOM:
2158 case F_BOTTOMZOOM:
2160 break;
2161 case F_FULLSCREENZOOM:
2163 break;
2164 }
2165
2166 twm_win->ewmhFlags &= ~(EWMH_STATE_MAXIMIZED_VERT |
2169 twm_win->ewmhFlags |= newFlags;
2170 }
2171
2173 if(twm_win->squeezed) {
2174 twm_win->ewmhFlags |= EWMH_STATE_SHADED;
2175 }
2176 else {
2177 twm_win->ewmhFlags &= ~EWMH_STATE_SHADED;
2178 }
2179 }
2180
2182 int pri = OtpEffectiveDisplayPriority(twm_win);
2183
2184 twm_win->ewmhFlags &= ~(EWMH_STATE_ABOVE | EWMH_STATE_BELOW);
2185
2186 /*
2187 * If it's a DOCK or DESKTOP, and where we expect those to be, we
2188 * consider that there's nothing to tell it. Otherwise, we tell
2189 * it ABOVE/BELOW based on where it effectively is.
2190 */
2191 if(twm_win->ewmhWindowType == wt_Dock && pri == EWMH_PRI_DOCK) {
2192 pri = 0;
2193 }
2194 if(twm_win->ewmhWindowType == wt_Desktop && pri == EWMH_PRI_DESKTOP) {
2195 pri = 0;
2196 }
2197
2198 if(pri > 0) {
2199 twm_win->ewmhFlags |= EWMH_STATE_ABOVE;
2200 }
2201 else if(pri < 0) {
2202 twm_win->ewmhFlags |= EWMH_STATE_BELOW;
2203 }
2204 }
2205
2206 flags = twm_win->ewmhFlags;
2207 i = 0;
2208
2209 if(flags & EWMH_STATE_MAXIMIZED_VERT) {
2211 }
2212 if(flags & EWMH_STATE_MAXIMIZED_HORZ) {
2214 }
2215 if(flags & EWMH_STATE_FULLSCREEN) {
2217 }
2218 if(flags & EWMH_STATE_SHADED) {
2220 }
2221 if(flags & EWMH_STATE_ABOVE) {
2223 }
2224 if(flags & EWMH_STATE_BELOW) {
2226 }
2227
2229 PropModeReplace, (unsigned char *)prop, i);
2230}
2231
2232/*
2233 * Get the initial state of _NET_WM_STATE.
2234 *
2235 * Only some of the flags are supported when initially creating a window.
2236 */
2238{
2239 int flags = 0;
2240 unsigned long *prop;
2241 unsigned long nitems;
2242 int i;
2243
2245
2246 if(prop) {
2247 for(i = 0; i < nitems; i++) {
2248 flags |= atomToFlag(prop[i]);
2249 }
2250
2251 XFree(prop);
2252 }
2253
2254 return flags;
2255}
2256
2257/*
2258 * Set _NET_WORKAREA.
2259 */
2261{
2262 unsigned long prop[4];
2263
2264 /* x */ prop[0] = scr->BorderLeft;
2265 /* y */ prop[1] = scr->BorderTop;
2266 /* w */ prop[2] = scr->rootw - scr->BorderLeft - scr->BorderRight;
2267 /* h */ prop[3] = scr->rooth - scr->BorderTop - scr->BorderBottom;
2268
2269 XChangeProperty(dpy, Scr->XineramaRoot, XA__NET_WORKAREA, XA_CARDINAL, 32,
2270 PropModeReplace, (unsigned char *)prop, 4);
2271}
static int PlaceX
Definition add_window.c:82
ctwm_cl_args CLarg
Definition clargs.c:27
Display * dpy
Definition ctwm_main.c:84
#define C_WINDOW
Definition ctwm.h:75
#define C_NO_CONTEXT
Definition ctwm.h:74
#define ZOOM_NONE
Definition ctwm.h:111
#define ALLOW_DEAD_STORE(x)
Definition ctwm.h:379
int NumScreens
How many Screens are on our display.
Definition ctwm_main.c:89
#define Scr
ScreenInfo ** ScreenList
List of ScreenInfo structs for each Screen.
Definition ctwm_main.c:92
void DoShutdown(void)
Cleanup and exit ctwm.
Time EventTime
Definition event_core.c:79
int ButtonPressed
Definition event_core.c:93
void AutoRaiseWindow(TwmWindow *tmp)
Definition event_utils.c:27
static void EwmhRemoveStrut(TwmWindow *twm_win)
Definition ewmh.c:2069
#define _NET_WM_MOVERESIZE_SIZE_TOP
Definition ewmh.c:68
void EwmhInitScreenLate(ScreenInfo *scr)
Definition ewmh.c:349
void EwmhUnmapNotify(TwmWindow *twm_win)
Definition ewmh.c:1689
static Image * ExtractIcon(ScreenInfo *scr, unsigned long *prop, int width, int height)
Definition ewmh.c:851
static int EwmhGet_NET_WM_STATE(TwmWindow *twm_win)
Definition ewmh.c:2237
#define CHKNRET(st)
int EwmhGetInitPriority(TwmWindow *twm_win)
Definition ewmh.c:1864
static void EwmhSet_NET_WORKAREA(ScreenInfo *scr)
Definition ewmh.c:2260
void EwmhSet_NET_WM_DESKTOP_ws(TwmWindow *twm_win, WorkSpace *ws)
Definition ewmh.c:1487
void EwmhSet_NET_FRAME_EXTENTS(TwmWindow *twm_win)
Set _NET_FRAME_EXTENTS property.
Definition ewmh.c:2099
static void convert_for_32(int w, int x, int y, int argb)
Definition ewmh.c:846
static void EwmhGetStrut(TwmWindow *twm_win, bool update)
Definition ewmh.c:1957
bool EwmhClientMessage(XClientMessageEvent *msg)
Definition ewmh.c:561
static unsigned long * EwmhGetWindowProperties(Window w, Atom name, Atom type, unsigned long *nitems_return)
Definition ewmh.c:1577
static bool caughtError
Definition ewmh.c:124
void EwmhTerminate(void)
Definition ewmh.c:528
static void EwmhTerminateScreen(ScreenInfo *scr)
Definition ewmh.c:512
#define NET_WM_STATE_ADD
Definition ewmh.c:64
#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT
Definition ewmh.c:67
#define DOBIT(fld)
Atom XEWMHAtom[NUM_EWMH_XATOMS]
Definition ewmh.c:61
static uint16_t * buffer_16bpp
Definition ewmh.c:835
static void EwmhClientMessage_NET_ACTIVE_WINDOW(XClientMessageEvent *msg)
Definition ewmh.c:1227
static void EwmhClientMessage_NET_WM_DESKTOP(XClientMessageEvent *msg)
Definition ewmh.c:1648
#define NET_WM_STATE_REMOVE
Definition ewmh.c:63
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT
Definition ewmh.c:73
void EwmhSelectionClear(XSelectionClearEvent *sev)
Definition ewmh.c:546
int EwmhHandlePropertyNotify(XPropertyEvent *event, TwmWindow *twm_win)
Definition ewmh.c:1403
void EwmhSet_NET_SHOWING_DESKTOP(int state)
Definition ewmh.c:2116
#define _NET_WM_MOVERESIZE_SIZE_LEFT
Definition ewmh.c:74
static void EwmhClientMessage_NET_WM_STATE(XClientMessageEvent *msg)
Definition ewmh.c:1066
static void EwmhClientMessage_NET_WM_MOVERESIZE(XClientMessageEvent *msg)
Definition ewmh.c:1269
bool EwmhInitScreenEarly(ScreenInfo *scr)
Definition ewmh.c:307
void EwmhAddClientWindow(TwmWindow *new_win)
Definition ewmh.c:1701
static int atomToFlag(Atom a)
Definition ewmh.c:1027
bool EwmhHasBorder(TwmWindow *twm_win)
Definition ewmh.c:1876
static void GenerateTimestamp(ScreenInfo *scr)
Definition ewmh.c:144
bool EwmhOnWindowRing(TwmWindow *twm_win)
Definition ewmh.c:1898
static bool EwmhReplaceWM(ScreenInfo *scr)
Definition ewmh.c:194
static int CatchError(Display *display, XErrorEvent *event)
Definition ewmh.c:126
static void EwmhInitAtoms(void)
Definition ewmh.c:119
void EwmhSet_NET_WM_DESKTOP(TwmWindow *twm_win)
Definition ewmh.c:1469
#define _NET_WM_MOVERESIZE_CANCEL
Definition ewmh.c:78
#define ALL_WORKSPACES
Definition ewmh.c:96
static void EwmhRecalculateStrut(void)
Definition ewmh.c:1915
void EwmhDeleteClientWindow(TwmWindow *old_win)
Definition ewmh.c:1738
void EwmhInit(void)
Definition ewmh.c:132
void EwmhGetProperties(TwmWindow *twm_win)
Definition ewmh.c:1842
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD
Definition ewmh.c:77
void EwmhSet_NET_ACTIVE_WINDOW(Window w)
Definition ewmh.c:1823
static void EwmhHandle_NET_WM_STRUTNotify(XPropertyEvent *event, TwmWindow *twm_win)
Definition ewmh.c:1018
static void SendPropertyMessage(Window to, Window about, Atom messagetype, long l0, long l1, long l2, long l3, long l4, long mask)
Definition ewmh.c:98
bool EwmhHasTitle(TwmWindow *twm_win)
Definition ewmh.c:1887
static XEvent synth_btnevent_for_moveresize(TwmWindow *twm_win)
Definition ewmh.c:1343
#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD
Definition ewmh.c:76
static void EwmhClientMessage_NET_WM_STATEchange(TwmWindow *twm_win, int change, int newVal)
Definition ewmh.c:1144
static void EwmhClientMessage_NET_CLOSE_WINDOW(XClientMessageEvent *msg)
Definition ewmh.c:1387
#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT
Definition ewmh.c:69
static unsigned long EwmhGetWindowProperty(Window w, Atom name, Atom type)
Definition ewmh.c:1541
#define NET_WM_STATE_TOGGLE
Definition ewmh.c:65
#define _NET_WM_MOVERESIZE_SIZE_BOTTOM
Definition ewmh.c:72
void EwmhSet_NET_WM_STATE(TwmWindow *twm_win, int changes)
Definition ewmh.c:2137
Image * EwmhGetIcon(ScreenInfo *scr, TwmWindow *twm_win)
Definition ewmh.c:637
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT
Definition ewmh.c:71
void EwmhSet_NET_CLIENT_LIST_STACKING(void)
Definition ewmh.c:1782
static uint32_t * buffer_32bpp
Definition ewmh.c:836
#define _NET_WM_MOVERESIZE_MOVE
Definition ewmh.c:75
static void EwmhHandle_NET_WM_ICONNotify(XPropertyEvent *event, TwmWindow *twm_win)
Definition ewmh.c:947
int EwmhGetOccupation(TwmWindow *twm_win)
Definition ewmh.c:1602
#define _NET_WM_MOVERESIZE_SIZE_RIGHT
Definition ewmh.c:70
static void convert_for_16(int w, int x, int y, int argb)
Definition ewmh.c:838
#define EWMH_STATE_ABOVE
Definition ewmh.h:41
@ wt_Dock
Definition ewmh.h:19
@ wt_Desktop
Definition ewmh.h:18
@ wt_Normal
Definition ewmh.h:17
#define EWMH_STATE_MAXIMIZED_VERT
Definition ewmh.h:37
#define EWMH_PRI_DOCK
Definition ewmh.h:50
#define EWMH_STATE_MAXIMIZED_HORZ
Definition ewmh.h:38
#define EWMH_PRI_DESKTOP
Definition ewmh.h:49
#define EWMH_STATE_SHADED
Definition ewmh.h:40
#define EWMH_STATE_BELOW
Definition ewmh.h:42
#define EWMH_HAS_STRUT
Definition ewmh.h:35
#define EWMH_STATE_FULLSCREEN
Definition ewmh.h:39
void ExecuteFunction(int func, void *action, Window w, TwmWindow *tmp_win, XEvent *eventp, int context, bool pulldown)
Definition functions.c:99
Window XineramaRoot
Root window holding our vscreens.
Definition screen.h:200
Window Root
Root window for the current vscreen.
Definition screen.h:194
VirtualScreen * vScreenList
Linked list of per-VS info.
Definition screen.h:513
int frame_x
X position on screen of frame.
int frame_y
Y position on screen of frame.
Window frame
The X window for the overall frame.
int frame_bw
2d border width.
unsigned int title_height
Height of the full title bar.
int frame_bw3D
3d border width.
void RedoIconName(TwmWindow *win)
Definition icons.c:1244
int GetIconOffset(Icon *icon)
Definition icons.c:1128
@ match_net_wm_icon
Definition icons.h:22
Image * AllocImage(void)
Definition image.c:158
void FreeImage(Image *image)
Definition image.c:164
int y
Definition menus.c:70
int x
Definition menus.c:69
int fullOccupation
Definition occupation.c:43
void ChangeOccupation(TwmWindow *tmp_win, int newoccupation)
void OtpSetAflagMask(TwmWindow *twm_win, unsigned mask, unsigned setto)
Definition otp.c:1522
int OtpEffectivePriority(TwmWindow *twm_win)
Definition otp.c:1803
void OtpRestackWindow(TwmWindow *twm_win)
Definition otp.c:1648
TwmWindow * OtpNextWinUp(TwmWindow *twm_win)
Definition otp.c:1458
int OtpEffectiveDisplayPriority(TwmWindow *twm_win)
Definition otp.c:1794
TwmWindow * OtpBottomWin(void)
Definition otp.c:1437
MenuRoot * root
Definition parse_yacc.c:26
RLayout * RLayoutCopyCropped(const RLayout *self, int left_margin, int right_margin, int top_margin, int bottom_margin)
Create a copy of an RLayout with given amounts cropped off the sides.
Definition r_layout.c:78
struct EwmhStrut * next
Definition ewmh.h:26
Definition icons.h:26
int height
Definition icons.h:39
Image * image
Definition icons.h:31
Window w
Definition icons.h:28
Window bm_w
Definition icons.h:30
int width
Definition icons.h:38
Matchtype match
Definition icons.h:27
Definition image.h:9
Pixmap mask
Definition image.h:11
int height
Definition image.h:13
Pixmap pixmap
Definition image.h:10
int width
Definition image.h:12
short x
Definition menus.h:84
Info and control for each X Screen we control.
Definition screen.h:96
int BorderTop
BorderTop config var.
Definition screen.h:758
WorkSpaceMgr workSpaceMgr
Info about the WorkSpaceManager (and Occupy window) for the screen.
Definition screen.h:508
int BorderBottom
BorderBottom config var.
Definition screen.h:759
int BorderRight
BorderRight config var.
Definition screen.h:757
bool workSpaceManagerActive
Whether the WSM is being shown.
Definition screen.h:509
int BorderLeft
BorderLeft config var.
Definition screen.h:756
int rootw
Copy of DisplayWidth(dpy, screen)
Definition screen.h:114
int d_depth
Copy of DefaultDepth(dpy, screen)
Definition screen.h:99
int screen
Which screen (i.e., the x after the dot in ":0.x")
Definition screen.h:97
int rooth
Copy of DisplayHeight(dpy, screen)
Definition screen.h:115
Info and control for every X Window we take over.
bool iswspmgr
This is a workspace manager window.
bool isiconmgr
This is an icon manager window.
Window w
The actual X Window handle.
int zoomed
ZOOM_NONE || function causing zoom.
struct Icon * icon
The current icon.
int occupation
Workspaces the window is in (bitmap)
struct VirtualScreen * vs
Where the window is currently mapped (may be NULL)
bool mapped
Is the window mapped ?
struct WList * iconmanagerlist
List of the icon managers the window is in.
struct VirtualScreen * parent_vs
Where the window is parented. Always set.
struct TwmWindow::_names names
Various sources of window/icon names. "
bool squeezed
Is the window squeezed ?
struct VirtualScreen * next
Definition vscreen.h:12
struct WorkSpaceWindow * wsw
Definition vscreen.h:11
Window window
Definition vscreen.h:9
WorkSpace * currentwspc
static int max(int a, int b)
Definition util.h:25
void DeIconify(TwmWindow *tmp_win)
void Squeeze(TwmWindow *tmp_win)
Definition win_ops.c:223
void SetFocus(TwmWindow *tmp_win, Time tim)
Definition win_ops.c:128
void fullzoom(TwmWindow *tmp_win, int func)
Definition win_resize.c:896
void apply_window_icon_name(TwmWindow *win)
[Re]set and apply changes to a window's icon name.
Definition win_utils.c:1349
void FreeWMPropertyString(char *prop)
Definition win_utils.c:327
TwmWindow * GetTwmWindow(Window w)
Definition win_utils.c:190
void WarpToWindow(TwmWindow *t, bool must_raise)
Definition win_utils.c:883
void apply_window_name(TwmWindow *win)
[Re]set and apply changes to a window's name.
Definition win_utils.c:1187
char * GetWMPropertyString(Window w, Atom prop)
Definition win_utils.c:222
#define MAXWORKSPACE
void GotoWorkSpaceByNumber(VirtualScreen *vs, int workspacenum)
void ShowBackground(VirtualScreen *vs, int newstate)