Add reminder to investigate recursive commands for 2.6
[fvwm.git] / fvwm / gnome.c
blobcbb493ce5a229c25a997c14562d55bd106e300ab
1 /* -*-c-*- */
2 /*
3 * GNOME WM Compliance adapted for fvwm
4 * Properties set on the root window (or desktop window)
6 * Even though the rest of fvwm is GPL consider this file
7 * Public Domain - use it however you see fit to make
8 * your WM GNOME compiant
10 * written by Raster
11 * adapted for fvwm by Jay Painter <jpaint@gnu.org>
13 #include "config.h"
15 #include <stdio.h>
16 #ifdef HAVE_FCNTL_H
17 #include <fcntl.h>
18 #endif
20 #include <X11/Xlib.h>
21 #include <X11/Xmd.h>
22 #include <X11/Xatom.h>
24 #include "libs/fvwmlib.h"
25 #include "libs/Parse.h"
26 #include "fvwm.h"
27 #include "externs.h"
28 #include "cursor.h"
29 #include "functions.h"
30 #include "commands.h"
31 #include "misc.h"
32 #include "screen.h"
33 #include "gnome.h"
34 #include "move_resize.h"
35 #include "stack.h"
36 #include "update.h"
37 #include "style.h"
38 #include "virtual.h"
39 #include "window_flags.h"
40 #include "borders.h"
41 #include "decorations.h"
45 * Properties set on the root window (or desktop window)
48 /* WIN_AREA CARD32[2] contains the current desktop area X,Y */
49 #define XA_WIN_AREA "_WIN_AREA"
51 /* WIN_AREA CARD32[2] contains the current desktop area size WxH */
52 #define XA_WIN_AREA_COUNT "_WIN_AREA_COUNT"
54 /* array of atoms - atom being one of the following atoms */
55 #define XA_WIN_PROTOCOLS "_WIN_PROTOCOLS"
57 /* array of iocn in various sizes */
58 /* Type: array of CARD32 */
59 /* first item is icon count (n) */
60 /* second item is icon record length (in CARD32s) */
61 /* this is followed by (n) icon records as follows */
62 /* pixmap (XID) */
63 /* mask (XID) */
64 /* width (CARD32) */
65 /* height (CARD32) */
66 /* depth (of pixmap, mask is assumed to be of depth 1) (CARD32) */
67 /* drawable (screen root drawable of pixmap) (XID) */
68 /* ... additional fields can be added at the end of this list */
69 #define XA_WIN_ICONS "_WIN_ICONS"
71 /* WIN_WORKSPACE CARD32 contains the current desktop number */
72 #define XA_WIN_WORKSPACE "_WIN_WORKSPACE"
73 /* WIN_WORKSPACE_COUNT CARD32 contains the number of desktops */
74 #define XA_WIN_WORKSPACE_COUNT "_WIN_WORKSPACE_COUNT"
76 /* WIN_WORKSPACE_NAMES StringList (Text Property) of workspace names */
77 /* unused by enlightenment */
78 #define XA_WIN_WORKSPACE_NAMES "_WIN_WORKSPACE_NAMES"
80 /* *** Don't use this.. iffy at best. ** */
81 /* The available work area for client windows. The WM can set this and the WM */
82 /* and/or clients may change it at any time. If it is changed the WM and/or */
83 /* clients should honor the changes. If this property does not exist a client */
84 /* or WM can create it. */
86 * CARD32 min_x;
87 * CARD32 min_y;
88 * CARD32 max_x;
89 * CARD32 max_y;
91 #define XA_WIN_WORKAREA "_WIN_WORKAREA"
92 /* array of 4 CARD32's */
94 /* This is a list of window id's the WM is currently managing - primarily */
95 /* for being able to have external "tasklist" apps */
96 #define XA_WIN_CLIENT_LIST "_WIN_CLIENT_LIST"
97 /* array of N XID's */
100 * Properties on client windows
103 /* The layer the window exists in */
104 /* 0 = Desktop */
105 /* 1 = Below */
106 /* 2 = Normal (default app layer) */
107 /* 4 = OnTop */
108 /* 6 = Dock (always on top - for panel) */
109 /* The app sets this alone, not the WM. If this property changes the WM */
110 /* should comply and change the appearance/behavior of the Client window */
111 /* if this hint does not exist the WM Will create it on the Client window */
112 #define WIN_LAYER_DESKTOP 0
113 #define WIN_LAYER_BELOW 2
114 #define WIN_LAYER_NORMAL 4
115 #define WIN_LAYER_ONTOP 6
116 #define WIN_LAYER_DOCK 8
117 #define WIN_LAYER_ABOVE_DOCK 10
118 #define WIN_LAYER_MENU 12
119 #define XA_WIN_LAYER "_WIN_LAYER"
120 /* WIN_LAYER = CARD32 */
122 /* flags for the window's state. The WM will change these as needed when */
123 /* state changes. If the property contains info on client map, E will modify */
124 /* the windows state accordingly. if the Hint does not exist the WM will */
125 /* create it on the client window. 0 for the bit means off, 1 means on. */
126 /* unused (default) values are 0 */
128 /* removed Minimized - no explanation of what it really means - ambiguity */
129 /* should not be here if not clear */
130 #define WIN_STATE_STICKY (1<<0) /* everyone knows sticky */
131 #define WIN_STATE_RESERVED_BIT1 (1<<1) /* removed minimize here */
132 #define WIN_STATE_MAXIMIZED_VERT (1<<2) /* window in maximized V state */
133 #define WIN_STATE_MAXIMIZED_HORIZ (1<<3) /* window in maximized H state */
134 #define WIN_STATE_HIDDEN (1<<4) /* not on taskbar but window visible */
135 #define WIN_STATE_SHADED (1<<5) /* shaded (NeXT style) */
136 #define WIN_STATE_HID_WORKSPACE (1<<6) /* not on current desktop */
137 #define WIN_STATE_HID_TRANSIENT (1<<7) /* Owner of transient is hidden */
138 #define WIN_STATE_FIXED_POSITION (1<<8) /* window is fixed in position even */
139 #define WIN_STATE_ARRANGE_IGNORE (1<<9) /* ignore for auto arranging */
140 /* when scrolling about large */
141 /* virtual desktops ala fvwm */
142 #define XA_WIN_STATE "_WIN_STATE"
143 /* WIN_STATE = CARD32 */
145 /* Preferences for behavior for app */
146 /* ONLY the client sets this */
147 #define WIN_HINTS_SKIP_FOCUS (1<<0) /* "alt-tab" skips this win */
148 #define WIN_HINTS_SKIP_WINLIST (1<<1) /* not in win list */
149 #define WIN_HINTS_SKIP_TASKBAR (1<<2) /* not on taskbar */
150 #define WIN_HINTS_GROUP_TRANSIENT (1<<3) /* ??????? */
151 #define WIN_HINTS_FOCUS_ON_CLICK (1<<4) /* app only accepts focus when clicked
153 #define XA_WIN_HINTS "_WIN_HINTS"
154 /* WIN_HINTS = CARD32 */
156 /* Application state - also "color reactiveness" - the app can keep changing */
157 /* this property when it changes its state and the WM or monitoring program */
158 /* will pick this up and dpylay somehting accordingly. ONLY the client sets */
159 /* this. */
160 #define WIN_APP_STATE_NONE 0
161 #define WIN_APP_STATE_ACTIVE1 1
162 #define WIN_APP_STATE_ACTIVE2 2
163 #define WIN_APP_STATE_ERROR1 3
164 #define WIN_APP_STATE_ERROR2 4
165 #define WIN_APP_STATE_FATAL_ERROR1 5
166 #define WIN_APP_STATE_FATAL_ERROR2 6
167 #define WIN_APP_STATE_IDLE1 7
168 #define WIN_APP_STATE_IDLE2 8
169 #define WIN_APP_STATE_WAITING1 9
170 #define WIN_APP_STATE_WAITING2 10
171 #define WIN_APP_STATE_WORKING1 11
172 #define WIN_APP_STATE_WORKING2 12
173 #define WIN_APP_STATE_NEED_USER_INPUT1 13
174 #define WIN_APP_STATE_NEED_USER_INPUT2 14
175 #define WIN_APP_STATE_STRUGGLING1 15
176 #define WIN_APP_STATE_STRUGGLING2 16
177 #define WIN_APP_STATE_DISK_TRAFFIC1 17
178 #define WIN_APP_STATE_DISK_TRAFFIC2 18
179 #define WIN_APP_STATE_NETWORK_TRAFFIC1 19
180 #define WIN_APP_STATE_NETWORK_TRAFFIC2 20
181 #define WIN_APP_STATE_OVERLOADED1 21
182 #define WIN_APP_STATE_OVERLOADED2 22
183 #define WIN_APP_STATE_PERCENT000_1 23
184 #define WIN_APP_STATE_PERCENT000_2 24
185 #define WIN_APP_STATE_PERCENT010_1 25
186 #define WIN_APP_STATE_PERCENT010_2 26
187 #define WIN_APP_STATE_PERCENT020_1 27
188 #define WIN_APP_STATE_PERCENT020_2 28
189 #define WIN_APP_STATE_PERCENT030_1 29
190 #define WIN_APP_STATE_PERCENT030_2 30
191 #define WIN_APP_STATE_PERCENT040_1 31
192 #define WIN_APP_STATE_PERCENT040_2 32
193 #define WIN_APP_STATE_PERCENT050_1 33
194 #define WIN_APP_STATE_PERCENT050_2 34
195 #define WIN_APP_STATE_PERCENT060_1 35
196 #define WIN_APP_STATE_PERCENT060_2 36
197 #define WIN_APP_STATE_PERCENT070_1 37
198 #define WIN_APP_STATE_PERCENT070_2 38
199 #define WIN_APP_STATE_PERCENT080_1 39
200 #define WIN_APP_STATE_PERCENT080_2 40
201 #define WIN_APP_STATE_PERCENT090_1 41
202 #define WIN_APP_STATE_PERCENT090_2 42
203 #define WIN_APP_STATE_PERCENT100_1 43
204 #define WIN_APP_STATE_PERCENT100_2 44
205 #define XA_WIN_APP_STATE "_WIN_APP_STATE"
206 /* WIN_APP_STATE = CARD32 */
208 /* Expanded space occupied - this is the area on screen the app's window */
209 /* will occupy when "expanded" - ie if you have a button on an app that */
210 /* "hides" it by reducing its size, this is the geometry of the expanded */
211 /* window - so the window manager can allow for this when doign auto */
212 /* positioing of client windows assuming the app can at any point use this */
213 /* this area and thus try and keep it clear. ONLY the client sets this */
215 * CARD32 x;
216 * CARD32 y;
217 * CARD32 width;
218 * CARD32 height;
220 #define XA_WIN_EXPANDED_SIZE "_WIN_EXPANDED_SIZE"
221 /* array of 4 CARD32's */
223 /* CARD32 that contians the desktop number the application is on If the */
224 /* application's state is "sticky" it is irrelevant. Only the WM should */
225 /* change this. */
226 #define XA_WIN_WORKSPACE "_WIN_WORKSPACE"
228 /* This atom is a 32-bit integer that is either 0 or 1 (currently). */
229 /* 0 denotes everything is as per usual but 1 denotes that ALL configure */
230 /* requests by the client on the client window with this property are */
231 /* not just a simple "moving" of the window, but the result of a user */
232 /* moving the window BUT the client handling that interaction by moving */
233 /* its own window. The window manager should respond accordingly by assuming */
234 /* any configure requests for this window whilst this atom is "active" in */
235 /* the "1" state are a client move and should handle flipping desktops if */
236 /* the window is being dragged "off screem" or across desktop boundaries */
237 /* etc. This atom is ONLY ever set by the client */
238 #define XA_WIN_CLIENT_MOVING "_WIN_CLIENT_MOVING"
239 /* WIN_CLIENT_MOVING = CARD32 */
241 /* Designed for checking if the WIN_ supporting WM is still there */
242 /* and kicking about - basically check this property - check the window */
243 /* ID it points to - then check that window Id has this property too */
244 /* if that is the case the WIN_ supporting WM is there and alive and the */
245 /* list of WIN_PROTOCOLS is valid */
246 #define XA_WIN_SUPPORTING_WM_CHECK "_WIN_SUPPORTING_WM_CHECK"
247 /* CARD32 */
249 /* for root window button clicks */
250 #define XA_WIN_DESKTOP_BUTTON_PROXY "_WIN_DESKTOP_BUTTON_PROXY"
251 /* CARD32 */
254 /* for the root window clicks */
255 static Window __button_proxy = 0;
258 /* how many desks does gnome know about */
259 static int gnome_max_desk = 1;
261 static int atom_size(int format)
263 if (format == 32)
265 return sizeof(long);
267 else
269 return (format >> 3);
273 static void *
274 AtomGet(Window win, Atom to_get, Atom type, int *size)
276 unsigned char *retval;
277 Atom type_ret;
278 unsigned long bytes_after, num_ret;
279 int format_ret;
280 long length;
281 void *data;
283 retval = NULL;
284 length = 0x7fffffff;
285 XGetWindowProperty(
286 dpy, win, to_get, 0L, length, False, type, &type_ret,
287 &format_ret, &num_ret, &bytes_after, &retval);
289 if ((retval) && (num_ret > 0) && (format_ret > 0))
291 int asize;
293 asize = atom_size(format_ret);
294 data = safemalloc(num_ret * asize);
295 if (data)
297 memcpy(data, retval, num_ret * asize);
299 XFree(retval);
300 *size = num_ret * (format_ret >> 3);
301 return data;
304 return NULL;
308 /*** GET WINDOW PROPERTIES ***/
310 #if 0
311 static void
312 GNOME_GetHintIcons(FvwmWindow *fwin)
314 Atom atom_get;
315 long *retval;
316 int size;
317 int i;
318 Pixmap pmap;
319 Pixmap mask;
321 atom_get = XInternAtom(dpy, XA_WIN_ICONS, False);
322 retval = AtomGet(FW_W(fwin), atom_get, XA_PIXMAP, &size);
323 if (retval)
325 int n;
327 n = size / atom_size(32);
328 for (i = 0; i < n; i += 2)
330 pmap = retval[i];
331 mask = retval[i + 1];
333 free(retval);
336 return;
339 static void
340 GNOME_GetHintLayer(FvwmWindow *fwin)
342 Atom atom_get;
343 long *retval;
344 int size;
346 atom_get = XInternAtom(dpy, XA_WIN_LAYER, False);
347 retval = AtomGet(FW_W(fwin), atom_get, XA_CARDINAL, &size);
348 if (retval)
350 set_layer(fwin, *retval);
351 free(retval);
354 return;
357 static void
358 GNOME_GetHintState(FvwmWindow *fwin)
360 Atom atom_get;
361 long *retval;
362 int size;
364 atom_get = XInternAtom(dpy, XA_WIN_STATE, False);
365 retval = AtomGet(FW_W(fwin), atom_get, XA_CARDINAL, &size);
366 if (retval)
368 if (*retval & WIN_STATE_STICKY)
370 SET_STICKY(fwin, 1);
373 if (*retval & WIN_STATE_SHADED)
375 /* Fixme: how do we find out the correct shade
376 * direction here? */
377 SET_SHADED(fwin, 1);
378 SET_SHADED_DIR(fwin, DIR_N);
381 if (*retval & WIN_STATE_FIXED_POSITION)
383 SET_FIXED(fwin, 1);
386 free(retval);
389 return;
392 static void
393 GNOME_GetHintAppState(FvwmWindow *fwin)
395 Atom atom_get;
396 unsigned char *retval;
397 int size;
399 /* have nothing interesting to do with an app state (lamp) right now */
400 atom_get = XInternAtom(dpy, XA_WIN_APP_STATE, False);
401 retval = AtomGet(FW_W(fwin), atom_get, XA_CARDINAL, &size);
402 if (retval)
404 free(retval);
407 return;
410 static void
411 GNOME_GetHintDesktop(FvwmWindow *fwin)
413 Atom atom_get;
414 unsigned char *retval;
415 int size;
416 int *desk;
418 atom_get = XInternAtom(dpy, XA_WIN_WORKSPACE, False);
419 retval = AtomGet(FW_W(fwin), atom_get, XA_CARDINAL, &size);
420 if (retval)
422 desk = (int *)retval;
423 fwin->Desk = *desk;
425 /* XXX: hide window if it's not on the current desktop! */
426 free(retval);
429 return;
432 static void
433 GNOME_GetHint(FvwmWindow *fwin)
435 Atom atom_get;
436 int *retval;
437 int size;
439 atom_get = XInternAtom(dpy, XA_WIN_HINTS, False);
440 retval = AtomGet(FW_W(fwin), atom_get, XA_CARDINAL, &size);
441 if (retval)
443 if (*retval & WIN_HINTS_SKIP_WINLIST)
445 SET_DO_SKIP_WINDOW_LIST(fwin, 1);
447 /* XXX: unimplimented */
448 if (*retval & WIN_HINTS_SKIP_TASKBAR)
452 if (*retval & WIN_HINTS_SKIP_FOCUS)
456 if (*retval & WIN_HINTS_FOCUS_ON_CLICK)
460 /* if (*retval & WIN_HINTS_DO_NOT_COVER);*/
462 free(retval);
465 return;
468 static void
469 GNOME_GetExpandedSize(FvwmWindow *fwin)
471 Atom atom_get;
472 long *retval;
473 int size;
475 /* unimplimented */
476 int expanded_x, expanded_y, expanded_width, expanded_height;
478 atom_get = XInternAtom(dpy, XA_WIN_EXPANDED_SIZE, False);
479 retval = AtomGet(FW_W(fwin), atom_get, XA_CARDINAL, &size);
480 if (retval)
482 expanded_x = retval[0];
483 expanded_y = retval[1];
484 expanded_width = retval[2];
485 expanded_height = retval[3];
486 free(retval);
489 return;
492 void
493 GNOME_GetHints(FvwmWindow *fwin)
495 if (DO_IGNORE_GNOME_HINTS(fwin))
497 return;
499 GNOME_GetHintDesktop(fwin);
500 GNOME_GetHintIcons(fwin);
501 GNOME_GetHintLayer(fwin);
502 GNOME_GetHintState(fwin);
503 GNOME_GetHintAppState(fwin);
504 GNOME_GetHint(fwin);
505 GNOME_GetExpandedSize(fwin);
507 return;
509 #endif
511 void
512 GNOME_SetHints(FvwmWindow *fwin)
514 Atom atom_set;
515 long val;
517 atom_set = XInternAtom(dpy, XA_WIN_STATE, False);
518 val = 0;
520 if (IS_STICKY_ACROSS_PAGES(fwin) && IS_STICKY_ACROSS_DESKS(fwin))
522 val |= WIN_STATE_STICKY;
524 if (IS_SHADED(fwin))
526 val |= WIN_STATE_SHADED;
528 if (!is_function_allowed(F_MOVE, NULL, fwin, RQORIG_PROGRAM_US, False))
530 val |= WIN_STATE_FIXED_POSITION;
532 XChangeProperty(
533 dpy, FW_W(fwin), atom_set, XA_CARDINAL, 32, PropModeReplace,
534 (unsigned char *)&val, 1);
536 return;
540 /* this duplicates most of the above... and it assumes
541 that style is inizialized to zero.
543 void
544 GNOME_GetStyle (FvwmWindow *fwin, window_style *style)
546 Atom atom_get;
547 unsigned char *retval;
548 int size;
550 if (S_DO_IGNORE_GNOME_HINTS(SCF(*style)))
552 return;
554 /* Desktop */
555 atom_get = XInternAtom(dpy, XA_WIN_WORKSPACE, False);
556 retval = AtomGet(FW_W(fwin), atom_get, XA_CARDINAL, &size);
557 if (retval)
559 SSET_START_DESK(*style, *(int*)retval);
560 /* Allow special case of -1 to work. */
561 if (SGET_START_DESK(*style) > -1)
563 SSET_START_DESK(*style, SGET_START_DESK(*style) + 1);
565 style->flags.use_start_on_desk = 1;
566 style->flag_mask.use_start_on_desk = 1;
567 free(retval);
570 /* Icons - not implemented */
572 /* Layer */
573 atom_get = XInternAtom(dpy, XA_WIN_LAYER, False);
574 retval = AtomGet(FW_W(fwin), atom_get, XA_CARDINAL, &size);
575 if (retval)
577 SSET_LAYER(*style, *(int*)retval);
578 style->flags.use_layer = (SGET_LAYER(*style) >= 0) ? 1 : 0;
579 style->flag_mask.use_layer = 1;
580 free(retval);
583 /* State */
584 atom_get = XInternAtom(dpy, XA_WIN_STATE, False);
585 retval = AtomGet(FW_W(fwin), atom_get, XA_CARDINAL, &size);
586 if (retval)
588 if (*(int*)retval & WIN_STATE_STICKY)
590 S_SET_IS_STICKY_ACROSS_PAGES(SCF(*style), 1);
591 S_SET_IS_STICKY_ACROSS_PAGES(SCM(*style), 1);
592 S_SET_IS_STICKY_ACROSS_PAGES(SCC(*style), 1);
593 S_SET_IS_STICKY_ACROSS_DESKS(SCF(*style), 1);
594 S_SET_IS_STICKY_ACROSS_DESKS(SCM(*style), 1);
595 S_SET_IS_STICKY_ACROSS_DESKS(SCC(*style), 1);
598 if (*(int*)retval & WIN_STATE_SHADED)
600 /* unimplemented, since we don't have a
601 start_shaded flag. SM code relies on a
602 separate do_shade flag, but that is ugly.
606 if ((*(int*)retval & WIN_STATE_FIXED_POSITION))
608 S_SET_IS_FIXED(SCF(*style), 1);
609 S_SET_IS_FIXED(SCM(*style), 1);
610 S_SET_IS_FIXED(SCC(*style), 1);
613 free(retval);
616 /* App state - not implemented */
618 /* Hints */
619 atom_get = XInternAtom(dpy, XA_WIN_HINTS, False);
620 retval = AtomGet(FW_W(fwin), atom_get, XA_CARDINAL, &size);
621 if (retval)
623 if (*retval & WIN_HINTS_SKIP_WINLIST)
625 S_SET_DO_WINDOW_LIST_SKIP(SCF(*style), 1);
626 S_SET_DO_WINDOW_LIST_SKIP(SCM(*style), 1);
627 S_SET_DO_WINDOW_LIST_SKIP(SCC(*style), 1);
630 free(retval);
633 /* Expanded size - not implemented */
635 return;
639 /*** SET WINDOW PROPERTIES ***/
640 void
641 GNOME_SetDesk(FvwmWindow *fwin)
643 Atom atom_set;
644 long val;
646 atom_set = XInternAtom(dpy, XA_WIN_WORKSPACE, False);
647 val = fwin->Desk;
648 if (val >= gnome_max_desk)
650 GNOME_SetDeskCount();
652 XChangeProperty(
653 dpy, FW_W(fwin), atom_set, XA_CARDINAL, 32, PropModeReplace,
654 (unsigned char *)&val, 1);
656 return;
660 void
661 GNOME_SetLayer(FvwmWindow *fwin)
663 Atom atom_set;
664 long val;
666 atom_set = XInternAtom(dpy, XA_WIN_LAYER, False);
667 val = get_layer(fwin);
668 XChangeProperty(
669 dpy, FW_W(fwin), atom_set, XA_CARDINAL, 32, PropModeReplace,
670 (unsigned char *)&val, 1);
672 return;
676 /*** INITIALIZE GNOME WM SUPPORT ***/
678 /* sets the virtual desktop grid properties */
679 void
680 GNOME_SetAreaCount(void)
682 Atom atom_set;
683 long val[2];
685 atom_set = XInternAtom(dpy, XA_WIN_AREA_COUNT, False);
686 val[0] = (Scr.VxMax + Scr.MyDisplayWidth) / Scr.MyDisplayWidth;
687 val[1] = (Scr.VyMax + Scr.MyDisplayHeight) / Scr.MyDisplayHeight;
688 XChangeProperty(
689 dpy, Scr.Root, atom_set, XA_CARDINAL, 32, PropModeReplace,
690 (unsigned char *)val, 2);
692 return;
696 /* sets the property indicating the current virtual desktop
697 * location
699 void
700 GNOME_SetCurrentArea(void)
702 Atom atom_set;
703 long val[2];
705 atom_set = XInternAtom(dpy, XA_WIN_AREA, False);
706 val[0] = Scr.Vx / Scr.MyDisplayWidth;
707 val[1] = Scr.Vy / Scr.MyDisplayHeight;
708 XChangeProperty(
709 dpy, Scr.Root, atom_set, XA_CARDINAL, 32, PropModeReplace,
710 (unsigned char *)val, 2);
712 return;
715 /* FIXME: what to do about negative desks ? */
716 /* ignore them! */
717 void
718 GNOME_SetDeskCount(void)
720 Atom atom_set;
721 long val;
722 FvwmWindow *t;
724 atom_set = XInternAtom(dpy, XA_WIN_WORKSPACE_COUNT, False);
725 val = 0;
726 if (Scr.CurrentDesk > 0)
728 val = Scr.CurrentDesk;
730 for (t = get_next_window_in_stack_ring(&Scr.FvwmRoot);
731 t != &Scr.FvwmRoot; t = get_next_window_in_stack_ring(t))
733 if (t->Desk > val)
735 val = t->Desk;
738 val++;
739 if (gnome_max_desk > val)
741 val = gnome_max_desk;
743 XChangeProperty(
744 dpy, Scr.Root, atom_set, XA_CARDINAL, 32, PropModeReplace,
745 (unsigned char *)&val, 1);
747 return;
751 /* XXX: this function is hard-coded to one! -JMP */
752 void
753 GNOME_SetCurrentDesk(void)
755 Atom atom_set;
756 long val;
758 atom_set = XInternAtom(dpy, XA_WIN_WORKSPACE, False);
759 val = (long) Scr.CurrentDesk;
760 if (val >= gnome_max_desk)
762 GNOME_SetDeskCount();
764 XChangeProperty(
765 dpy, Scr.Root, atom_set, XA_CARDINAL, 32, PropModeReplace,
766 (unsigned char *)&val, 1);
767 GNOME_SetCurrentArea();
769 return;
773 /* sets the names assigned to the desktops */
774 void
775 GNOME_SetDeskNames(void)
777 Atom atom_set;
778 XTextProperty text;
779 char *names[1];
781 atom_set = XInternAtom(dpy, XA_WIN_WORKSPACE_NAMES, False);
782 names[0] = "GNOME Desktop";
783 if (XStringListToTextProperty(names, 1, &text))
785 XSetTextProperty(dpy, Scr.Root, &text, atom_set);
786 XFree(text.value);
789 return;
793 void
794 GNOME_SetClientList(void)
796 Atom atom_set;
797 Window *wl=NULL;
798 int displayed=0;
799 int i = 0;
800 FvwmWindow *t;
802 /* Find out how many window pointers we need to store, allocate
803 * the space and go through the list again to actually store them.
805 for (t = Scr.FvwmRoot.next; t; t = t->next)
807 if (!DO_SKIP_WINDOW_LIST(t))
809 displayed++;
812 if(displayed)
814 wl=(Window*)safemalloc(sizeof(Window*)*displayed);
815 for (t = Scr.FvwmRoot.next; t; t = t->next)
817 if (!DO_SKIP_WINDOW_LIST(t))
819 wl[i++] = FW_W(t);
823 /* Update X */
824 atom_set = XInternAtom(dpy, XA_WIN_CLIENT_LIST, False);
825 XChangeProperty(
826 dpy, Scr.Root, atom_set, XA_CARDINAL, 32,
827 PropModeReplace, (unsigned char *)wl, i);
828 if(wl)
829 free(wl);
831 return;
834 void
835 GNOME_SetWinArea(FvwmWindow *w)
837 Atom atom_set;
838 long val[2];
840 atom_set = XInternAtom(dpy, XA_WIN_AREA, False);
842 if (!DO_SKIP_WINDOW_LIST(w))
844 if (IsRectangleOnThisPage(&(w->g.frame), w->Desk))
846 val[0] = Scr.Vx / Scr.MyDisplayWidth;
847 val[1] = Scr.Vy / Scr.MyDisplayHeight;
849 else
851 val[0] = (w->g.frame.x + Scr.Vx) / Scr.MyDisplayWidth;
852 if (val[0] < 0 &&
853 w->g.frame.x + Scr.Vx + w->g.frame.width > 0)
855 val[0] = 0;
857 val[1] = (w->g.frame.y + Scr.Vy) / Scr.MyDisplayHeight;
858 if (val[1] < 0 &&
859 w->g.frame.y + Scr.Vy + w->g.frame.height > 0)
861 val[1] = 0;
864 XChangeProperty(
865 dpy, FW_W(w), atom_set, XA_CARDINAL, 32,
866 PropModeReplace, (unsigned char *)val, 2);
869 return;
872 void
873 GNOME_Init(void)
875 int i;
876 Atom atom_set, list[11];
877 long val;
879 atom_set = XInternAtom(dpy, XA_WIN_PROTOCOLS, False);
880 /* these indicate what GNOME compliance properties have been
881 * implemented */
882 i = 0;
883 list[i++] = XInternAtom(dpy, XA_WIN_LAYER, False);
884 list[i++] = XInternAtom(dpy, XA_WIN_STATE, False);
885 list[i++] = XInternAtom(dpy, XA_WIN_HINTS, False);
886 /* list[i++] = XInternAtom(dpy, XA_WIN_APP_STATE, False); */
887 /* list[i++] = XInternAtom(dpy, XA_WIN_EXPANDED_SIZE, False); */
888 /* list[i++] = XInternAtom(dpy, XA_WIN_ICONS, False); */
889 list[i++] = XInternAtom(dpy, XA_WIN_WORKSPACE, False);
890 list[i++] = XInternAtom(dpy, XA_WIN_WORKSPACE_COUNT, False);
891 list[i++] = XInternAtom(dpy, XA_WIN_WORKSPACE_NAMES, False);
892 list[i++] = XInternAtom(dpy, XA_WIN_CLIENT_LIST, False);
893 list[i++] = XInternAtom(dpy, XA_WIN_DESKTOP_BUTTON_PROXY, False);
894 XChangeProperty(
895 dpy, Scr.Root, atom_set, XA_ATOM, 32, PropModeReplace,
896 (unsigned char *)list, i);
898 /*--------------------------------------------------------------------
899 why use two windows when one does just fine ?
900 --------------------------------------------------------------------*/
901 /* create a window which is a child of the root window and set the
902 * XA_WIN_SUPPORTING_WM_CHECK property on it, and also set the
903 * same property on the root window with the window ID of of the
904 * window we just created
906 __button_proxy = XCreateWindow(dpy, Scr.Root, -10, -10, 10, 10, 0, 0,
907 InputOnly, CopyFromParent, 0, NULL);
908 atom_set = XInternAtom(dpy, XA_WIN_SUPPORTING_WM_CHECK, False);
909 val = __button_proxy;
910 XChangeProperty(
911 dpy, Scr.Root, atom_set, XA_CARDINAL, 32, PropModeReplace,
912 (unsigned char *)&val, 1);
913 XChangeProperty(
914 dpy, __button_proxy, atom_set, XA_CARDINAL, 32,
915 PropModeReplace, (unsigned char *)&val, 1);
917 /* create a window which is the child of the root window for proxying
918 * root window clicks
920 atom_set = XInternAtom(dpy, XA_WIN_DESKTOP_BUTTON_PROXY, False);
921 XChangeProperty(
922 dpy, Scr.Root, atom_set, XA_CARDINAL, 32,
923 PropModeReplace, (unsigned char *)&val, 1);
924 XChangeProperty(
925 dpy, __button_proxy, atom_set, XA_CARDINAL, 32,
926 PropModeReplace, (unsigned char *)&val, 1);
928 /* some initial settings */
929 GNOME_SetDeskCount();
930 GNOME_SetCurrentDesk();
931 GNOME_SetDeskNames();
932 GNOME_SetAreaCount();
933 GNOME_SetCurrentArea();
934 GNOME_SetClientList();
936 return;
940 /*-----------------------------------------------------------------------
941 tell gnome how many desks to show
942 -----------------------------------------------------------------------*/
943 void
944 CMD_GnomeShowDesks(F_CMD_ARGS)
946 int n;
947 Atom atom_set;
948 long val[1];
950 atom_set = XInternAtom(dpy, XA_WIN_WORKSPACE_COUNT, False);
951 DBUG("GNOME_ShowDesks","Routine Entered");
952 n = GetIntegerArguments(action, NULL, (int *)val, 1);
953 if(n != 1)
955 fvwm_msg(ERR, "GnomeShowDesks", "requires one argument");
956 return;
958 gnome_max_desk = val[0];
959 XChangeProperty(
960 dpy, Scr.Root, atom_set, XA_CARDINAL, 32, PropModeReplace,
961 (unsigned char *)(&val[0]), 1);
963 return;
967 /*** RECIVING MESSAGES ***/
969 GNOME_ProcessClientMessage(const exec_context_t *exc)
971 Atom a;
972 FvwmWindow *fw = exc->w.fw;
973 XEvent *ev = exc->x.etrigger;
974 long p0 = 0;
975 long p1 = 0;
976 const char* invalid_req = "---";
977 const char* invalid_prop = "---";
979 if (fw != NULL && DO_IGNORE_GNOME_HINTS(fw))
981 return 0;
983 a = XInternAtom(dpy, XA_WIN_AREA, False);
984 if (ev->xclient.message_type == a)
986 /* convert to integer grid */
987 p0 = ev->xclient.data.l[0] * Scr.MyDisplayWidth;
988 p1 = ev->xclient.data.l[1] * Scr.MyDisplayHeight;
989 if (p0 < 0 || p0 > 0x7fffffff || p1 < 0 || p1 > 0x7fffffff)
991 invalid_prop = "page";
992 invalid_req = "_WIN_AREA";
993 goto err_msg;
995 MoveViewport(p0, p1, 1);
997 return 1;
999 a = XInternAtom(dpy, XA_WIN_WORKSPACE, False);
1000 if (ev->xclient.message_type == a)
1002 p0 = ev->xclient.data.l[0];
1003 if (p0 < 0 || p0 > 0x7fffffff)
1005 invalid_prop = "desk";
1006 invalid_req = "_WIN_WORKSPACE";
1007 goto err_msg;
1009 goto_desk(p0);
1011 return 1;
1013 a = XInternAtom(dpy, XA_WIN_LAYER, False);
1014 if (ev->xclient.message_type == a && fw)
1016 p0 = ev->xclient.data.l[0];
1017 if (p0 < 0 || p0 > 0x7fffffff)
1019 invalid_prop = "layer";
1020 invalid_req = "_WIN_LAYER";
1021 goto err_msg;
1023 new_layer(fw, p0);
1025 return 1;
1027 a = XInternAtom(dpy, XA_WIN_STATE, False);
1028 if (ev->xclient.message_type == a && fw)
1030 GNOME_HandlePropRequest(
1031 exc, ev->xclient.data.l[0], ev->xclient.data.l[1]);
1033 return 1;
1036 return 0;
1038 err_msg:
1039 fvwm_msg(
1040 WARN, "GNOME_ProcessClientMessage",
1041 "The application window (id %#lx)\n"
1042 " \"%s\" has requested an invalid %s (%ld, %ld)\n"
1043 " using a %s client message.\n"
1044 " fvwm is ignoring this request.\n",
1045 fw ? FW_W(fw) : 0, fw ? fw->name.name : "(none)", invalid_prop,
1046 p0, p1, invalid_req);
1047 fvwm_msg_report_app_and_workers();
1049 return 0;
1053 void GNOME_HandlePropRequest(
1054 const exec_context_t *exc, unsigned int propm, unsigned int prop)
1056 Atom atype;
1057 Atom a;
1058 int aformat;
1059 FvwmWindow *fwin;
1060 unsigned char *indi;
1061 unsigned long nitems, bytes_remain, oldprop;
1062 indi = (unsigned char *)&oldprop;
1063 DBUG("HandleGnomePropRequest","Routine Entered");
1065 a = XInternAtom(dpy, XA_WIN_STATE, False);
1067 for (fwin = Scr.FvwmRoot.next; fwin; fwin = fwin->next)
1069 if (FW_W(fwin) == exc->w.w)
1071 break;
1074 /*--------------------------------------------------------------------
1075 First change the props on the window so the gnome app knows we did
1076 something.
1077 --------------------------------------------------------------------*/
1078 #ifdef FVWM_DEBUG_MSGS
1079 fvwm_msg(
1080 DBG, "HandleGnomePropRequest", "window is %d", (int)FW_W(fwin));
1081 #endif
1082 if (fwin == NULL)
1084 return;
1086 if (DO_IGNORE_GNOME_HINTS(fwin))
1088 return;
1091 #ifdef FVWM_DEBUG_MSGS
1092 fvwm_msg(DBG, "HandleGnomePropRequest", "prop req is %d", prop);
1093 fvwm_msg(DBG, "HandleGnomePropRequest", "propm req is %d", propm);
1094 #endif
1095 XGetWindowProperty(dpy, FW_W(fwin), a, 0L, 3L, False, a,
1096 &atype, &aformat, &nitems, &bytes_remain, &indi);
1097 oldprop &= ~(propm);
1098 oldprop |= (propm & prop);
1099 #ifdef FVWM_DEBUG_MSGS
1100 fvwm_msg(
1101 DBG, "HandleGnomePropRequest", "oldprop req is %d",
1102 (int)oldprop);
1103 #endif
1104 XChangeProperty(
1105 dpy, FW_W(fwin), a, XA_CARDINAL, 32, PropModeReplace,
1106 (unsigned char *)&oldprop, 1);
1108 /*--------------------------------------------------------------------
1109 Then apply the requests
1110 --------------------------------------------------------------------*/
1112 /*--------------------------------------------------------------------
1113 Sticky
1114 --------------------------------------------------------------------*/
1115 if (propm & WIN_STATE_STICKY)
1117 if (prop & WIN_STATE_STICKY)
1119 SET_STICKY_ACROSS_PAGES(fwin, 1);
1120 SET_STICKY_ACROSS_DESKS(fwin, 1);
1122 else
1124 SET_STICKY_ACROSS_PAGES(fwin, 0);
1125 SET_STICKY_ACROSS_DESKS(fwin, 0);
1127 border_draw_decorations(
1128 fwin, PART_TITLE, (Scr.Hilite==fwin), True, CLEAR_ALL,
1129 NULL, NULL);
1131 /*--------------------------------------------------------------------
1132 WindowShade
1133 -------------------------------------------------------------------*/
1134 if (propm & WIN_STATE_SHADED)
1136 if (prop & WIN_STATE_SHADED)
1138 /* shade up */
1139 execute_function_override_window(
1140 NULL, exc, "WindowShade True", 0, fwin);
1142 else
1144 /* shade down */
1145 execute_function_override_window(
1146 NULL, exc, "WindowShade False", 0, fwin);
1150 return;
1153 void
1154 GNOME_ProxyButtonEvent(const XEvent *ev)
1156 switch (ev->type)
1158 case ButtonPress:
1159 XUngrabPointer(dpy, CurrentTime);
1160 FSendEvent(
1161 dpy, __button_proxy, False, SubstructureNotifyMask,
1162 (XEvent *)ev);
1163 break;
1165 case ButtonRelease:
1166 FSendEvent(
1167 dpy, __button_proxy, False, SubstructureNotifyMask,
1168 (XEvent *)ev);
1169 break;
1172 return;
1176 /* this is the function entered into fvwm's functions table */
1177 void
1178 CMD_GnomeButton(F_CMD_ARGS)
1180 /* send off the button press event */
1181 GNOME_ProxyButtonEvent(exc->x.etrigger);
1183 return;