Fix ExplainWindowPlacement when using "NoUSPosition" style.
[fvwm.git] / fvwm / ewmh.c
blob96cfdac82714c3383c44e6aab27e8bcd86255848
1 /* -*-c-*- */
2 /* Copyright (C) 2001 Olivier Chapuis */
3 /* This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * An implementation of the Extended Window Manager Hints specification
20 * http://freedesktop.org/Standards/wm-spec/
22 * Not Implemented (draft 1.3 - 2004-05-01):
24 * _NET_DESKTOP_LAYOUT (not useful for us)
25 * _NET_VIRTUAL_ROOTS (not useful at all for us)
26 * _NET_SHOWING_DESKTOP should be implemented
27 * _NET_REQUEST_FRAME_EXTENTS may be implemented
29 * Some _NET_WINDOW_TYPE are simply ignored:
30 * _NET_WM_WINDOW_TYPE_SPLASH
31 * _NET_WM_WINDOW_TYPE_UTILITIES
32 * _KDE_NET_WM_WINDOW_TYPE_OVERRIDE (deprecated)
34 * _NET_WM_STATE_DEMANDS_ATTENTION state
36 * _NET_WM_STRUT_PARTIAL should be implemented
38 * _NET_WM_USER_TIME can be used to decide if we give the focus to a newly
39 * mapped window
41 * The kill huge process protocol: _NET_WM_PID and _NET_WM_PING
43 * _NET_WM_HANDLED_ICONS (what to do? Nothing?)
45 * "Source indication in requests" is not used but can be useful with some
46 * "ignore styles"
48 * Problems:
49 * - _NET_WM_WINDOW_TYPE_TOOLBAR is interpreted in a different way
50 * in GNOME (the spec) and in KDE 2/3.0 (~ simple dock?).
54 #include "config.h"
56 #include <stdio.h>
57 #include <X11/Xatom.h>
59 #include "libs/fvwmlib.h"
60 #include "libs/FScreen.h"
61 #include "fvwm.h"
62 #include "execcontext.h"
63 #include "functions.h"
64 #include "commands.h"
65 #include "misc.h"
66 #include "screen.h"
67 #include "update.h"
68 #include "stack.h"
69 #include "style.h"
70 #include "externs.h"
71 #include "decorations.h"
72 #include "ewmh.h"
73 #include "ewmh_intern.h"
74 #include "geometry.h"
75 #include "window_flags.h"
77 typedef struct kst_item
79 Window w;
80 struct kst_item *next;
81 } KstItem;
84 Atom XA_UTF8_STRING = None;
85 KstItem *ewmh_KstWinList = NULL;
88 * Default
90 ewmhInfo ewmhc =
92 4, /* NumberOfDesktops */
93 0, /* MaxDesktops limit the number of desktops*/
94 0, /* CurrentNumberOfDesktops */
95 False, /* NeedsToCheckDesk */
96 {0, 0, 0, 0}, /* BaseStrut */
100 * The ewmh atoms lists
102 #define ENTRY(name, type, func) {name, None, type, func}
104 /* WARNING: lists must be in "name" alphabetic order! */
106 /* EWMH_ATOM_LIST_CLIENT_ROOT
107 * net atoms that can be send (Client Message) by a client and do not
108 * need a window to operate */
109 ewmh_atom ewmh_atom_client_root[] =
111 ENTRY("_NET_CURRENT_DESKTOP", XA_CARDINAL, ewmh_CurrentDesktop),
112 ENTRY("_NET_DESKTOP_GEOMETRY", XA_CARDINAL, ewmh_DesktopGeometry),
113 ENTRY("_NET_DESKTOP_NAMES", None, None),
114 ENTRY("_NET_DESKTOP_VIEWPORT", XA_CARDINAL, ewmh_DesktopViewPort),
115 ENTRY("_NET_NUMBER_OF_DESKTOPS", XA_CARDINAL, ewmh_NumberOfDesktops),
116 {NULL,0,0,0}
119 /* EWMH_ATOM_LIST_CLIENT_WIN
120 * net atoms that can be send (Client Message) by a client and do need
121 * window to operate */
122 ewmh_atom ewmh_atom_client_win[] =
124 ENTRY("_NET_ACTIVE_WINDOW", XA_WINDOW, ewmh_ActiveWindow),
125 ENTRY("_NET_CLOSE_WINDOW", XA_WINDOW, ewmh_CloseWindow),
126 ENTRY("_NET_MOVERESIZE_WINDOW", XA_WINDOW, ewmh_MoveResizeWindow),
127 ENTRY("_NET_RESTACK_WINDOW", XA_WINDOW, ewmh_RestackWindow),
128 ENTRY("_NET_WM_DESKTOP", XA_CARDINAL, ewmh_WMDesktop),
129 ENTRY("_NET_WM_MOVERESIZE", XA_WINDOW, ewmh_MoveResize),
130 ENTRY("_NET_WM_STATE", XA_ATOM, ewmh_WMState),
131 {NULL,0,0,0}
134 /* EWMH_ATOM_LIST_WM_STATE
135 * the different wm state, a client can ask to add, remove or toggle
136 * via a _NET_WM_STATE Client message. fvwm must maintain these states
137 * too */
138 ewmh_atom ewmh_atom_wm_state[] =
140 ENTRY(
141 "_NET_WM_STATE_ABOVE", XA_ATOM,
142 ewmh_WMStateStaysOnTop),
143 ENTRY(
144 "_NET_WM_STATE_BELOW", XA_ATOM,
145 ewmh_WMStateStaysOnBottom),
146 ENTRY(
147 "_NET_WM_STATE_FULLSCREEN", XA_ATOM,
148 ewmh_WMStateFullScreen),
149 ENTRY("_NET_WM_STATE_HIDDEN", XA_ATOM, ewmh_WMStateHidden),
150 ENTRY(
151 "_NET_WM_STATE_MAXIMIZED_HORIZ", XA_ATOM,
152 ewmh_WMStateMaxHoriz),
153 ENTRY(
154 "_NET_WM_STATE_MAXIMIZED_HORZ", XA_ATOM,
155 ewmh_WMStateMaxHoriz),
156 ENTRY("_NET_WM_STATE_MAXIMIZED_VERT", XA_ATOM, ewmh_WMStateMaxVert),
157 ENTRY("_NET_WM_STATE_MODAL", XA_ATOM, ewmh_WMStateModal),
158 ENTRY("_NET_WM_STATE_SHADED", XA_ATOM, ewmh_WMStateShaded),
159 ENTRY(
160 "_NET_WM_STATE_SKIP_PAGER", XA_ATOM,
161 ewmh_WMStateSkipPager),
162 ENTRY(
163 "_NET_WM_STATE_SKIP_TASKBAR", XA_ATOM,
164 ewmh_WMStateSkipTaskBar),
165 ENTRY(
166 "_NET_WM_STATE_STAYS_ON_TOP", XA_ATOM,
167 ewmh_WMStateStaysOnTop),
168 ENTRY("_NET_WM_STATE_STICKY", XA_ATOM, ewmh_WMStateSticky),
169 {NULL,0,0,0}
171 #define EWMH_NUMBER_OF_STATE sizeof(ewmh_atom_wm_state)/sizeof(ewmh_atom) - 1
173 /* EWMH ATOM_LIST_ALLOWED_ACTIONS: atom for _NET_WM_ALLOWED_ACTIONS */
174 ewmh_atom ewmh_atom_allowed_actions[] =
176 ENTRY("_NET_WM_ACTION_CHANGE_DESKTOP", XA_ATOM, ewmh_AllowsYes),
177 ENTRY("_NET_WM_ACTION_CLOSE", XA_ATOM, ewmh_AllowsClose),
178 ENTRY("_NET_WM_ACTION_FULLSCREEN", XA_ATOM, ewmh_AllowsFullScreen),
179 ENTRY("_NET_WM_ACTION_MAXIMIZE_HORZ", XA_ATOM, ewmh_AllowsMaximize),
180 ENTRY("_NET_WM_ACTION_MAXIMIZE_VERT", XA_ATOM, ewmh_AllowsMaximize),
181 ENTRY("_NET_WM_ACTION_MINIMIZE", XA_ATOM, ewmh_AllowsMinimize),
182 ENTRY("_NET_WM_ACTION_MOVE", XA_ATOM, ewmh_AllowsMove),
183 ENTRY("_NET_WM_ACTION_RESIZE", XA_ATOM, ewmh_AllowsResize),
184 ENTRY("_NET_WM_ACTION_SHADE", XA_ATOM, ewmh_AllowsYes),
185 ENTRY("_NET_WM_ACTION_STICK", XA_ATOM, ewmh_AllowsYes),
186 {NULL,0,0,0}
188 #define EWMH_NUMBER_OF_ALLOWED_ACTIONS \
189 sizeof(ewmh_atom_allowed_actions)/sizeof(ewmh_atom) - 1
191 /* EWMH ATOM_LIST_WINDOW_TYPE: the various window type */
192 ewmh_atom ewmh_atom_window_type[] =
194 ENTRY("_NET_WM_WINDOW_TYPE_DESKTOP", XA_ATOM, ewmh_HandleDesktop),
195 ENTRY("_NET_WM_WINDOW_TYPE_DIALOG", XA_ATOM, ewmh_HandleDialog),
196 ENTRY("_NET_WM_WINDOW_TYPE_DOCK", XA_ATOM, ewmh_HandleDock),
197 ENTRY("_NET_WM_WINDOW_TYPE_MENU", XA_ATOM, ewmh_HandleMenu),
198 ENTRY("_NET_WM_WINDOW_TYPE_NORMAL", XA_ATOM, ewmh_HandleNormal),
199 ENTRY("_NET_WM_WINDOW_TYPE_TOOLBAR", XA_ATOM, ewmh_HandleToolBar),
200 {NULL,0,0,0}
203 /* EWMH ATOM_LIST_FIXED_PROPERTY
204 * property that have a window at startup and which should not change */
205 ewmh_atom ewmh_atom_fixed_property[] =
207 ENTRY("_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", XA_WINDOW, None),
208 ENTRY("_NET_WM_HANDLED_ICON", XA_ATOM, None),
209 ENTRY("_NET_WM_PID", XA_ATOM, None),
210 ENTRY("_NET_WM_WINDOW_TYPE", XA_ATOM, None),
211 {NULL,0,0,0}
214 /* EWMH ATOM_LIST_PROPERTY_NOTIFY
215 * properties of a window which is updated by the window via a PropertyNotify
216 * event */
217 ewmh_atom ewmh_atom_property_notify[] =
219 ENTRY("_NET_WM_ICON", XA_CARDINAL, ewmh_WMIcon),
220 ENTRY("_NET_WM_ICON_GEOMETRY", XA_CARDINAL, ewmh_WMIconGeometry),
221 ENTRY("_NET_WM_ICON_NAME", None, EWMH_WMIconName),
222 ENTRY("_NET_WM_NAME", None, EWMH_WMName),
223 ENTRY("_NET_WM_STRUT", XA_CARDINAL, ewmh_WMStrut),
224 {NULL,0,0,0}
227 /* EWMH_ATOM_LIST_FVWM_ROOT: root atom that should be maintained by fvwm only
229 ewmh_atom ewmh_atom_fvwm_root[] =
231 ENTRY("_KDE_NET_SYSTEM_TRAY_WINDOWS", XA_WINDOW, None),
232 ENTRY("_NET_CLIENT_LIST", XA_WINDOW, None),
233 ENTRY("_NET_CLIENT_LIST_STACKING", XA_WINDOW, None),
234 ENTRY("_NET_SUPPORTED", XA_ATOM, None),
235 ENTRY("_NET_SUPPORTING_WM_CHECK", XA_WINDOW, None),
236 ENTRY("_NET_VIRTUAL_ROOTS", XA_WINDOW, None),
237 ENTRY("_NET_WORKAREA", XA_CARDINAL, None),
238 {NULL,0,0,0}
241 /* EWMH_ATOM_LIST_FVWM_WIN: window atom that should be maintained by fvwm
242 * only */
243 ewmh_atom ewmh_atom_fvwm_win[] =
245 ENTRY("_KDE_NET_WM_FRAME_STRUT", XA_CARDINAL, None),
246 ENTRY("_NET_FRAME_EXTENTS", XA_CARDINAL, None),
247 ENTRY("_NET_WM_ALLOWED_ACTIONS", XA_ATOM, None),
248 ENTRY("_NET_WM_ICON_VISIBLE_NAME", None, None),
249 ENTRY("_NET_WM_VISIBLE_NAME", None, None),
250 {NULL,0,0,0}
254 #define NUMBER_OF_ATOM_LISTS 9
255 #define L_ENTRY(x,y) {x,y,sizeof(y)/sizeof(ewmh_atom)}
256 ewmh_atom_list atom_list[] =
258 L_ENTRY(EWMH_ATOM_LIST_CLIENT_ROOT, ewmh_atom_client_root),
259 L_ENTRY(EWMH_ATOM_LIST_CLIENT_WIN, ewmh_atom_client_win),
260 L_ENTRY(EWMH_ATOM_LIST_WM_STATE, ewmh_atom_wm_state),
261 L_ENTRY(EWMH_ATOM_LIST_ALLOWED_ACTIONS, ewmh_atom_allowed_actions),
262 L_ENTRY(EWMH_ATOM_LIST_WINDOW_TYPE, ewmh_atom_window_type),
263 L_ENTRY(EWMH_ATOM_LIST_FIXED_PROPERTY, ewmh_atom_fixed_property),
264 L_ENTRY(EWMH_ATOM_LIST_PROPERTY_NOTIFY, ewmh_atom_property_notify),
265 L_ENTRY(EWMH_ATOM_LIST_FVWM_ROOT, ewmh_atom_fvwm_root),
266 L_ENTRY(EWMH_ATOM_LIST_FVWM_WIN, ewmh_atom_fvwm_win),
267 L_ENTRY(EWMH_ATOM_LIST_END, NULL)
271 * Atoms utilities
274 static
275 int compare(const void *a, const void *b)
277 return (strcmp((char *)a, ((ewmh_atom *)b)->name));
280 static
281 ewmh_atom *get_ewmh_atom_by_name(
282 const char *atom_name, ewmh_atom_list_name list_name)
284 ewmh_atom *a = NULL;
285 Bool done = 0;
286 int i = 0;
288 while(!done && atom_list[i].name != EWMH_ATOM_LIST_END)
290 if (atom_list[i].name == list_name ||
291 list_name == EWMH_ATOM_LIST_ALL)
293 a = (ewmh_atom *)bsearch(
294 atom_name, atom_list[i].list,
295 atom_list[i].size - 1, sizeof(ewmh_atom),
296 compare);
297 if (a != NULL || list_name != EWMH_ATOM_LIST_ALL)
299 done = 1;
302 i++;
305 return a;
308 ewmh_atom *ewmh_GetEwmhAtomByAtom(Atom atom, ewmh_atom_list_name list_name)
310 Bool done = 0;
311 int i = 0;
313 while(!done && atom_list[i].name != EWMH_ATOM_LIST_END)
315 if (atom_list[i].name == list_name ||
316 list_name == EWMH_ATOM_LIST_ALL)
318 ewmh_atom *list = atom_list[i].list;
319 while(list->name != NULL)
321 if (atom == list->atom)
323 return list;
325 list++;
327 if (atom_list[i].name == list_name)
329 return NULL;
332 i++;
335 return NULL;
338 static int atom_size(int format)
340 if (format == 32)
342 return sizeof(long);
344 else
346 return (format >> 3);
350 void ewmh_ChangeProperty(
351 Window w, const char *atom_name, ewmh_atom_list_name list,
352 unsigned char *data, int length)
354 ewmh_atom *a;
355 int format = 32;
357 if ((a = get_ewmh_atom_by_name(atom_name, list)) != NULL)
359 int asize;
360 int free_data = 0;
362 if (a->atom_type == XA_UTF8_STRING)
364 format = 8;
367 asize = atom_size(format);
368 if (
369 format == 32 && asize * 8 != format &&
370 strcmp(atom_name, "_NET_WM_ICON") == 0)
372 long *datacopy = (long*)safemalloc(asize * length);
373 int i;
375 for (i = 0; i < length; i++)
377 datacopy[i] = ((CARD32 *)data)[i];
379 data = (unsigned char*)datacopy;
380 free_data = 1;
382 XChangeProperty(
383 dpy, w, a->atom, a->atom_type , format,
384 PropModeReplace, data, length);
386 if (free_data)
388 free(data);
392 return;
395 void ewmh_DeleteProperty(
396 Window w, const char *atom_name, ewmh_atom_list_name list)
398 ewmh_atom *a;
400 if ((a = get_ewmh_atom_by_name(atom_name, list)) != NULL)
402 XDeleteProperty(dpy, w, a->atom);
405 return;
408 static
409 void *atom_get(Window win, Atom to_get, Atom type, int *size)
411 unsigned char *retval;
412 Atom type_ret;
413 unsigned long bytes_after, num_ret;
414 long length;
415 int format_ret;
416 void *data;
417 int ok;
419 retval = NULL;
420 length = 0x7fffffff;
421 ok = XGetWindowProperty(
422 dpy, win, to_get, 0L, length, False, type, &type_ret,
423 &format_ret, &num_ret, &bytes_after, &retval);
425 if ((ok == Success) && (retval) && (num_ret > 0) && (format_ret > 0))
427 int asize;
429 asize = atom_size(format_ret);
430 data = safemalloc(num_ret * asize);
431 if (format_ret == 32 && asize * 8 != format_ret)
433 int i;
435 for (i = 0; i < num_ret; i++)
437 ((CARD32 *)data)[i] = ((long *)retval)[i];
440 else
442 if (data)
444 memcpy(data, retval, num_ret * asize);
447 XFree(retval);
448 *size = num_ret * (format_ret >> 3);
450 return data;
452 if (retval)
454 XFree(retval);
457 return NULL;
460 void *ewmh_AtomGetByName(
461 Window win, const char *atom_name, ewmh_atom_list_name list,
462 int *size)
464 ewmh_atom *a;
465 void *data = NULL;
467 if ((a = get_ewmh_atom_by_name(atom_name, list)) != NULL)
469 data = atom_get(win, a->atom, a->atom_type, size);
472 return data;
476 * client_root: here the client is fvwm
478 static
479 int check_desk(void)
481 int d = -1;
482 FvwmWindow *fw;
484 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
486 if (!IS_STICKY_ACROSS_DESKS(fw))
488 d = max(d, fw->Desk);
492 return d;
495 void EWMH_SetCurrentDesktop(void)
497 long val;
499 val = Scr.CurrentDesk;
501 if (val < 0 || (val >= ewmhc.MaxDesktops && ewmhc.MaxDesktops != 0))
503 return;
506 if (val >= ewmhc.CurrentNumberOfDesktops ||
507 (ewmhc.NumberOfDesktops != ewmhc.CurrentNumberOfDesktops &&
508 val < ewmhc.CurrentNumberOfDesktops))
510 EWMH_SetNumberOfDesktops();
513 ewmh_ChangeProperty(Scr.Root,"_NET_CURRENT_DESKTOP",
514 EWMH_ATOM_LIST_CLIENT_ROOT,
515 (unsigned char *)&val, 1);
517 return;
520 void EWMH_SetNumberOfDesktops(void)
522 long val;
524 if (ewmhc.CurrentNumberOfDesktops < ewmhc.NumberOfDesktops)
526 ewmhc.CurrentNumberOfDesktops = ewmhc.NumberOfDesktops;
529 if (ewmhc.CurrentNumberOfDesktops > ewmhc.NumberOfDesktops ||
530 ewmhc.NeedsToCheckDesk)
532 int d = check_desk();
534 ewmhc.NeedsToCheckDesk = False;
535 if (d >= ewmhc.MaxDesktops && ewmhc.MaxDesktops != 0)
536 d = 0;
537 ewmhc.CurrentNumberOfDesktops =
538 max(ewmhc.NumberOfDesktops, d+1);
541 if (Scr.CurrentDesk >= ewmhc.CurrentNumberOfDesktops &&
542 (Scr.CurrentDesk < ewmhc.MaxDesktops || ewmhc.MaxDesktops == 0))
544 ewmhc.CurrentNumberOfDesktops = Scr.CurrentDesk + 1;
547 val = (long)ewmhc.CurrentNumberOfDesktops;
548 ewmh_ChangeProperty(Scr.Root, "_NET_NUMBER_OF_DESKTOPS",
549 EWMH_ATOM_LIST_CLIENT_ROOT,
550 (unsigned char *)&val, 1);
551 ewmh_SetWorkArea();
553 return;
556 void EWMH_SetDesktopViewPort(void)
558 long val[256][2]; /* no more than 256 desktops */
559 int i = 0;
561 while(i < ewmhc.NumberOfDesktops && i < 256)
563 val[i][0] = Scr.Vx;
564 val[i][1] = Scr.Vy;
565 i++;
567 ewmh_ChangeProperty(
568 Scr.Root, "_NET_DESKTOP_VIEWPORT", EWMH_ATOM_LIST_CLIENT_ROOT,
569 (unsigned char *)&val, i*2);
571 return;
574 void EWMH_SetDesktopGeometry(void)
576 long val[2];
578 val[0] = Scr.VxMax + Scr.MyDisplayWidth;
579 val[1] = Scr.VyMax + Scr.MyDisplayHeight;
580 ewmh_ChangeProperty(
581 Scr.Root,"_NET_DESKTOP_GEOMETRY", EWMH_ATOM_LIST_CLIENT_ROOT,
582 (unsigned char *)&val, 2);
584 return;
588 * client_win: here the client is fvwm
590 void EWMH_SetActiveWindow(Window w)
592 ewmh_ChangeProperty(
593 Scr.Root, "_NET_ACTIVE_WINDOW", EWMH_ATOM_LIST_CLIENT_WIN,
594 (unsigned char *)&w, 1);
596 return;
599 void EWMH_SetWMDesktop(FvwmWindow *fw)
601 long desk = fw->Desk;
603 if (IS_STICKY_ACROSS_DESKS(fw))
605 desk = (unsigned long)-1;
607 else if (desk >= ewmhc.CurrentNumberOfDesktops)
609 ewmhc.NeedsToCheckDesk = True;
610 EWMH_SetNumberOfDesktops();
612 ewmh_ChangeProperty(
613 FW_W(fw), "_NET_WM_DESKTOP", EWMH_ATOM_LIST_CLIENT_WIN,
614 (unsigned char *)&desk, 1);
616 return;
620 * fvwm must maintain the _NET_WM_STATE
623 void EWMH_SetWMState(FvwmWindow *fw, Bool do_restore)
625 Atom wm_state[EWMH_NUMBER_OF_STATE];
626 int i = 0;
627 ewmh_atom *list = ewmh_atom_wm_state;
629 while(list->name != NULL)
631 if (list->action(fw, NULL, NULL, do_restore))
633 wm_state[i++] = list->atom;
635 list++;
638 if (i > 0)
640 ewmh_ChangeProperty(
641 FW_W(fw), "_NET_WM_STATE", EWMH_ATOM_LIST_CLIENT_WIN,
642 (unsigned char *)wm_state, i);
644 else
646 ewmh_DeleteProperty(
647 FW_W(fw), "_NET_WM_STATE",
648 EWMH_ATOM_LIST_CLIENT_WIN);
651 return;
655 * fvwm_root
658 /*** kde system tray ***/
659 /* #define DEBUG_KST */
660 static
661 void add_kst_item(Window w)
663 KstItem *t,**prev;
665 t = ewmh_KstWinList;
666 prev = &ewmh_KstWinList;
668 while(t != NULL)
670 prev = &(t->next);
671 t = t->next;
673 *prev = (KstItem *)safemalloc(sizeof(KstItem));
674 (*prev)->w = w;
675 (*prev)->next = NULL;
677 return;
680 static
681 void delete_kst_item(Window w)
683 KstItem *t,**prev;
685 t = ewmh_KstWinList;
686 prev = &ewmh_KstWinList;
687 while((t!= NULL)&&(t->w != w))
689 prev = &(t->next);
690 t = t->next;
692 if (t == NULL)
694 return;
696 if(prev != NULL)
698 *prev = t->next;
700 free(t);
702 return;
705 static
706 void set_kde_sys_tray(void)
708 Window *wins = NULL;
709 KstItem *t;
710 int i = 0, nbr = 0;
712 t = ewmh_KstWinList;
713 while(t != NULL)
715 nbr++;
716 t = t->next;
719 if (nbr > 0)
721 wins = (Window *)safemalloc(sizeof(Window) * nbr);
724 t = ewmh_KstWinList;
725 #ifdef DEBUG_KST
726 fprintf(stderr,"ADD_TO_KST: ");
727 #endif
728 while (t != NULL)
730 #ifdef DEBUG_KST
731 fprintf(stderr,"0x%lx ",t->w);
732 #endif
733 wins[i++] = t->w;
734 t = t->next;
736 #ifdef DEBUG_KST
737 fprintf(stderr,"\n");
738 #endif
740 ewmh_ChangeProperty(Scr.Root,"_KDE_NET_SYSTEM_TRAY_WINDOWS",
741 EWMH_ATOM_LIST_FVWM_ROOT,
742 (unsigned char *)wins,i);
743 if (wins != NULL)
745 free(wins);
748 return;
751 void ewmh_AddToKdeSysTray(FvwmWindow *fw)
753 int size = 0;
754 CARD32 *val;
755 KstItem *t;
757 val = ewmh_AtomGetByName(
758 FW_W(fw), "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
759 EWMH_ATOM_LIST_FIXED_PROPERTY, &size);
761 if (val == NULL)
763 return;
765 free(val);
767 t = ewmh_KstWinList;
768 while(t != NULL && t->w != FW_W(fw))
769 t = t->next;
771 if (t != NULL)
773 return; /* already in the list */
776 add_kst_item(FW_W(fw));
777 set_kde_sys_tray();
779 return;
782 #if 0
783 /* not used at present time */
784 void ewmh_FreeKdeSysTray(void)
786 KstItem *t;
788 t = ewmh_KstWinList;
789 while(t != NULL)
791 XSelectInput(dpy, t->w, NoEventMask);
792 delete_kst_item(t->w);
793 t = ewmh_KstWinList;
795 set_kde_sys_tray();
797 return;
799 #endif
801 int EWMH_IsKdeSysTrayWindow(Window w)
803 KstItem *t;
805 t = ewmh_KstWinList;
806 while(t != NULL && t->w != w)
808 t = t->next;
810 if (t == NULL)
812 return 0;
814 #ifdef DEBUG_KST
815 fprintf(stderr,"IsKdeSysTrayWindow: 0x%lx\n", w);
816 #endif
818 return 1;
821 void EWMH_ManageKdeSysTray(Window w, int type)
823 KstItem *t;
825 t = ewmh_KstWinList;
826 while(t != NULL && t->w != w)
828 t = t->next;
830 if (t == NULL)
832 return;
834 switch(type)
836 case UnmapNotify:
837 #ifdef DEBUG_KST
838 fprintf(stderr,"KST_UNMAP: 0x%lx\n", w);
839 #endif
840 XSelectInput(dpy, w, StructureNotifyMask);
841 XFlush(dpy);
842 break;
843 case DestroyNotify:
844 #ifdef DEBUG_KST
845 fprintf(stderr,"KST_DESTROY: 0x%lx\n", w);
846 #endif
847 XSelectInput(dpy, t->w, NoEventMask);
848 XFlush(dpy);
849 delete_kst_item(w);
850 set_kde_sys_tray();
851 break;
852 case ReparentNotify:
853 #ifdef DEBUG_KST
854 fprintf(stderr,"KST_Reparent: 0x%lx\n", w);
855 #endif
856 XSelectInput(dpy, w, StructureNotifyMask);
857 XFlush(dpy);
858 break;
859 default:
860 #ifdef DEBUG_KST
861 fprintf(stderr,"KST_NO: 0x%lx\n", w);
862 #endif
863 break;
866 return;
869 /**** Client lists ****/
871 void EWMH_SetClientList(void)
873 Window *wl = NULL;
874 FvwmWindow *fw;
875 int nbr = 0;
876 int i = 0;
878 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
880 nbr++;
882 if (nbr != 0)
884 wl = (Window *)safemalloc(sizeof(Window) * nbr);
885 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
887 wl[i++] = FW_W(fw);
890 ewmh_ChangeProperty(
891 Scr.Root,"_NET_CLIENT_LIST", EWMH_ATOM_LIST_FVWM_ROOT,
892 (unsigned char *)wl, nbr);
893 if (wl != NULL)
895 free (wl);
898 return;
901 void EWMH_SetClientListStacking(void)
903 Window *wl = NULL;
904 FvwmWindow *fw;
905 int nbr = 0;
906 int i = 0;
908 for (
909 fw = Scr.FvwmRoot.stack_next; fw != &Scr.FvwmRoot;
910 fw = fw->stack_next)
912 nbr++;
914 i = nbr-1;
915 if (nbr != 0)
917 wl = (Window *)safemalloc(sizeof(Window) * nbr);
918 for (
919 fw = Scr.FvwmRoot.stack_next; fw != &Scr.FvwmRoot;
920 fw = fw->stack_next)
922 wl[i--] = FW_W(fw);
925 ewmh_ChangeProperty(
926 Scr.Root,"_NET_CLIENT_LIST_STACKING", EWMH_ATOM_LIST_FVWM_ROOT,
927 (unsigned char *)wl, nbr);
928 if (wl != NULL)
930 free (wl);
933 return;
936 /**** Working Area stuff ****/
937 /**** At present time we support only sticky windows with strut ****/
939 void ewmh_SetWorkArea(void)
941 long val[256][4]; /* no more than 256 desktops */
942 int i = 0;
944 while(i < ewmhc.NumberOfDesktops && i < 256)
946 val[i][0] = Scr.Desktops->ewmh_working_area.x;
947 val[i][1] = Scr.Desktops->ewmh_working_area.y;
948 val[i][2] = Scr.Desktops->ewmh_working_area.width;
949 val[i][3] = Scr.Desktops->ewmh_working_area.height;
950 i++;
952 ewmh_ChangeProperty(
953 Scr.Root, "_NET_WORKAREA", EWMH_ATOM_LIST_FVWM_ROOT,
954 (unsigned char *)&val, i*4);
956 return;
959 void ewmh_ComputeAndSetWorkArea(void)
961 int left = ewmhc.BaseStrut.left;
962 int right = ewmhc.BaseStrut.right;
963 int top = ewmhc.BaseStrut.top;
964 int bottom = ewmhc.BaseStrut.bottom;
965 int x,y,width,height;
966 FvwmWindow *fw;
968 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
970 if (
971 DO_EWMH_IGNORE_STRUT_HINTS(fw) ||
972 !IS_STICKY_ACROSS_PAGES(fw))
974 continue;
976 left = max(left, fw->strut.left);
977 right = max(right, fw->strut.right);
978 top = max(top, fw->strut.top);
979 bottom = max(bottom, fw->strut.bottom);
982 x = left;
983 y = top;
984 width = Scr.MyDisplayWidth - (left + right);
985 height = Scr.MyDisplayHeight - (top + bottom);
987 if (
988 Scr.Desktops->ewmh_working_area.x != x ||
989 Scr.Desktops->ewmh_working_area.y != y ||
990 Scr.Desktops->ewmh_working_area.width != width ||
991 Scr.Desktops->ewmh_working_area.height != height)
993 Scr.Desktops->ewmh_working_area.x = x;
994 Scr.Desktops->ewmh_working_area.y = y;
995 Scr.Desktops->ewmh_working_area.width = width;
996 Scr.Desktops->ewmh_working_area.height = height;
997 ewmh_SetWorkArea();
1000 return;
1003 void ewmh_HandleDynamicWorkArea(void)
1005 int dyn_left = ewmhc.BaseStrut.left;
1006 int dyn_right = ewmhc.BaseStrut.right;
1007 int dyn_top = ewmhc.BaseStrut.top;
1008 int dyn_bottom = ewmhc.BaseStrut.bottom;
1009 int x,y,width,height;
1010 FvwmWindow *fw;
1012 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
1014 if (
1015 DO_EWMH_IGNORE_STRUT_HINTS(fw) ||
1016 !IS_STICKY_ACROSS_PAGES(fw))
1018 continue;
1020 dyn_left = max(dyn_left, fw->dyn_strut.left);
1021 dyn_right = max(dyn_right, fw->dyn_strut.right);
1022 dyn_top = max(dyn_top, fw->dyn_strut.top);
1023 dyn_bottom = max(dyn_bottom, fw->dyn_strut.bottom);
1026 x = dyn_left;
1027 y = dyn_top;
1028 width = Scr.MyDisplayWidth - (dyn_left + dyn_right);
1029 height = Scr.MyDisplayHeight - (dyn_top + dyn_bottom);
1031 if (
1032 Scr.Desktops->ewmh_dyn_working_area.x != x ||
1033 Scr.Desktops->ewmh_dyn_working_area.y != y ||
1034 Scr.Desktops->ewmh_dyn_working_area.width != width ||
1035 Scr.Desktops->ewmh_dyn_working_area.height != height)
1037 Scr.Desktops->ewmh_dyn_working_area.x = x;
1038 Scr.Desktops->ewmh_dyn_working_area.y = y;
1039 Scr.Desktops->ewmh_dyn_working_area.width = width;
1040 Scr.Desktops->ewmh_dyn_working_area.height = height;
1041 /* here we may update the maximized window ...etc */
1044 return;
1047 void EWMH_UpdateWorkArea(void)
1049 ewmh_ComputeAndSetWorkArea();
1050 ewmh_HandleDynamicWorkArea();
1052 return;
1055 void EWMH_GetWorkAreaIntersection(
1056 FvwmWindow *fw, int *x, int *y, int *w, int *h, int type)
1058 int nx,ny,nw,nh;
1059 int area_x = Scr.Desktops->ewmh_working_area.x;
1060 int area_y = Scr.Desktops->ewmh_working_area.y;
1061 int area_w = Scr.Desktops->ewmh_working_area.width;
1062 int area_h = Scr.Desktops->ewmh_working_area.height;
1063 Bool is_dynamic = False;
1065 switch(type)
1067 case EWMH_IGNORE_WORKING_AREA:
1068 return;
1069 case EWMH_USE_WORKING_AREA:
1070 break;
1071 case EWMH_USE_DYNAMIC_WORKING_AREA:
1072 is_dynamic = True;
1073 break;
1074 default:
1075 break;
1077 if (is_dynamic)
1079 area_x = Scr.Desktops->ewmh_dyn_working_area.x;
1080 area_y = Scr.Desktops->ewmh_dyn_working_area.y;
1081 area_w = Scr.Desktops->ewmh_dyn_working_area.width;
1082 area_h = Scr.Desktops->ewmh_dyn_working_area.height;
1084 nx = max(*x, area_x);
1085 ny = max(*y, area_y);
1086 nw = min(*x + *w, area_x + area_w) - nx;
1087 nh = min(*y + *h, area_y + area_h) - ny;
1088 *x = nx;
1089 *y = ny;
1090 *w = nw;
1091 *h = nh;
1093 return;
1096 static
1097 float get_intersection(
1098 int x11, int y11, int x12, int y12, int x21, int y21, int x22, int y22,
1099 Bool use_percent)
1101 float ret = 0;
1102 int xl, xr, yt, yb;
1104 if (x11 < x22 && x12 > x21 && y11 < y22 && y12 > y21)
1106 xl = max(x11, x21);
1107 xr = min(x12, x22);
1108 yt = max(y11, y21);
1109 yb = min(y12, y22);
1110 ret = (xr - xl) * (yb - yt);
1112 if (use_percent &&
1113 (x22 - x21) * (y22 - y21) != 0 && (x12 - x11) * (y12 - y11) != 0)
1115 ret = 100 * max(ret / ((x22 - x21) * (y22 - y21)),
1116 ret / ((x12 - x11) * (y12 - y11)));
1119 return ret;
1122 static
1123 float ewmh_GetStrutIntersection(
1124 int x11, int y11, int x12, int y12,
1125 int left, int right, int top, int bottom,
1126 Bool use_percent)
1128 float ret = 0;
1129 int x21, y21, x22, y22;
1131 /* left */
1132 x21 = 0;
1133 y21 = 0;
1134 x22 = left;
1135 y22 = Scr.MyDisplayHeight;
1136 ret += get_intersection(
1137 x11, y11, x12, y12, x21, y21, x22, y22, use_percent);
1138 /* right */
1139 x21 = Scr.MyDisplayWidth - right;
1140 y21 = 0;
1141 x22 = Scr.MyDisplayWidth;
1142 y22 = Scr.MyDisplayHeight;
1143 ret += get_intersection(
1144 x11, y11, x12, y12, x21, y21, x22, y22, use_percent);
1145 /* top */
1146 x21 = 0;
1147 y21 = 0;
1148 x22 = Scr.MyDisplayWidth;
1149 y22 = top;
1150 ret += get_intersection(
1151 x11, y11, x12, y12, x21, y21, x22, y22, use_percent);
1152 /* bottom */
1153 x21 = 0;
1154 y21 = Scr.MyDisplayHeight - bottom;
1155 x22 = Scr.MyDisplayWidth;
1156 y22 = Scr.MyDisplayHeight;
1157 ret += get_intersection(
1158 x11, y11, x12, y12, x21, y21, x22, y22, use_percent);
1160 return ret;
1163 float EWMH_GetBaseStrutIntersection(
1164 int x11, int y11, int x12, int y12, Bool use_percent)
1166 return ewmh_GetStrutIntersection(
1167 x11, y11, x12, y12, ewmhc.BaseStrut.left,
1168 ewmhc.BaseStrut.right, ewmhc.BaseStrut.top,
1169 ewmhc.BaseStrut.bottom, use_percent);
1172 float EWMH_GetStrutIntersection(
1173 int x11, int y11, int x12, int y12, Bool use_percent)
1175 int left, right, top, bottom;
1177 left = Scr.Desktops->ewmh_working_area.x;
1178 right = Scr.MyDisplayWidth -
1179 (Scr.Desktops->ewmh_working_area.x
1180 + Scr.Desktops->ewmh_working_area.width);
1181 top = Scr.Desktops->ewmh_working_area.y;
1182 bottom = Scr.MyDisplayHeight -
1183 (Scr.Desktops->ewmh_working_area.y
1184 + Scr.Desktops->ewmh_working_area.height);
1186 return ewmh_GetStrutIntersection(
1187 x11, y11, x12, y12, left, right, top, bottom, use_percent);
1191 * fvwm_win
1193 void EWMH_SetFrameStrut(FvwmWindow *fw)
1195 long val[4];
1196 size_borders b;
1198 if (EWMH_IsKdeSysTrayWindow(FW_W(fw)))
1200 /* Fixed position of tray window in kicker */
1201 return;
1203 get_window_borders(fw, &b);
1205 /* left */
1206 val[0] = b.top_left.width;
1207 /* right */
1208 val[1] = b.bottom_right.width;
1209 /* top */
1210 val[2] = b.top_left.height;
1211 /* bottom */
1212 val[3] = b.bottom_right.height;
1214 ewmh_ChangeProperty(
1215 FW_W(fw), "_KDE_NET_WM_FRAME_STRUT", EWMH_ATOM_LIST_FVWM_WIN,
1216 (unsigned char *)&val, 4);
1217 ewmh_ChangeProperty(
1218 FW_W(fw), "_NET_FRAME_EXTENTS", EWMH_ATOM_LIST_FVWM_WIN,
1219 (unsigned char *)&val, 4);
1221 return;
1225 * allowed actions
1227 Bool ewmh_AllowsYes(EWMH_CMD_ARGS)
1229 return True;
1232 Bool ewmh_AllowsClose(EWMH_CMD_ARGS)
1234 return is_function_allowed(
1235 F_CLOSE, NULL, fw, RQORIG_PROGRAM_US, False);
1238 Bool ewmh_AllowsFullScreen(EWMH_CMD_ARGS)
1240 if (
1241 !is_function_allowed(
1242 F_MAXIMIZE, NULL, fw, RQORIG_PROGRAM_US, False) ||
1243 !is_function_allowed(
1244 F_MOVE, NULL, fw, RQORIG_PROGRAM_US, False) ||
1245 !is_function_allowed(
1246 F_RESIZE, NULL, fw, RQORIG_PROGRAM_US, True))
1248 return False;
1251 return True;
1254 Bool ewmh_AllowsMinimize(EWMH_CMD_ARGS)
1256 return is_function_allowed(F_ICONIFY, NULL, fw, RQORIG_PROGRAM_US, False);
1259 Bool ewmh_AllowsMaximize(EWMH_CMD_ARGS)
1261 return is_function_allowed(F_MAXIMIZE, NULL, fw, RQORIG_PROGRAM_US, False);
1264 Bool ewmh_AllowsMove(EWMH_CMD_ARGS)
1266 return is_function_allowed(F_MOVE, NULL, fw, RQORIG_PROGRAM_US, False);
1269 Bool ewmh_AllowsResize(EWMH_CMD_ARGS)
1271 return is_function_allowed(F_RESIZE, NULL, fw, RQORIG_PROGRAM_US, False);
1274 void EWMH_SetAllowedActions(FvwmWindow *fw)
1276 Atom wm_actions[EWMH_NUMBER_OF_ALLOWED_ACTIONS];
1277 int i = 0;
1278 ewmh_atom *list = ewmh_atom_allowed_actions;
1280 while(list->name != NULL)
1282 if (list->action(fw, NULL, NULL, 0))
1283 wm_actions[i++] = list->atom;
1284 list++;
1287 if (i > 0)
1289 ewmh_ChangeProperty(
1290 FW_W(fw), "_NET_WM_ALLOWED_ACTIONS",
1291 EWMH_ATOM_LIST_FVWM_WIN, (unsigned char *)wm_actions,
1294 else
1296 ewmh_DeleteProperty(
1297 FW_W(fw), "_NET_WM_ALLOWED_ACTIONS",
1298 EWMH_ATOM_LIST_FVWM_WIN);
1301 return;
1305 * Window types
1308 int ewmh_HandleDesktop(EWMH_CMD_ARGS)
1310 if (Scr.EwmhDesktop != NULL && FW_W(Scr.EwmhDesktop) != FW_W(fw))
1312 fvwm_msg(
1313 WARN,"ewmh_HandleDesktop",
1314 "A Desktop application (0x%lx) already runs! This"
1315 " can cause problems\n", FW_W(Scr.EwmhDesktop));
1316 /* what to do ? */
1319 fw->ewmh_window_type = EWMH_WINDOW_TYPE_DESKTOP_ID;
1320 Scr.EwmhDesktop = fw;
1322 SSET_LAYER(*style, 0);
1323 style->flags.use_layer = 1;
1324 style->flag_mask.use_layer = 1;
1325 style->change_mask.use_layer = 1;
1327 S_SET_IS_STICKY_ACROSS_PAGES(SCF(*style), 1);
1328 S_SET_IS_STICKY_ACROSS_PAGES(SCM(*style), 1);
1329 S_SET_IS_STICKY_ACROSS_PAGES(SCC(*style), 1);
1330 S_SET_IS_STICKY_ACROSS_DESKS(SCF(*style), 1);
1331 S_SET_IS_STICKY_ACROSS_DESKS(SCM(*style), 1);
1332 S_SET_IS_STICKY_ACROSS_DESKS(SCC(*style), 1);
1334 S_SET_IS_FIXED(SCF(*style), 1);
1335 S_SET_IS_FIXED(SCM(*style), 1);
1336 S_SET_IS_FIXED(SCC(*style), 1);
1338 S_SET_DO_WINDOW_LIST_SKIP(SCF(*style), 1);
1339 S_SET_DO_WINDOW_LIST_SKIP(SCM(*style), 1);
1340 S_SET_DO_WINDOW_LIST_SKIP(SCC(*style), 1);
1342 S_SET_DO_CIRCULATE_SKIP(SCF(*style), 1);
1343 S_SET_DO_CIRCULATE_SKIP(SCM(*style), 1);
1344 S_SET_DO_CIRCULATE_SKIP(SCC(*style), 1);
1346 S_SET_IS_UNICONIFIABLE(SCF(*style), 1);
1347 S_SET_IS_UNICONIFIABLE(SCM(*style), 1);
1348 S_SET_IS_UNICONIFIABLE(SCC(*style), 1);
1350 S_SET_IS_UNMAXIMIZABLE(SCF(*style), 1);
1351 S_SET_IS_UNMAXIMIZABLE(SCM(*style), 1);
1352 S_SET_IS_UNMAXIMIZABLE(SCC(*style), 1);
1354 /* No border */
1355 SSET_BORDER_WIDTH(*style, 0);
1356 style->flags.has_border_width = 1;
1357 style->flag_mask.has_border_width = 1;
1358 style->change_mask.has_border_width = 1;
1360 SSET_HANDLE_WIDTH(*style, 0);
1361 style->flags.has_handle_width = 1;
1362 style->flag_mask.has_handle_width = 1;
1363 style->change_mask.has_handle_width = 1;
1365 /* no title */
1366 style->flags.has_no_title = 1;
1367 style->flag_mask.has_no_title = 1;
1368 style->change_mask.has_no_title = 1;
1370 /* ClickToFocus, I do not think we should use NeverFocus */
1371 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCF(*style)), 1);
1372 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCM(*style)), 1);
1373 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCC(*style)), 1);
1374 FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCF(*style)), 1);
1375 FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCM(*style)), 1);
1376 FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCC(*style)), 1);
1378 /* ClickToFocusPassesClick */
1379 FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCF(*style)), 1);
1380 FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1381 FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1382 FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCF(*style)), 1);
1383 FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1384 FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1386 /* not useful */
1387 FPS_RAISE_FOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCF(*style)), 0);
1388 FPS_RAISE_FOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1389 FPS_RAISE_FOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1390 FPS_RAISE_UNFOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCF(*style)), 0);
1391 FPS_RAISE_UNFOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1392 FPS_RAISE_UNFOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1393 FPS_RAISE_FOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCF(*style)), 0);
1394 FPS_RAISE_FOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1395 FPS_RAISE_FOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1396 FPS_RAISE_UNFOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCF(*style)), 0);
1397 FPS_RAISE_UNFOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1398 FPS_RAISE_UNFOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1400 return 1;
1403 int ewmh_HandleDialog(EWMH_CMD_ARGS)
1405 fw->ewmh_window_type = EWMH_WINDOW_TYPE_DIALOG_ID;
1407 return 0;
1410 int ewmh_HandleDock(EWMH_CMD_ARGS)
1412 fw->ewmh_window_type = EWMH_WINDOW_TYPE_DOCK_ID;
1414 S_SET_IS_STICKY_ACROSS_PAGES(SCF(*style), 1);
1415 S_SET_IS_STICKY_ACROSS_PAGES(SCM(*style), 1);
1416 S_SET_IS_STICKY_ACROSS_PAGES(SCC(*style), 1);
1417 S_SET_IS_STICKY_ACROSS_DESKS(SCF(*style), 1);
1418 S_SET_IS_STICKY_ACROSS_DESKS(SCM(*style), 1);
1419 S_SET_IS_STICKY_ACROSS_DESKS(SCC(*style), 1);
1421 S_SET_DO_WINDOW_LIST_SKIP(SCF(*style), 1);
1422 S_SET_DO_WINDOW_LIST_SKIP(SCM(*style), 1);
1423 S_SET_DO_WINDOW_LIST_SKIP(SCC(*style), 1);
1425 S_SET_DO_CIRCULATE_SKIP(SCF(*style), 1);
1426 S_SET_DO_CIRCULATE_SKIP(SCM(*style), 1);
1427 S_SET_DO_CIRCULATE_SKIP(SCC(*style), 1);
1429 S_SET_IS_UNICONIFIABLE(SCF(*style), 1);
1430 S_SET_IS_UNICONIFIABLE(SCM(*style), 1);
1431 S_SET_IS_UNICONIFIABLE(SCC(*style), 1);
1433 S_SET_IS_UNMAXIMIZABLE(SCF(*style), 1);
1434 S_SET_IS_UNMAXIMIZABLE(SCM(*style), 1);
1435 S_SET_IS_UNMAXIMIZABLE(SCC(*style), 1);
1437 if (fw->ewmh_hint_layer == -1)
1439 fw->ewmh_hint_layer = Scr.TopLayer;
1440 if (DO_EWMH_USE_STACKING_HINTS(style))
1442 SSET_LAYER(*style, Scr.TopLayer);
1443 style->flags.use_layer = 1;
1444 style->flag_mask.use_layer = 1;
1445 style->change_mask.use_layer = 1;
1447 else if (!style->change_mask.use_layer)
1449 SSET_LAYER(*style, Scr.DefaultLayer);
1450 style->flags.use_layer = 1;
1451 style->flag_mask.use_layer = 1;
1452 style->change_mask.use_layer = 1;
1455 /* no title ? MWM hints should be used by the app but ... */
1457 return 1;
1460 int ewmh_HandleMenu(EWMH_CMD_ARGS)
1462 fw->ewmh_window_type = EWMH_WINDOW_TYPE_MENU_ID;
1464 /* tear off menu */
1466 S_SET_DO_WINDOW_LIST_SKIP(SCF(*style), 1);
1467 S_SET_DO_WINDOW_LIST_SKIP(SCM(*style), 1);
1468 S_SET_DO_WINDOW_LIST_SKIP(SCC(*style), 1);
1470 S_SET_DO_CIRCULATE_SKIP(SCF(*style), 1);
1471 S_SET_DO_CIRCULATE_SKIP(SCM(*style), 1);
1472 S_SET_DO_CIRCULATE_SKIP(SCC(*style), 1);
1474 /* NeverFocus */
1475 FPS_LENIENT(S_FOCUS_POLICY(SCF(*style)), 0);
1476 FPS_LENIENT(S_FOCUS_POLICY(SCM(*style)), 1);
1477 FPS_LENIENT(S_FOCUS_POLICY(SCC(*style)), 1);
1479 FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCF(*style)), 0);
1480 FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCF(*style)), 0);
1481 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCF(*style)), 0);
1482 FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCF(*style)), 0);
1483 FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCF(*style)), 0);
1484 FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCF(*style)), 0);
1486 FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCM(*style)), 1);
1487 FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCC(*style)), 1);
1488 FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCM(*style)), 1);
1489 FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCC(*style)), 1);
1490 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCM(*style)), 1);
1491 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCC(*style)), 1);
1492 FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCM(*style)), 1);
1493 FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCC(*style)), 1);
1494 FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCM(*style)), 1);
1495 FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCC(*style)), 1);
1496 FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCM(*style)), 1);
1497 FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCC(*style)), 1);
1499 return 1;
1502 int ewmh_HandleNormal(EWMH_CMD_ARGS)
1504 fw->ewmh_window_type = EWMH_WINDOW_TYPE_NORMAL_ID;
1506 return 0;
1509 int ewmh_HandleToolBar(EWMH_CMD_ARGS)
1511 fw->ewmh_window_type = EWMH_WINDOW_TYPE_TOOLBAR_ID;
1513 /* this ok for KDE 2 (and 3??) but I do not think that a toolbar
1514 should be sticky */
1515 S_SET_IS_STICKY_ACROSS_PAGES(SCF(*style), 1);
1516 S_SET_IS_STICKY_ACROSS_PAGES(SCM(*style), 1);
1517 S_SET_IS_STICKY_ACROSS_PAGES(SCC(*style), 1);
1518 S_SET_IS_STICKY_ACROSS_DESKS(SCF(*style), 1);
1519 S_SET_IS_STICKY_ACROSS_DESKS(SCM(*style), 1);
1520 S_SET_IS_STICKY_ACROSS_DESKS(SCC(*style), 1);
1522 S_SET_DO_WINDOW_LIST_SKIP(SCF(*style), 1);
1523 S_SET_DO_WINDOW_LIST_SKIP(SCM(*style), 1);
1524 S_SET_DO_WINDOW_LIST_SKIP(SCC(*style), 1);
1526 S_SET_DO_CIRCULATE_SKIP(SCF(*style), 1);
1527 S_SET_DO_CIRCULATE_SKIP(SCM(*style), 1);
1528 S_SET_DO_CIRCULATE_SKIP(SCC(*style), 1);
1530 /* no title ? MWM hints should be used by the app but ... */
1532 return 1;
1535 void ewmh_HandleWindowType(FvwmWindow *fw, window_style *style)
1537 CARD32 *val;
1538 unsigned int nitems;
1539 ewmh_atom *list = ewmh_atom_window_type;
1540 int size = 0;
1541 int i = 0;
1542 Bool found = False;
1544 fw->ewmh_window_type = 0;
1545 if (DO_EWMH_IGNORE_WINDOW_TYPE(style))
1547 return;
1549 val = ewmh_AtomGetByName(
1550 FW_W(fw), "_NET_WM_WINDOW_TYPE",
1551 EWMH_ATOM_LIST_FIXED_PROPERTY, &size);
1552 if (val == NULL)
1554 return;
1556 /* we support only one window type: the first that we support */
1557 nitems = size / sizeof(CARD32);
1558 while(i < nitems && !found)
1560 list = ewmh_atom_window_type;
1561 while(list->name != NULL && !found)
1563 if (list->atom == val[i])
1565 list->action(fw, NULL, style, 0);
1566 found = True;
1568 list++;
1570 i++;
1572 free(val);
1574 return;
1578 * a workaround for ksmserver exit windows
1580 static
1581 int ksmserver_workarround(FvwmWindow *fw)
1584 if (fw->name.name != NULL && fw->class.res_name != NULL &&
1585 fw->icon_name.name != NULL && fw->class.res_class != NULL &&
1586 strcmp(fw->name.name, "ksmserver") == 0 &&
1587 strcmp(fw->class.res_class, "ksmserver") == 0 &&
1588 strcmp(fw->icon_name.name, "ksmserver") == 0 &&
1589 strcmp(fw->class.res_name, "unnamed") == 0)
1591 int layer = 0;
1593 if (IS_TRANSIENT(fw))
1595 layer = Scr.TopLayer + 2;
1597 else
1599 layer = Scr.TopLayer + 1;
1601 new_layer(fw, layer);
1603 return 1;
1606 return 0;
1610 * Window Initialisation / Destroy
1613 void EWMH_GetStyle(FvwmWindow *fw, window_style *style)
1615 if (style->change_mask.use_layer)
1617 fw->ewmh_normal_layer = SGET_LAYER(*style);
1619 else if (fw->ewmh_normal_layer == 0)
1621 fw->ewmh_normal_layer = Scr.DefaultLayer;
1623 ewmh_WMState(fw, NULL, style, 0);
1624 ewmh_WMDesktop(fw, NULL, style, 0);
1625 /* the window type override the state hint */
1626 ewmh_HandleWindowType(fw, style);
1628 return;
1631 static void ewmh_check_wm_pid(FvwmWindow *fw)
1633 int size = 0;
1634 CARD32 *val;
1636 fw->ewmh_window_type = 0;
1637 val = ewmh_AtomGetByName(
1638 FW_W(fw), "_NET_WM_PID", EWMH_ATOM_LIST_FIXED_PROPERTY, &size);
1639 if (val != NULL)
1641 free(val);
1642 SET_HAS_EWMH_WM_PID(fw, 1);
1643 if (CR_MOTION_METHOD(fw) == CR_MOTION_METHOD_AUTO)
1645 SET_CR_MOTION_METHOD(fw, CR_MOTION_METHOD_USE_GRAV);
1646 SET_CR_MOTION_METHOD_DETECTED(fw, 1);
1650 return;
1653 /* see also EWMH_WMName and EWMH_WMIconName in add_window */
1654 void EWMH_WindowInit(FvwmWindow *fw)
1656 /*EWMH_DLOG("Init window 0x%lx",FW_W(fw));*/
1657 EWMH_SetWMState(fw, False);
1658 EWMH_SetWMDesktop(fw);
1659 EWMH_SetAllowedActions(fw);
1660 ewmh_WMStrut(fw, NULL, NULL, 0);
1661 ewmh_WMIconGeometry(fw, NULL, NULL, 0);
1662 ewmh_AddToKdeSysTray(fw);
1663 EWMH_SetFrameStrut(fw);
1664 if (IS_EWMH_DESKTOP(FW_W(fw)))
1666 return;
1668 if (ksmserver_workarround(fw))
1670 return;
1672 ewmh_WMIcon(fw, NULL, NULL, 0);
1673 ewmh_check_wm_pid(fw);
1674 /*EWMH_DLOG("window 0x%lx initialised",FW_W(fw));*/
1676 return;
1679 /* unmap or reparent: restore state */
1680 void EWMH_RestoreInitialStates(FvwmWindow *fw, int event_type)
1682 EWMH_SetWMState(fw, True);
1683 if (HAS_EWMH_INIT_WM_DESKTOP(fw) == EWMH_STATE_HAS_HINT)
1685 ewmh_ChangeProperty(
1686 FW_W(fw), "_NET_WM_DESKTOP",
1687 EWMH_ATOM_LIST_CLIENT_WIN,
1688 (unsigned char *)&(fw->ewmh_hint_desktop), 1);
1690 else
1692 ewmh_DeleteProperty(
1693 FW_W(fw), "_NET_WM_DESKTOP",
1694 EWMH_ATOM_LIST_CLIENT_WIN);
1696 if (HAS_EWMH_WM_ICON_HINT(fw) == EWMH_FVWM_ICON)
1698 EWMH_DeleteWmIcon(fw, True, True);
1701 return;
1704 /* a window are going to be destroyed (in the add_window.c destroy_window
1705 * sens) */
1706 void EWMH_DestroyWindow(FvwmWindow *fw)
1708 if (IS_EWMH_DESKTOP(FW_W(fw)))
1710 Scr.EwmhDesktop = NULL;
1712 if (fw->Desk >= ewmhc.NumberOfDesktops)
1714 ewmhc.NeedsToCheckDesk = True;
1717 return;
1720 /* a window has been destroyed (unmap/reparent/destroy) */
1721 void EWMH_WindowDestroyed(void)
1723 EWMH_SetClientList();
1724 EWMH_SetClientListStacking();
1725 if (ewmhc.NeedsToCheckDesk)
1727 EWMH_SetNumberOfDesktops();
1729 ewmh_ComputeAndSetWorkArea();
1730 ewmh_HandleDynamicWorkArea();
1732 return;
1736 * Init Stuff
1738 static
1739 int set_all_atom_in_list(ewmh_atom *list)
1741 int l = 0;
1743 while(list->name != NULL)
1745 list->atom = XInternAtom(dpy,list->name,False);
1746 if (list->atom_type == None)
1748 list->atom_type = XA_UTF8_STRING;
1750 l++;
1751 list++;
1754 return l;
1757 static
1758 void set_net_supported(int l)
1760 Atom *supported;
1761 int i, k = 0;
1763 supported = (Atom *)safemalloc(l*sizeof(Atom));
1764 for(i=0; i < NUMBER_OF_ATOM_LISTS; i++)
1766 ewmh_atom *list = atom_list[i].list;
1767 while(list->name != NULL)
1769 supported[k++] = list->atom;
1770 list++;
1774 ewmh_ChangeProperty(
1775 Scr.Root, "_NET_SUPPORTED", EWMH_ATOM_LIST_FVWM_ROOT,
1776 (unsigned char *)supported, k);
1777 free(supported);
1779 return;
1782 static
1783 void clean_up(void)
1785 ewmh_ChangeProperty(
1786 Scr.Root,"_KDE_NET_SYSTEM_TRAY_WINDOWS",
1787 EWMH_ATOM_LIST_FVWM_ROOT, NULL, 0);
1789 return;
1792 void EWMH_Init(void)
1794 int i;
1795 int supported_count = 0;
1796 long val;
1797 XTextProperty text;
1798 unsigned char utf_name[4];
1799 char *names[1];
1800 XClassHint classhints;
1802 /* initialisation of all the atoms */
1803 XA_UTF8_STRING = XInternAtom(dpy,"UTF8_STRING",False);
1804 for(i=0; i < NUMBER_OF_ATOM_LISTS; i++)
1806 supported_count += set_all_atom_in_list(atom_list[i].list);
1809 /* the laws that we respect */
1810 set_net_supported(supported_count);
1812 /* use the Scr.NoFocusWin as the WM_CHECK window */
1813 val = Scr.NoFocusWin;
1814 ewmh_ChangeProperty(
1815 Scr.Root, "_NET_SUPPORTING_WM_CHECK",
1816 EWMH_ATOM_LIST_FVWM_ROOT, (unsigned char *)&val, 1);
1817 ewmh_ChangeProperty(
1818 Scr.NoFocusWin, "_NET_SUPPORTING_WM_CHECK",
1819 EWMH_ATOM_LIST_FVWM_ROOT, (unsigned char *)&val, 1);
1821 names[0] = "fvwm";
1822 classhints.res_name= "fvwm";
1823 classhints.res_class= "FVWM";
1825 XSetClassHint(dpy, Scr.NoFocusWin, &classhints);
1826 if (XStringListToTextProperty(names, 1, &text))
1828 XSetWMName(dpy, Scr.NoFocusWin, &text);
1829 XFree(text.value);
1832 /* FVWM in UTF8 */
1833 utf_name[0] = 0x46;
1834 utf_name[1] = 0x56;
1835 utf_name[2] = 0x57;
1836 utf_name[3] = 0x4D;
1838 ewmh_ChangeProperty(
1839 Scr.NoFocusWin, "_NET_WM_NAME", EWMH_ATOM_LIST_PROPERTY_NOTIFY,
1840 (unsigned char *)&utf_name, 4);
1842 clean_up();
1844 EWMH_SetDesktopNames();
1845 EWMH_SetCurrentDesktop();
1846 EWMH_SetNumberOfDesktops();
1847 EWMH_SetDesktopViewPort();
1848 EWMH_SetDesktopGeometry();
1849 EWMH_SetClientList();
1850 EWMH_SetClientListStacking();
1851 ewmh_ComputeAndSetWorkArea();
1853 return;
1857 * Exit Stuff
1859 void EWMH_ExitStuff(void)
1861 FvwmWindow *fw;
1863 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
1865 EWMH_RestoreInitialStates(fw, 0);
1868 return;
1871 #ifdef EWMH_DEBUG
1872 void EWMH_DLOG(char *msg, ...)
1874 va_list args;
1875 clock_t time_val, time_taken;
1876 static clock_t start_time = 0;
1877 static clock_t prev_time = 0;
1878 struct tms not_used_tms;
1879 char buffer[200]; /* oversized */
1880 time_t mytime;
1881 struct tm *t_ptr;
1883 time(&mytime);
1884 t_ptr = localtime(&mytime);
1885 if (start_time == 0)
1887 /* get clock ticks */
1888 prev_time = start_time = (unsigned int)times(&not_used_tms);
1890 /* get clock ticks */
1891 time_val = (unsigned int)times(&not_used_tms);
1892 time_taken = time_val - prev_time;
1893 prev_time = time_val;
1894 sprintf(
1895 buffer, "%.2d:%.2d:%.2d %6ld",
1896 t_ptr->tm_hour, t_ptr->tm_min, t_ptr->tm_sec, time_taken);
1898 fprintf(stderr, "EWMH DEBUG: ");
1899 va_start(args,msg);
1900 vfprintf(stderr, msg, args);
1901 va_end(args);
1902 fprintf(stderr, "\n");
1903 fprintf(stderr, " [time]: %s\n",buffer);
1905 return;
1907 #endif
1909 void EWMH_fullscreen(FvwmWindow *fw)
1911 fscreen_scr_arg fscr;
1912 rectangle scr_g;
1913 size_borders b;
1914 int page_x;
1915 int page_y;
1916 char cmd[128] = "\0";
1918 /* maximize with ResizeMoveMaximize */
1919 if (
1920 !is_function_allowed(
1921 F_MAXIMIZE, NULL, fw, RQORIG_PROGRAM_US, False) ||
1922 !is_function_allowed(
1923 F_MOVE, NULL, fw, RQORIG_PROGRAM_US, False) ||
1924 !is_function_allowed(
1925 F_RESIZE, NULL, fw, RQORIG_PROGRAM_US, True))
1927 return;
1929 if (IS_ICONIFIED(fw))
1931 execute_function_override_window(
1932 NULL, NULL, "Iconify off", 0, fw);
1934 if (IS_SHADED(fw))
1936 int sas = fw->shade_anim_steps;
1938 fw->shade_anim_steps = 0;
1939 execute_function_override_window(
1940 NULL, NULL, "WindowShade off", 0, fw);
1941 fw->shade_anim_steps = sas;
1943 SET_EWMH_FULLSCREEN(fw,True);
1944 apply_decor_change(fw);
1945 fscr.xypos.x = fw->g.frame.x + fw->g.frame.width / 2;
1946 fscr.xypos.y = fw->g.frame.y + fw->g.frame.height / 2;
1947 FScreenGetScrRect(
1948 &fscr, FSCREEN_XYPOS, &scr_g.x, &scr_g.y,
1949 &scr_g.width, &scr_g.height);
1950 get_window_borders(fw, &b);
1951 get_page_offset_check_visible(&page_x, &page_y, fw);
1952 sprintf(
1953 cmd, "ResizeMoveMaximize %dp %dp +%dp +%dp",
1954 scr_g.width, scr_g.height,
1955 scr_g.x - b.top_left.width + page_x,
1956 scr_g.y - b.top_left.height + page_y);
1957 if (DO_EWMH_USE_STACKING_HINTS(fw))
1959 int sl = fw->ewmh_normal_layer;
1961 new_layer(fw, Scr.TopLayer);
1962 if (sl == 0)
1964 fw->ewmh_normal_layer = Scr.DefaultLayer;
1966 else
1968 fw->ewmh_normal_layer = sl;
1971 if (cmd[0] != 0)
1973 SET_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw, 1);
1974 execute_function_override_window(NULL, NULL, cmd, 0, fw);
1975 SET_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw, 0);
1978 return;