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.
7 *
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.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, see: <http://www.gnu.org/licenses/>
15 */
16
17 /*
18 * An implementation of the Extended Window Manager Hints specification
19 * http://freedesktop.org/Standards/wm-spec/
20 *
21 * Not Implemented (draft 1.3 - 2004-05-01):
22 *
23 * _NET_DESKTOP_LAYOUT (not useful for us)
24 * _NET_VIRTUAL_ROOTS (not useful at all for us)
25 * _NET_SHOWING_DESKTOP should be implemented
26 * _NET_REQUEST_FRAME_EXTENTS may be implemented
27 *
28 * Some _NET_WINDOW_TYPE are simply ignored:
29 * _NET_WM_WINDOW_TYPE_SPLASH
30 * _NET_WM_WINDOW_TYPE_UTILITIES
31 * _KDE_NET_WM_WINDOW_TYPE_OVERRIDE (deprecated)
32 *
33 * _NET_WM_STATE_DEMANDS_ATTENTION state
34 *
35 * _NET_WM_STRUT_PARTIAL should be implemented
36 *
37 * _NET_WM_USER_TIME can be used to decide if we give the focus to a newly
38 * mapped window
39 *
40 * The kill huge process protocol: _NET_WM_PID and _NET_WM_PING
41 *
42 * _NET_WM_HANDLED_ICONS (what to do? Nothing?)
43 *
44 * "Source indication in requests" is not used but can be useful with some
45 * "ignore styles"
46 *
47 * Problems:
48 * - _NET_WM_WINDOW_TYPE_TOOLBAR is interpreted in a different way
49 * in GNOME (the spec) and in KDE 2/3.0 (~ simple dock?).
50 *
51 */
52
53 #include "config.h"
54
55 #include <stdio.h>
56 #include "libs/fvwm_x11.h"
57 #include "libs/fvwmlib.h"
58 #include "fvwm.h"
59 #include "execcontext.h"
60 #include "functions.h"
61 #include "commands.h"
62 #include "misc.h"
63 #include "screen.h"
64 #include "update.h"
65 #include "stack.h"
66 #include "style.h"
67 #include "externs.h"
68 #include "decorations.h"
69 #include "ewmh.h"
70 #include "ewmh_intern.h"
71 #include "geometry.h"
72 #include "window_flags.h"
73
74 typedef struct kst_item
75 {
76 Window w;
77 struct kst_item *next;
78 } KstItem;
79
80
81 Atom XA_UTF8_STRING = None;
82 KstItem *ewmh_KstWinList = NULL;
83
84 /*
85 * The ewmh atoms lists
86 */
87 #define ENTRY(name, type, func) {name, None, type, func}
88
89 /* WARNING: lists must be in "name" alphabetic order! */
90
91 /* EWMH_ATOM_LIST_CLIENT_ROOT
92 * net atoms that can be send (Client Message) by a client and do not
93 * need a window to operate */
94 ewmh_atom ewmh_atom_client_root[] =
95 {
96 ENTRY("_NET_CURRENT_DESKTOP", XA_CARDINAL, ewmh_CurrentDesktop),
97 ENTRY("_NET_DESKTOP_GEOMETRY", XA_CARDINAL, ewmh_DesktopGeometry),
98 ENTRY("_NET_DESKTOP_NAMES", None, None),
99 ENTRY("_NET_DESKTOP_VIEWPORT", XA_CARDINAL, ewmh_DesktopViewPort),
100 ENTRY("_NET_NUMBER_OF_DESKTOPS", XA_CARDINAL, ewmh_NumberOfDesktops),
101 {NULL,0,0,0}
102 };
103
104 /* EWMH_ATOM_LIST_CLIENT_WIN
105 * net atoms that can be send (Client Message) by a client and do need
106 * window to operate */
107 ewmh_atom ewmh_atom_client_win[] =
108 {
109 ENTRY("_NET_ACTIVE_WINDOW", XA_WINDOW, ewmh_ActiveWindow),
110 ENTRY("_NET_CLOSE_WINDOW", XA_WINDOW, ewmh_CloseWindow),
111 ENTRY("_NET_MOVERESIZE_WINDOW", XA_WINDOW, ewmh_MoveResizeWindow),
112 ENTRY("_NET_RESTACK_WINDOW", XA_WINDOW, ewmh_RestackWindow),
113 ENTRY("_NET_WM_DESKTOP", XA_CARDINAL, ewmh_WMDesktop),
114 ENTRY("_NET_WM_MOVERESIZE", XA_WINDOW, ewmh_MoveResize),
115 ENTRY("_NET_WM_STATE", XA_ATOM, ewmh_WMState),
116 {NULL,0,0,0}
117 };
118
119 /* EWMH_ATOM_LIST_WM_STATE
120 * the different wm state, a client can ask to add, remove or toggle
121 * via a _NET_WM_STATE Client message. fvwm must maintain these states
122 * too */
123 ewmh_atom ewmh_atom_wm_state[] =
124 {
125 ENTRY(
126 "_NET_WM_STATE_ABOVE", XA_ATOM,
127 ewmh_WMStateStaysOnTop),
128 ENTRY(
129 "_NET_WM_STATE_BELOW", XA_ATOM,
130 ewmh_WMStateStaysOnBottom),
131 ENTRY(
132 "_NET_WM_STATE_FULLSCREEN", XA_ATOM,
133 ewmh_WMStateFullScreen),
134 ENTRY("_NET_WM_STATE_HIDDEN", XA_ATOM, ewmh_WMStateHidden),
135 ENTRY(
136 "_NET_WM_STATE_MAXIMIZED_HORIZ", XA_ATOM,
137 ewmh_WMStateMaxHoriz),
138 ENTRY(
139 "_NET_WM_STATE_MAXIMIZED_HORZ", XA_ATOM,
140 ewmh_WMStateMaxHoriz),
141 ENTRY("_NET_WM_STATE_MAXIMIZED_VERT", XA_ATOM, ewmh_WMStateMaxVert),
142 ENTRY("_NET_WM_STATE_MODAL", XA_ATOM, ewmh_WMStateModal),
143 ENTRY("_NET_WM_STATE_SHADED", XA_ATOM, ewmh_WMStateShaded),
144 ENTRY(
145 "_NET_WM_STATE_SKIP_PAGER", XA_ATOM,
146 ewmh_WMStateSkipPager),
147 ENTRY(
148 "_NET_WM_STATE_SKIP_TASKBAR", XA_ATOM,
149 ewmh_WMStateSkipTaskBar),
150 ENTRY(
151 "_NET_WM_STATE_STAYS_ON_TOP", XA_ATOM,
152 ewmh_WMStateStaysOnTop),
153 ENTRY("_NET_WM_STATE_STICKY", XA_ATOM, ewmh_WMStateSticky),
154 {NULL,0,0,0}
155 };
156 #define EWMH_NUMBER_OF_STATE sizeof(ewmh_atom_wm_state)/sizeof(ewmh_atom) - 1
157
158 /* EWMH ATOM_LIST_ALLOWED_ACTIONS: atom for _NET_WM_ALLOWED_ACTIONS */
159 ewmh_atom ewmh_atom_allowed_actions[] =
160 {
161 ENTRY("_NET_WM_ACTION_CHANGE_DESKTOP", XA_ATOM, ewmh_AllowsYes),
162 ENTRY("_NET_WM_ACTION_CLOSE", XA_ATOM, ewmh_AllowsClose),
163 ENTRY("_NET_WM_ACTION_FULLSCREEN", XA_ATOM, ewmh_AllowsFullScreen),
164 ENTRY("_NET_WM_ACTION_MAXIMIZE_HORZ", XA_ATOM, ewmh_AllowsMaximize),
165 ENTRY("_NET_WM_ACTION_MAXIMIZE_VERT", XA_ATOM, ewmh_AllowsMaximize),
166 ENTRY("_NET_WM_ACTION_MINIMIZE", XA_ATOM, ewmh_AllowsMinimize),
167 ENTRY("_NET_WM_ACTION_MOVE", XA_ATOM, ewmh_AllowsMove),
168 ENTRY("_NET_WM_ACTION_RESIZE", XA_ATOM, ewmh_AllowsResize),
169 ENTRY("_NET_WM_ACTION_SHADE", XA_ATOM, ewmh_AllowsYes),
170 ENTRY("_NET_WM_ACTION_STICK", XA_ATOM, ewmh_AllowsYes),
171 {NULL,0,0,0}
172 };
173 #define EWMH_NUMBER_OF_ALLOWED_ACTIONS \
174 sizeof(ewmh_atom_allowed_actions)/sizeof(ewmh_atom) - 1
175
176 /* EWMH ATOM_LIST_WINDOW_TYPE: the various window type */
177 ewmh_atom ewmh_atom_window_type[] =
178 {
179 ENTRY("_NET_WM_WINDOW_TYPE_DESKTOP", XA_ATOM, ewmh_HandleDesktop),
180 ENTRY("_NET_WM_WINDOW_TYPE_DIALOG", XA_ATOM, ewmh_HandleDialog),
181 ENTRY("_NET_WM_WINDOW_TYPE_DOCK", XA_ATOM, ewmh_HandleDock),
182 ENTRY("_NET_WM_WINDOW_TYPE_MENU", XA_ATOM, ewmh_HandleMenu),
183 ENTRY("_NET_WM_WINDOW_TYPE_NORMAL", XA_ATOM, ewmh_HandleNormal),
184 ENTRY("_NET_WM_WINDOW_TYPE_TOOLBAR", XA_ATOM, ewmh_HandleToolBar),
185 ENTRY("_NET_WM_WINDOW_TYPE_NOTIFICATION", XA_ATOM, ewmh_HandleNotification),
186 {NULL,0,0,0}
187 };
188
189 /* EWMH ATOM_LIST_FIXED_PROPERTY
190 * property that have a window at startup and which should not change */
191 ewmh_atom ewmh_atom_fixed_property[] =
192 {
193 ENTRY("_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", XA_WINDOW, None),
194 ENTRY("_NET_WM_HANDLED_ICON", XA_ATOM, None),
195 ENTRY("_NET_WM_PID", XA_ATOM, None),
196 ENTRY("_NET_WM_WINDOW_TYPE", XA_ATOM, None),
197 {NULL,0,0,0}
198 };
199
200 /* EWMH ATOM_LIST_PROPERTY_NOTIFY
201 * properties of a window which is updated by the window via a PropertyNotify
202 * event */
203 ewmh_atom ewmh_atom_property_notify[] =
204 {
205 ENTRY("_NET_WM_ICON", XA_CARDINAL, ewmh_WMIcon),
206 ENTRY("_NET_WM_ICON_GEOMETRY", XA_CARDINAL, ewmh_WMIconGeometry),
207 ENTRY("_NET_WM_ICON_NAME", None, EWMH_WMIconName),
208 ENTRY("_NET_WM_NAME", None, EWMH_WMName),
209 ENTRY("_NET_WM_STRUT", XA_CARDINAL, ewmh_WMStrut),
210 {NULL,0,0,0}
211 };
212
213 /* EWMH_ATOM_LIST_FVWM_ROOT: root atom that should be maintained by fvwm only
214 */
215 ewmh_atom ewmh_atom_fvwm_root[] =
216 {
217 ENTRY("_KDE_NET_SYSTEM_TRAY_WINDOWS", XA_WINDOW, None),
218 ENTRY("_NET_CLIENT_LIST", XA_WINDOW, None),
219 ENTRY("_NET_CLIENT_LIST_STACKING", XA_WINDOW, None),
220 ENTRY("_NET_SUPPORTED", XA_ATOM, None),
221 ENTRY("_NET_SUPPORTING_WM_CHECK", XA_WINDOW, None),
222 ENTRY("_NET_VIRTUAL_ROOTS", XA_WINDOW, None),
223 ENTRY("_NET_WORKAREA", XA_CARDINAL, None),
224 {NULL,0,0,0}
225 };
226
227 /* EWMH_ATOM_LIST_FVWM_WIN: window atom that should be maintained by fvwm
228 * only */
229 ewmh_atom ewmh_atom_fvwm_win[] =
230 {
231 ENTRY("_KDE_NET_WM_FRAME_STRUT", XA_CARDINAL, None),
232 ENTRY("_NET_FRAME_EXTENTS", XA_CARDINAL, None),
233 ENTRY("_NET_WM_ALLOWED_ACTIONS", XA_ATOM, None),
234 ENTRY("_NET_WM_ICON_VISIBLE_NAME", None, None),
235 ENTRY("_NET_WM_VISIBLE_NAME", None, None),
236 {NULL,0,0,0}
237 };
238
239
240 #define NUMBER_OF_ATOM_LISTS 9
241 #define L_ENTRY(x,y) {x,y,sizeof(y)/sizeof(ewmh_atom)}
242 ewmh_atom_list atom_list[] =
243 {
244 L_ENTRY(EWMH_ATOM_LIST_CLIENT_ROOT, ewmh_atom_client_root),
245 L_ENTRY(EWMH_ATOM_LIST_CLIENT_WIN, ewmh_atom_client_win),
246 L_ENTRY(EWMH_ATOM_LIST_WM_STATE, ewmh_atom_wm_state),
247 L_ENTRY(EWMH_ATOM_LIST_ALLOWED_ACTIONS, ewmh_atom_allowed_actions),
248 L_ENTRY(EWMH_ATOM_LIST_WINDOW_TYPE, ewmh_atom_window_type),
249 L_ENTRY(EWMH_ATOM_LIST_FIXED_PROPERTY, ewmh_atom_fixed_property),
250 L_ENTRY(EWMH_ATOM_LIST_PROPERTY_NOTIFY, ewmh_atom_property_notify),
251 L_ENTRY(EWMH_ATOM_LIST_FVWM_ROOT, ewmh_atom_fvwm_root),
252 L_ENTRY(EWMH_ATOM_LIST_FVWM_WIN, ewmh_atom_fvwm_win),
253 L_ENTRY(EWMH_ATOM_LIST_END, NULL)
254 };
255
256 /*
257 * Atoms utilities
258 */
259
260 static
compare(const void * a,const void * b)261 int compare(const void *a, const void *b)
262 {
263 return (strcmp((char *)a, ((ewmh_atom *)b)->name));
264 }
265
266 static
get_ewmh_atom_by_name(const char * atom_name,ewmh_atom_list_name list_name)267 ewmh_atom *get_ewmh_atom_by_name(
268 const char *atom_name, ewmh_atom_list_name list_name)
269 {
270 ewmh_atom *a = NULL;
271 Bool done = 0;
272 int i = 0;
273
274 while(!done && atom_list[i].name != EWMH_ATOM_LIST_END)
275 {
276 if (atom_list[i].name == list_name ||
277 list_name == EWMH_ATOM_LIST_ALL)
278 {
279 a = (ewmh_atom *)bsearch(
280 atom_name, atom_list[i].list,
281 atom_list[i].size - 1, sizeof(ewmh_atom),
282 compare);
283 if (a != NULL || list_name != EWMH_ATOM_LIST_ALL)
284 {
285 done = 1;
286 }
287 }
288 i++;
289 }
290
291 return a;
292 }
293
ewmh_GetEwmhAtomByAtom(Atom atom,ewmh_atom_list_name list_name)294 ewmh_atom *ewmh_GetEwmhAtomByAtom(Atom atom, ewmh_atom_list_name list_name)
295 {
296 int i = 0;
297
298 for (i = 0; atom_list[i].name != EWMH_ATOM_LIST_END; i++)
299 {
300 ewmh_atom *item;
301
302 if (list_name != atom_list[i].name &&
303 list_name != EWMH_ATOM_LIST_ALL)
304 {
305 continue;
306 }
307 for (item = atom_list[i].list; item->name != NULL; item++)
308 {
309 if (atom == item->atom)
310 {
311 return item;
312 }
313 }
314 if (list_name == atom_list[i].name)
315 {
316 return NULL;
317 }
318 }
319
320 return NULL;
321 }
322
atom_size(int format)323 static int atom_size(int format)
324 {
325 if (format == 32)
326 {
327 return sizeof(long);
328 }
329 else
330 {
331 return (format >> 3);
332 }
333 }
334
ewmh_ChangeProperty(Window w,const char * atom_name,ewmh_atom_list_name list,unsigned char * data,int length)335 void ewmh_ChangeProperty(
336 Window w, const char *atom_name, ewmh_atom_list_name list,
337 unsigned char *data, int length)
338 {
339 ewmh_atom *a;
340 int format = 32;
341
342 if ((a = get_ewmh_atom_by_name(atom_name, list)) != NULL)
343 {
344 int asize;
345 int free_data = 0;
346
347 if (a->atom_type == XA_UTF8_STRING)
348 {
349 format = 8;
350 }
351
352 asize = atom_size(format);
353 if (
354 format == 32 && asize * 8 != format &&
355 strcmp(atom_name, "_NET_WM_ICON") == 0)
356 {
357 long *datacopy = fxmalloc(asize * length);
358 int i;
359
360 for (i = 0; i < length; i++)
361 {
362 datacopy[i] = ((CARD32 *)data)[i];
363 }
364 data = (unsigned char*)datacopy;
365 free_data = 1;
366 }
367 XChangeProperty(
368 dpy, w, a->atom, a->atom_type , format,
369 PropModeReplace, data, length);
370
371 if (free_data)
372 {
373 free(data);
374 }
375 }
376
377 return;
378 }
379
ewmh_DeleteProperty(Window w,const char * atom_name,ewmh_atom_list_name list)380 void ewmh_DeleteProperty(
381 Window w, const char *atom_name, ewmh_atom_list_name list)
382 {
383 ewmh_atom *a;
384
385 if ((a = get_ewmh_atom_by_name(atom_name, list)) != NULL)
386 {
387 XDeleteProperty(dpy, w, a->atom);
388 }
389
390 return;
391 }
392
393 static
atom_get(Window win,Atom to_get,Atom type,int * size)394 void *atom_get(Window win, Atom to_get, Atom type, int *size)
395 {
396 unsigned char *retval;
397 Atom type_ret;
398 unsigned long bytes_after, num_ret;
399 long length;
400 int format_ret;
401 void *data;
402 int ok;
403
404 retval = NULL;
405 length = 0x7fffffff;
406 ok = XGetWindowProperty(
407 dpy, win, to_get, 0L, length, False, type, &type_ret,
408 &format_ret, &num_ret, &bytes_after, &retval);
409
410 if ((ok == Success) && (retval) && (num_ret > 0) && (format_ret > 0))
411 {
412 int asize;
413
414 asize = atom_size(format_ret);
415 data = fxmalloc(num_ret * asize);
416 if (format_ret == 32 && asize * 8 != format_ret)
417 {
418 int i;
419
420 for (i = 0; i < num_ret; i++)
421 {
422 ((CARD32 *)data)[i] = ((long *)retval)[i];
423 }
424 }
425 else
426 {
427 if (data)
428 {
429 memcpy(data, retval, num_ret * asize);
430 }
431 }
432 XFree(retval);
433 *size = num_ret * (format_ret >> 3);
434
435 return data;
436 }
437 if (retval)
438 {
439 XFree(retval);
440 }
441
442 return NULL;
443 }
444
ewmh_AtomGetByName(Window win,const char * atom_name,ewmh_atom_list_name list,int * size)445 void *ewmh_AtomGetByName(
446 Window win, const char *atom_name, ewmh_atom_list_name list,
447 int *size)
448 {
449 ewmh_atom *a;
450 void *data = NULL;
451
452 if ((a = get_ewmh_atom_by_name(atom_name, list)) != NULL)
453 {
454 data = atom_get(win, a->atom, a->atom_type, size);
455 }
456
457 return data;
458 }
459
460 /*
461 * client_root: here the client is fvwm
462 */
463 static
check_desk(void)464 int check_desk(void)
465 {
466 int d = -1;
467 FvwmWindow *fw;
468
469 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
470 {
471 if (!IS_STICKY_ACROSS_DESKS(fw))
472 {
473 d = max(d, fw->Desk);
474 }
475 }
476
477 return d;
478 }
479
EWMH_SetCurrentDesktop(struct monitor * m)480 void EWMH_SetCurrentDesktop(struct monitor *m)
481 {
482 long val;
483
484 /* FIXME: this should broadcast to all monitors. */
485
486 val = m->virtual_scr.CurrentDesk;
487
488 if (val < 0 || (val >= m->ewmhc.MaxDesktops && m->ewmhc.MaxDesktops != 0))
489 {
490 return;
491 }
492
493 if (val >= m->ewmhc.CurrentNumberOfDesktops ||
494 (m->ewmhc.NumberOfDesktops != m->ewmhc.CurrentNumberOfDesktops &&
495 val < m->ewmhc.CurrentNumberOfDesktops))
496 {
497 EWMH_SetNumberOfDesktops(m);
498 }
499
500 ewmh_ChangeProperty(Scr.Root,"_NET_CURRENT_DESKTOP",
501 EWMH_ATOM_LIST_CLIENT_ROOT,
502 (unsigned char *)&val, 1);
503
504 return;
505 }
506
EWMH_SetNumberOfDesktops(struct monitor * m)507 void EWMH_SetNumberOfDesktops(struct monitor *m)
508 {
509 long val;
510
511 if (m->ewmhc.CurrentNumberOfDesktops < m->ewmhc.NumberOfDesktops)
512 {
513 m->ewmhc.CurrentNumberOfDesktops = m->ewmhc.NumberOfDesktops;
514 }
515
516 if (m->ewmhc.CurrentNumberOfDesktops > m->ewmhc.NumberOfDesktops ||
517 m->ewmhc.NeedsToCheckDesk)
518 {
519 int d = check_desk();
520
521 m->ewmhc.NeedsToCheckDesk = False;
522 if (d >= m->ewmhc.MaxDesktops && m->ewmhc.MaxDesktops != 0)
523 d = 0;
524 m->ewmhc.CurrentNumberOfDesktops =
525 max(m->ewmhc.NumberOfDesktops, d+1);
526 }
527
528 if (m->virtual_scr.CurrentDesk >= m->ewmhc.CurrentNumberOfDesktops &&
529 (m->virtual_scr.CurrentDesk < m->ewmhc.MaxDesktops ||
530 m->ewmhc.MaxDesktops == 0))
531 {
532 m->ewmhc.CurrentNumberOfDesktops = m->virtual_scr.CurrentDesk + 1;
533 }
534
535 val = (long)m->ewmhc.CurrentNumberOfDesktops;
536 ewmh_ChangeProperty(Scr.Root, "_NET_NUMBER_OF_DESKTOPS",
537 EWMH_ATOM_LIST_CLIENT_ROOT,
538 (unsigned char *)&val, 1);
539 ewmh_SetWorkArea(m);
540
541 return;
542 }
543
EWMH_SetDesktopViewPort(struct monitor * m)544 void EWMH_SetDesktopViewPort(struct monitor *m)
545 {
546 long val[256][2]; /* no more than 256 desktops */
547 int i = 0;
548
549 while(i < m->ewmhc.NumberOfDesktops && i < 256)
550 {
551 val[i][0] = m->virtual_scr.Vx;
552 val[i][1] = m->virtual_scr.Vy;
553 i++;
554 }
555 ewmh_ChangeProperty(
556 Scr.Root, "_NET_DESKTOP_VIEWPORT", EWMH_ATOM_LIST_CLIENT_ROOT,
557 (unsigned char *)&val, i*2);
558
559 return;
560 }
561
EWMH_SetDesktopGeometry(struct monitor * m)562 void EWMH_SetDesktopGeometry(struct monitor *m)
563 {
564 long val[2];
565
566 /* FIXME: needs broadcast for global. */
567
568 val[0] = m->virtual_scr.VxMax + m->si->w; //m->virtual_scr.MyDisplayWidth;
569 val[1] = m->virtual_scr.VyMax + m->si->h; //m->virtual_scr.MyDisplayHeight;
570 ewmh_ChangeProperty(
571 Scr.Root,"_NET_DESKTOP_GEOMETRY", EWMH_ATOM_LIST_CLIENT_ROOT,
572 (unsigned char *)&val, 2);
573
574 return;
575 }
576
577 /*
578 * client_win: here the client is fvwm
579 */
EWMH_SetActiveWindow(Window w)580 void EWMH_SetActiveWindow(Window w)
581 {
582 ewmh_ChangeProperty(
583 Scr.Root, "_NET_ACTIVE_WINDOW", EWMH_ATOM_LIST_CLIENT_WIN,
584 (unsigned char *)&w, 1);
585
586 return;
587 }
588
EWMH_SetWMDesktop(FvwmWindow * fw)589 void EWMH_SetWMDesktop(FvwmWindow *fw)
590 {
591 struct monitor *m = (fw && fw->m) ? fw->m : monitor_get_current();
592 long desk = fw->Desk;
593
594 if (IS_STICKY_ACROSS_DESKS(fw))
595 {
596 desk = (unsigned long)-1;
597 }
598 else if (desk >= m->ewmhc.CurrentNumberOfDesktops)
599 {
600 m->ewmhc.NeedsToCheckDesk = True;
601 EWMH_SetNumberOfDesktops(m);
602 }
603 ewmh_ChangeProperty(
604 FW_W(fw), "_NET_WM_DESKTOP", EWMH_ATOM_LIST_CLIENT_WIN,
605 (unsigned char *)&desk, 1);
606
607 return;
608 }
609
610 /*
611 * fvwm must maintain the _NET_WM_STATE
612 */
613
EWMH_SetWMState(FvwmWindow * fw,Bool do_restore)614 void EWMH_SetWMState(FvwmWindow *fw, Bool do_restore)
615 {
616 Atom wm_state[EWMH_NUMBER_OF_STATE];
617 int i = 0;
618 ewmh_atom *list = ewmh_atom_wm_state;
619
620 while(list->name != NULL)
621 {
622 if (list->action(fw, NULL, NULL, do_restore))
623 {
624 wm_state[i++] = list->atom;
625 }
626 list++;
627 }
628
629 if (i > 0)
630 {
631 ewmh_ChangeProperty(
632 FW_W(fw), "_NET_WM_STATE", EWMH_ATOM_LIST_CLIENT_WIN,
633 (unsigned char *)wm_state, i);
634 }
635 else
636 {
637 ewmh_DeleteProperty(
638 FW_W(fw), "_NET_WM_STATE",
639 EWMH_ATOM_LIST_CLIENT_WIN);
640 }
641
642 return;
643 }
644
645 /*
646 * fvwm_root
647 */
648
649 /*** kde system tray ***/
650 /* #define DEBUG_KST */
651 static
add_kst_item(Window w)652 void add_kst_item(Window w)
653 {
654 KstItem *t,**prev;
655
656 t = ewmh_KstWinList;
657 prev = &ewmh_KstWinList;
658
659 while(t != NULL)
660 {
661 prev = &(t->next);
662 t = t->next;
663 }
664 *prev = fxmalloc(sizeof(KstItem));
665 (*prev)->w = w;
666 (*prev)->next = NULL;
667
668 return;
669 }
670
671 static
delete_kst_item(Window w)672 void delete_kst_item(Window w)
673 {
674 KstItem *t,**prev;
675
676 t = ewmh_KstWinList;
677 prev = &ewmh_KstWinList;
678 while((t!= NULL)&&(t->w != w))
679 {
680 prev = &(t->next);
681 t = t->next;
682 }
683 if (t == NULL)
684 {
685 return;
686 }
687 if(prev != NULL)
688 {
689 *prev = t->next;
690 }
691 free(t);
692
693 return;
694 }
695
696 static
set_kde_sys_tray(void)697 void set_kde_sys_tray(void)
698 {
699 Window *wins = NULL;
700 KstItem *t;
701 int i = 0, nbr = 0;
702
703 t = ewmh_KstWinList;
704 while(t != NULL)
705 {
706 nbr++;
707 t = t->next;
708 }
709
710 if (nbr > 0)
711 {
712 wins = fxmalloc(sizeof(Window) * nbr);
713 }
714
715 t = ewmh_KstWinList;
716 #ifdef DEBUG_KST
717 fvwm_debug(__func__, "ADD_TO_KST: ");
718 #endif
719 while (t != NULL)
720 {
721 #ifdef DEBUG_KST
722 fvwm_debug(__func__, "0x%lx ",t->w);
723 #endif
724 wins[i++] = t->w;
725 t = t->next;
726 }
727 #ifdef DEBUG_KST
728 fvwm_debug(__func__, "\n");
729 #endif
730
731 ewmh_ChangeProperty(Scr.Root,"_KDE_NET_SYSTEM_TRAY_WINDOWS",
732 EWMH_ATOM_LIST_FVWM_ROOT,
733 (unsigned char *)wins,i);
734 if (wins != NULL)
735 {
736 free(wins);
737 }
738
739 return;
740 }
741
ewmh_AddToKdeSysTray(FvwmWindow * fw)742 void ewmh_AddToKdeSysTray(FvwmWindow *fw)
743 {
744 int size = 0;
745 CARD32 *val;
746 KstItem *t;
747
748 val = ewmh_AtomGetByName(
749 FW_W(fw), "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
750 EWMH_ATOM_LIST_FIXED_PROPERTY, &size);
751
752 if (val == NULL)
753 {
754 return;
755 }
756 free(val);
757
758 t = ewmh_KstWinList;
759 while(t != NULL && t->w != FW_W(fw))
760 t = t->next;
761
762 if (t != NULL)
763 {
764 return; /* already in the list */
765 }
766
767 add_kst_item(FW_W(fw));
768 set_kde_sys_tray();
769
770 return;
771 }
772
773 #if 0
774 /* not used at present time */
775 void ewmh_FreeKdeSysTray(void)
776 {
777 KstItem *t;
778
779 t = ewmh_KstWinList;
780 while(t != NULL)
781 {
782 XSelectInput(dpy, t->w, NoEventMask);
783 delete_kst_item(t->w);
784 t = ewmh_KstWinList;
785 }
786 set_kde_sys_tray();
787
788 return;
789 }
790 #endif
791
EWMH_IsKdeSysTrayWindow(Window w)792 int EWMH_IsKdeSysTrayWindow(Window w)
793 {
794 KstItem *t;
795
796 t = ewmh_KstWinList;
797 while(t != NULL && t->w != w)
798 {
799 t = t->next;
800 }
801 if (t == NULL)
802 {
803 return 0;
804 }
805 #ifdef DEBUG_KST
806 fvwm_debug(__func__, "IsKdeSysTrayWindow: 0x%lx\n", w);
807 #endif
808
809 return 1;
810 }
811
EWMH_ManageKdeSysTray(Window w,int type)812 void EWMH_ManageKdeSysTray(Window w, int type)
813 {
814 KstItem *t;
815
816 t = ewmh_KstWinList;
817 while(t != NULL && t->w != w)
818 {
819 t = t->next;
820 }
821 if (t == NULL)
822 {
823 return;
824 }
825 switch(type)
826 {
827 case UnmapNotify:
828 #ifdef DEBUG_KST
829 fvwm_debug(__func__, "KST_UNMAP: 0x%lx\n", w);
830 #endif
831 XSelectInput(dpy, w, StructureNotifyMask);
832 XFlush(dpy);
833 break;
834 case DestroyNotify:
835 #ifdef DEBUG_KST
836 fvwm_debug(__func__, "KST_DESTROY: 0x%lx\n", w);
837 #endif
838 XSelectInput(dpy, t->w, NoEventMask);
839 XFlush(dpy);
840 delete_kst_item(w);
841 set_kde_sys_tray();
842 break;
843 case ReparentNotify:
844 #ifdef DEBUG_KST
845 fvwm_debug(__func__, "KST_Reparent: 0x%lx\n", w);
846 #endif
847 XSelectInput(dpy, w, StructureNotifyMask);
848 XFlush(dpy);
849 break;
850 default:
851 #ifdef DEBUG_KST
852 fvwm_debug(__func__, "KST_NO: 0x%lx\n", w);
853 #endif
854 break;
855 }
856
857 return;
858 }
859
860 /**** Client lists ****/
861
EWMH_SetClientList(struct monitor * m)862 void EWMH_SetClientList(struct monitor *m)
863 {
864 Window *wl = NULL;
865 FvwmWindow *fw;
866 int nbr = 0;
867 int i = 0;
868
869 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
870 {
871 nbr++;
872 }
873 if (nbr != 0)
874 {
875 wl = fxmalloc(sizeof(Window) * nbr);
876 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
877 {
878 wl[i++] = FW_W(fw);
879 }
880 }
881 ewmh_ChangeProperty(
882 Scr.Root,"_NET_CLIENT_LIST", EWMH_ATOM_LIST_FVWM_ROOT,
883 (unsigned char *)wl, nbr);
884 if (wl != NULL)
885 {
886 free (wl);
887 }
888
889 return;
890 }
891
EWMH_SetClientListStacking(struct monitor * m)892 void EWMH_SetClientListStacking(struct monitor *m)
893 {
894 Window *wl = NULL;
895 FvwmWindow *fw;
896 int nbr = 0;
897 int i = 0;
898
899 for (
900 fw = Scr.FvwmRoot.stack_next; fw != &Scr.FvwmRoot;
901 fw = fw->stack_next)
902 {
903 nbr++;
904 }
905 i = nbr-1;
906 if (nbr != 0)
907 {
908 wl = fxmalloc(sizeof(Window) * nbr);
909 for (
910 fw = Scr.FvwmRoot.stack_next; fw != &Scr.FvwmRoot;
911 fw = fw->stack_next)
912 {
913 wl[i--] = FW_W(fw);
914 }
915 }
916 ewmh_ChangeProperty(
917 Scr.Root,"_NET_CLIENT_LIST_STACKING", EWMH_ATOM_LIST_FVWM_ROOT,
918 (unsigned char *)wl, nbr);
919 if (wl != NULL)
920 {
921 free (wl);
922 }
923
924 return;
925 }
926
927 /**** Working Area stuff ****/
928 /**** At present time we support only sticky windows with strut ****/
929
ewmh_SetWorkArea(struct monitor * m)930 void ewmh_SetWorkArea(struct monitor *m)
931 {
932 long val[256][4]; /* no more than 256 desktops */
933 int i = 0;
934
935 if (m->Desktops == NULL)
936 return;
937
938 while(i < m->ewmhc.NumberOfDesktops && i < 256)
939 {
940 val[i][0] = m->Desktops->ewmh_working_area.x;
941 val[i][1] = m->Desktops->ewmh_working_area.y;
942 val[i][2] = m->Desktops->ewmh_working_area.width;
943 val[i][3] = m->Desktops->ewmh_working_area.height;
944 i++;
945 }
946 ewmh_ChangeProperty(
947 Scr.Root, "_NET_WORKAREA", EWMH_ATOM_LIST_FVWM_ROOT,
948 (unsigned char *)&val, i*4);
949
950 return;
951 }
952
ewmh_ComputeAndSetWorkArea(struct monitor * m)953 void ewmh_ComputeAndSetWorkArea(struct monitor *m)
954 {
955 int left = m->ewmhc.BaseStrut.left;
956 int right = m->ewmhc.BaseStrut.right;
957 int top = m->ewmhc.BaseStrut.top;
958 int bottom = m->ewmhc.BaseStrut.bottom;
959 int x,y,width,height;
960 FvwmWindow *fw;
961
962 /* FIXME: needs broadcast if global monitor in use. */
963
964 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
965 {
966 if (fw->m != m)
967 continue;
968 if (
969 DO_EWMH_IGNORE_STRUT_HINTS(fw) ||
970 !IS_STICKY_ACROSS_PAGES(fw))
971 {
972 continue;
973 }
974 left = max(left, fw->strut.left);
975 right = max(right, fw->strut.right);
976 top = max(top, fw->strut.top);
977 bottom = max(bottom, fw->strut.bottom);
978 }
979
980 x = left;
981 y = top;
982
983 width = m->si->w - (left + right);
984 height = m->si->h - (top + bottom);
985
986 fvwm_debug(__func__, "monitor '%s': {l: %d, r: %d, t: %d, b: %d} "
987 "{x: %d, y: %d, w: %d, h: %d}\n", m->si->name,
988 left, right, top, bottom, x, y, width, height);
989
990 if (
991 m->Desktops->ewmh_working_area.x != x ||
992 m->Desktops->ewmh_working_area.y != y ||
993 m->Desktops->ewmh_working_area.width != width ||
994 m->Desktops->ewmh_working_area.height != height)
995 {
996 m->Desktops->ewmh_working_area.x = x;
997 m->Desktops->ewmh_working_area.y = y;
998 m->Desktops->ewmh_working_area.width = width;
999 m->Desktops->ewmh_working_area.height = height;
1000
1001 fvwm_debug(__func__, "differ, so setting work area\n");
1002
1003 ewmh_SetWorkArea(m);
1004 }
1005
1006 return;
1007 }
1008
ewmh_HandleDynamicWorkArea(struct monitor * m)1009 void ewmh_HandleDynamicWorkArea(struct monitor *m)
1010 {
1011 int dyn_left = m->ewmhc.BaseStrut.left;
1012 int dyn_right = m->ewmhc.BaseStrut.right;
1013 int dyn_top = m->ewmhc.BaseStrut.top;
1014 int dyn_bottom = m->ewmhc.BaseStrut.bottom;
1015 int x,y,width,height;
1016 FvwmWindow *fw;
1017
1018 /* FIXME: needs broadcast if global monitor in use. */
1019
1020 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
1021 {
1022 if (fw->m != m)
1023 continue;
1024 if (
1025 DO_EWMH_IGNORE_STRUT_HINTS(fw) ||
1026 !IS_STICKY_ACROSS_PAGES(fw))
1027 {
1028 continue;
1029 }
1030 dyn_left = max(dyn_left, fw->dyn_strut.left);
1031 dyn_right = max(dyn_right, fw->dyn_strut.right);
1032 dyn_top = max(dyn_top, fw->dyn_strut.top);
1033 dyn_bottom = max(dyn_bottom, fw->dyn_strut.bottom);
1034 }
1035
1036 x = dyn_left;
1037 y = dyn_top;
1038
1039 width = m->si->w - (dyn_left + dyn_right);
1040 height = m->si->h - (dyn_top + dyn_bottom);
1041
1042 if (
1043 m->Desktops->ewmh_dyn_working_area.x != x ||
1044 m->Desktops->ewmh_dyn_working_area.y != y ||
1045 m->Desktops->ewmh_dyn_working_area.width != width ||
1046 m->Desktops->ewmh_dyn_working_area.height != height)
1047 {
1048 m->Desktops->ewmh_dyn_working_area.x = x;
1049 m->Desktops->ewmh_dyn_working_area.y = y;
1050 m->Desktops->ewmh_dyn_working_area.width = width;
1051 m->Desktops->ewmh_dyn_working_area.height = height;
1052 /* here we may update the maximized window ...etc */
1053 }
1054
1055 return;
1056 }
1057
EWMH_UpdateWorkArea(struct monitor * m)1058 void EWMH_UpdateWorkArea(struct monitor *m)
1059 {
1060 ewmh_ComputeAndSetWorkArea(m);
1061 ewmh_HandleDynamicWorkArea(m);
1062 }
1063
EWMH_GetWorkAreaIntersection(FvwmWindow * fw,int * x,int * y,int * w,int * h,int type)1064 void EWMH_GetWorkAreaIntersection(
1065 FvwmWindow *fw, int *x, int *y, int *w, int *h, int type)
1066 {
1067 struct monitor *m = (fw && fw->m) ? fw->m : monitor_get_current();
1068
1069 EWMH_UpdateWorkArea(m);
1070
1071 int nx,ny,nw,nh;
1072 int area_x = m->Desktops->ewmh_working_area.x;
1073 int area_y = m->Desktops->ewmh_working_area.y;
1074 int area_w = m->Desktops->ewmh_working_area.width;
1075 int area_h = m->Desktops->ewmh_working_area.height;
1076 Bool is_dynamic = False;
1077
1078 fvwm_debug(__func__, "mon: %s {ax: %d, ay: %d, aw: %d, ah: %d\n",
1079 m->si->name, area_x, area_y, area_w, area_h);
1080 fvwm_debug(__func__, "mon: %s {x: %d, y: %d, w: %d, h: %d\n",
1081 m->si->name, *x, *y, *w, *h);
1082
1083 /* FIXME: needs broadcast if global monitor in use. */
1084
1085 switch(type)
1086 {
1087 case EWMH_IGNORE_WORKING_AREA:
1088 return;
1089 case EWMH_USE_WORKING_AREA:
1090 break;
1091 case EWMH_USE_DYNAMIC_WORKING_AREA:
1092 is_dynamic = True;
1093 break;
1094 default:
1095 break;
1096 }
1097 if (is_dynamic)
1098 {
1099 area_x = m->Desktops->ewmh_dyn_working_area.x;
1100 area_y = m->Desktops->ewmh_dyn_working_area.y;
1101 area_w = m->Desktops->ewmh_dyn_working_area.width;
1102 area_h = m->Desktops->ewmh_dyn_working_area.height;
1103 }
1104 nx = max(*x, area_x + m->si->x);
1105 ny = max(*y, area_y + m->si->y);
1106 nw = min(*x + *w, area_x + area_w) - nx + m->si->x;
1107 nh = min(*y + *h, area_y + area_h) - ny + m->si->y;
1108
1109 *x = nx;
1110 *y = ny;
1111 *w = nw;
1112 *h = nh;
1113
1114 fvwm_debug(__func__, "mon: %s finalising: {x: %d, y: %d, w: %d, h: %d}\n",
1115 m->si->name, *x, *y, *w, *h);
1116
1117 return;
1118 }
1119
1120 static
get_intersection(int x11,int y11,int x12,int y12,int x21,int y21,int x22,int y22,Bool use_percent)1121 float get_intersection(
1122 int x11, int y11, int x12, int y12, int x21, int y21, int x22, int y22,
1123 Bool use_percent)
1124 {
1125 float ret = 0;
1126 int xl, xr, yt, yb;
1127
1128 if (x11 < x22 && x12 > x21 && y11 < y22 && y12 > y21)
1129 {
1130 xl = max(x11, x21);
1131 xr = min(x12, x22);
1132 yt = max(y11, y21);
1133 yb = min(y12, y22);
1134 ret = (xr - xl) * (yb - yt);
1135 }
1136 if (use_percent &&
1137 (x22 - x21) * (y22 - y21) != 0 && (x12 - x11) * (y12 - y11) != 0)
1138 {
1139 ret = 100 * max(ret / ((x22 - x21) * (y22 - y21)),
1140 ret / ((x12 - x11) * (y12 - y11)));
1141 }
1142
1143 return ret;
1144 }
1145
1146 static
ewmh_GetStrutIntersection(struct monitor * m,int x11,int y11,int x12,int y12,int left,int right,int top,int bottom,Bool use_percent)1147 float ewmh_GetStrutIntersection(struct monitor *m,
1148 int x11, int y11, int x12, int y12,
1149 int left, int right, int top, int bottom,
1150 Bool use_percent)
1151 {
1152 float ret = 0;
1153 int x21, y21, x22, y22;
1154
1155 /* FIXME: possibly need to consider using m->si->x/y/w/h */
1156
1157 /* left */
1158 x21 = 0;
1159 y21 = 0;
1160 x22 = left;
1161 y22 = monitor_get_all_heights();
1162 ret += get_intersection(
1163 x11, y11, x12, y12, x21, y21, x22, y22, use_percent);
1164 /* right */
1165 x21 = monitor_get_all_widths() - right;
1166 y21 = 0;
1167 x22 = monitor_get_all_widths();
1168 y22 = monitor_get_all_heights();
1169 ret += get_intersection(
1170 x11, y11, x12, y12, x21, y21, x22, y22, use_percent);
1171 /* top */
1172 x21 = 0;
1173 y21 = 0;
1174 x22 = monitor_get_all_widths();
1175 y22 = top;
1176 ret += get_intersection(
1177 x11, y11, x12, y12, x21, y21, x22, y22, use_percent);
1178 /* bottom */
1179 x21 = 0;
1180 y21 = monitor_get_all_heights() - bottom;
1181 x22 = monitor_get_all_widths();
1182 y22 = monitor_get_all_heights();
1183 ret += get_intersection(
1184 x11, y11, x12, y12, x21, y21, x22, y22, use_percent);
1185
1186 return ret;
1187 }
1188
EWMH_GetBaseStrutIntersection(struct monitor * m,int x11,int y11,int x12,int y12,Bool use_percent)1189 float EWMH_GetBaseStrutIntersection(struct monitor *m,
1190 int x11, int y11, int x12, int y12, Bool use_percent)
1191 {
1192 return ewmh_GetStrutIntersection(m,
1193 x11, y11, x12, y12, m->ewmhc.BaseStrut.left,
1194 m->ewmhc.BaseStrut.right, m->ewmhc.BaseStrut.top,
1195 m->ewmhc.BaseStrut.bottom, use_percent);
1196 }
1197
EWMH_GetStrutIntersection(struct monitor * m,int x11,int y11,int x12,int y12,Bool use_percent)1198 float EWMH_GetStrutIntersection(struct monitor *m,
1199 int x11, int y11, int x12, int y12, Bool use_percent)
1200 {
1201 int left, right, top, bottom;
1202
1203 /* FIXME: needs broadcast if global monitor in use. */
1204
1205 left = m->Desktops->ewmh_working_area.x;
1206 right = monitor_get_all_widths() -
1207 (m->Desktops->ewmh_working_area.x
1208 + m->Desktops->ewmh_working_area.width);
1209 top = m->Desktops->ewmh_working_area.y;
1210 bottom = monitor_get_all_heights() -
1211 (m->Desktops->ewmh_working_area.y
1212 + m->Desktops->ewmh_working_area.height);
1213
1214 return ewmh_GetStrutIntersection(m,
1215 x11, y11, x12, y12, left, right, top, bottom, use_percent);
1216 }
1217
1218 /*
1219 * fvwm_win
1220 */
EWMH_SetFrameStrut(FvwmWindow * fw)1221 void EWMH_SetFrameStrut(FvwmWindow *fw)
1222 {
1223 long val[4];
1224 size_borders b;
1225
1226 if (EWMH_IsKdeSysTrayWindow(FW_W(fw)))
1227 {
1228 /* Fixed position of tray window in kicker */
1229 return;
1230 }
1231 get_window_borders(fw, &b);
1232
1233 /* left */
1234 val[0] = b.top_left.width;
1235 /* right */
1236 val[1] = b.bottom_right.width;
1237 /* top */
1238 val[2] = b.top_left.height;
1239 /* bottom */
1240 val[3] = b.bottom_right.height;
1241
1242 ewmh_ChangeProperty(
1243 FW_W(fw), "_KDE_NET_WM_FRAME_STRUT", EWMH_ATOM_LIST_FVWM_WIN,
1244 (unsigned char *)&val, 4);
1245 ewmh_ChangeProperty(
1246 FW_W(fw), "_NET_FRAME_EXTENTS", EWMH_ATOM_LIST_FVWM_WIN,
1247 (unsigned char *)&val, 4);
1248
1249 return;
1250 }
1251
1252 /*
1253 * allowed actions
1254 */
ewmh_AllowsYes(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1255 Bool ewmh_AllowsYes(
1256 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1257 {
1258 return True;
1259 }
1260
ewmh_AllowsClose(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1261 Bool ewmh_AllowsClose(
1262 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1263 {
1264 return is_function_allowed(
1265 F_CLOSE, NULL, fw, RQORIG_PROGRAM_US, False);
1266 }
1267
ewmh_AllowsFullScreen(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1268 Bool ewmh_AllowsFullScreen(
1269 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1270 {
1271 if (
1272 !is_function_allowed(
1273 F_MAXIMIZE, NULL, fw, RQORIG_PROGRAM_US, False) ||
1274 !is_function_allowed(
1275 F_MOVE, NULL, fw, RQORIG_PROGRAM_US, False) ||
1276 !is_function_allowed(
1277 F_RESIZE, NULL, fw, RQORIG_PROGRAM_US, True))
1278 {
1279 return False;
1280 }
1281
1282 return True;
1283 }
1284
ewmh_AllowsMinimize(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1285 Bool ewmh_AllowsMinimize(
1286 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1287 {
1288 return is_function_allowed(F_ICONIFY, NULL, fw, RQORIG_PROGRAM_US, False);
1289 }
1290
ewmh_AllowsMaximize(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1291 Bool ewmh_AllowsMaximize(
1292 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1293 {
1294 return is_function_allowed(F_MAXIMIZE, NULL, fw, RQORIG_PROGRAM_US, False);
1295 }
1296
ewmh_AllowsMove(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1297 Bool ewmh_AllowsMove(
1298 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1299 {
1300 return is_function_allowed(F_MOVE, NULL, fw, RQORIG_PROGRAM_US, False);
1301 }
1302
ewmh_AllowsResize(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1303 Bool ewmh_AllowsResize(
1304 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1305 {
1306 return is_function_allowed(F_RESIZE, NULL, fw, RQORIG_PROGRAM_US, False);
1307 }
1308
EWMH_SetAllowedActions(FvwmWindow * fw)1309 void EWMH_SetAllowedActions(FvwmWindow *fw)
1310 {
1311 Atom wm_actions[EWMH_NUMBER_OF_ALLOWED_ACTIONS];
1312 int i = 0;
1313 ewmh_atom *list = ewmh_atom_allowed_actions;
1314
1315 while(list->name != NULL)
1316 {
1317 if (list->action(fw, NULL, NULL, 0))
1318 wm_actions[i++] = list->atom;
1319 list++;
1320 }
1321
1322 if (i > 0)
1323 {
1324 ewmh_ChangeProperty(
1325 FW_W(fw), "_NET_WM_ALLOWED_ACTIONS",
1326 EWMH_ATOM_LIST_FVWM_WIN, (unsigned char *)wm_actions,
1327 i);
1328 }
1329 else
1330 {
1331 ewmh_DeleteProperty(
1332 FW_W(fw), "_NET_WM_ALLOWED_ACTIONS",
1333 EWMH_ATOM_LIST_FVWM_WIN);
1334 }
1335
1336 return;
1337 }
1338
1339 /*
1340 * Window types
1341 */
1342
ewmh_HandleDesktop(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1343 int ewmh_HandleDesktop(
1344 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1345 {
1346 if (Scr.EwmhDesktop != NULL && FW_W(Scr.EwmhDesktop) != FW_W(fw))
1347 {
1348 fvwm_debug(__func__,
1349 "A Desktop application (0x%lx) already runs! This"
1350 " can cause problems\n", FW_W(Scr.EwmhDesktop));
1351 /* what to do ? */
1352 }
1353
1354 fw->ewmh_window_type = EWMH_WINDOW_TYPE_DESKTOP_ID;
1355 Scr.EwmhDesktop = fw;
1356
1357 SSET_LAYER(*style, 0);
1358 style->flags.use_layer = 1;
1359 style->flag_mask.use_layer = 1;
1360 style->change_mask.use_layer = 1;
1361
1362 S_SET_IS_STICKY_ACROSS_PAGES(SCF(*style), 1);
1363 S_SET_IS_STICKY_ACROSS_PAGES(SCM(*style), 1);
1364 S_SET_IS_STICKY_ACROSS_PAGES(SCC(*style), 1);
1365 S_SET_IS_STICKY_ACROSS_DESKS(SCF(*style), 1);
1366 S_SET_IS_STICKY_ACROSS_DESKS(SCM(*style), 1);
1367 S_SET_IS_STICKY_ACROSS_DESKS(SCC(*style), 1);
1368
1369 S_SET_IS_FIXED(SCF(*style), 1);
1370 S_SET_IS_FIXED(SCM(*style), 1);
1371 S_SET_IS_FIXED(SCC(*style), 1);
1372
1373 S_SET_DO_WINDOW_LIST_SKIP(SCF(*style), 1);
1374 S_SET_DO_WINDOW_LIST_SKIP(SCM(*style), 1);
1375 S_SET_DO_WINDOW_LIST_SKIP(SCC(*style), 1);
1376
1377 S_SET_DO_CIRCULATE_SKIP(SCF(*style), 1);
1378 S_SET_DO_CIRCULATE_SKIP(SCM(*style), 1);
1379 S_SET_DO_CIRCULATE_SKIP(SCC(*style), 1);
1380
1381 S_SET_IS_UNICONIFIABLE(SCF(*style), 1);
1382 S_SET_IS_UNICONIFIABLE(SCM(*style), 1);
1383 S_SET_IS_UNICONIFIABLE(SCC(*style), 1);
1384
1385 S_SET_IS_UNMAXIMIZABLE(SCF(*style), 1);
1386 S_SET_IS_UNMAXIMIZABLE(SCM(*style), 1);
1387 S_SET_IS_UNMAXIMIZABLE(SCC(*style), 1);
1388
1389 /* No border */
1390 SSET_BORDER_WIDTH(*style, 0);
1391 style->flags.has_border_width = 1;
1392 style->flag_mask.has_border_width = 1;
1393 style->change_mask.has_border_width = 1;
1394
1395 SSET_HANDLE_WIDTH(*style, 0);
1396 style->flags.has_handle_width = 1;
1397 style->flag_mask.has_handle_width = 1;
1398 style->change_mask.has_handle_width = 1;
1399
1400 /* no title */
1401 style->flags.has_no_title = 1;
1402 style->flag_mask.has_no_title = 1;
1403 style->change_mask.has_no_title = 1;
1404
1405 /* ClickToFocus, I do not think we should use NeverFocus */
1406 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCF(*style)), 1);
1407 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCM(*style)), 1);
1408 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCC(*style)), 1);
1409 FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCF(*style)), 1);
1410 FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCM(*style)), 1);
1411 FPS_GRAB_FOCUS(S_FOCUS_POLICY(SCC(*style)), 1);
1412
1413 /* ClickToFocusPassesClick */
1414 FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCF(*style)), 1);
1415 FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1416 FPS_PASS_FOCUS_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1417 FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCF(*style)), 1);
1418 FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1419 FPS_PASS_RAISE_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1420
1421 /* not useful */
1422 FPS_RAISE_FOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCF(*style)), 0);
1423 FPS_RAISE_FOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1424 FPS_RAISE_FOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1425 FPS_RAISE_UNFOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCF(*style)), 0);
1426 FPS_RAISE_UNFOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1427 FPS_RAISE_UNFOCUSED_CLIENT_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1428 FPS_RAISE_FOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCF(*style)), 0);
1429 FPS_RAISE_FOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1430 FPS_RAISE_FOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1431 FPS_RAISE_UNFOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCF(*style)), 0);
1432 FPS_RAISE_UNFOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCM(*style)), 1);
1433 FPS_RAISE_UNFOCUSED_DECOR_CLICK(S_FOCUS_POLICY(SCC(*style)), 1);
1434
1435 return 1;
1436 }
1437
ewmh_HandleDialog(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1438 int ewmh_HandleDialog(
1439 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1440 {
1441 fw->ewmh_window_type = EWMH_WINDOW_TYPE_DIALOG_ID;
1442
1443 return 0;
1444 }
1445
ewmh_HandleDock(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1446 int ewmh_HandleDock(
1447 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1448 {
1449 fw->ewmh_window_type = EWMH_WINDOW_TYPE_DOCK_ID;
1450
1451 S_SET_IS_STICKY_ACROSS_PAGES(SCF(*style), 1);
1452 S_SET_IS_STICKY_ACROSS_PAGES(SCM(*style), 1);
1453 S_SET_IS_STICKY_ACROSS_PAGES(SCC(*style), 1);
1454 S_SET_IS_STICKY_ACROSS_DESKS(SCF(*style), 1);
1455 S_SET_IS_STICKY_ACROSS_DESKS(SCM(*style), 1);
1456 S_SET_IS_STICKY_ACROSS_DESKS(SCC(*style), 1);
1457
1458 S_SET_DO_WINDOW_LIST_SKIP(SCF(*style), 1);
1459 S_SET_DO_WINDOW_LIST_SKIP(SCM(*style), 1);
1460 S_SET_DO_WINDOW_LIST_SKIP(SCC(*style), 1);
1461
1462 S_SET_DO_CIRCULATE_SKIP(SCF(*style), 1);
1463 S_SET_DO_CIRCULATE_SKIP(SCM(*style), 1);
1464 S_SET_DO_CIRCULATE_SKIP(SCC(*style), 1);
1465
1466 S_SET_IS_UNICONIFIABLE(SCF(*style), 1);
1467 S_SET_IS_UNICONIFIABLE(SCM(*style), 1);
1468 S_SET_IS_UNICONIFIABLE(SCC(*style), 1);
1469
1470 S_SET_IS_UNMAXIMIZABLE(SCF(*style), 1);
1471 S_SET_IS_UNMAXIMIZABLE(SCM(*style), 1);
1472 S_SET_IS_UNMAXIMIZABLE(SCC(*style), 1);
1473
1474 if (fw->ewmh_hint_layer == -1)
1475 {
1476 fw->ewmh_hint_layer = Scr.TopLayer;
1477 if (DO_EWMH_USE_STACKING_HINTS(style))
1478 {
1479 SSET_LAYER(*style, Scr.TopLayer);
1480 style->flags.use_layer = 1;
1481 style->flag_mask.use_layer = 1;
1482 style->change_mask.use_layer = 1;
1483 }
1484 else if (!style->change_mask.use_layer)
1485 {
1486 SSET_LAYER(*style, Scr.DefaultLayer);
1487 style->flags.use_layer = 1;
1488 style->flag_mask.use_layer = 1;
1489 style->change_mask.use_layer = 1;
1490 }
1491 }
1492 /* no title ? MWM hints should be used by the app but ... */
1493
1494 return 1;
1495 }
1496
ewmh_HandleMenu(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1497 int ewmh_HandleMenu(
1498 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1499 {
1500 fw->ewmh_window_type = EWMH_WINDOW_TYPE_MENU_ID;
1501
1502 /* tear off menu */
1503
1504 S_SET_DO_WINDOW_LIST_SKIP(SCF(*style), 1);
1505 S_SET_DO_WINDOW_LIST_SKIP(SCM(*style), 1);
1506 S_SET_DO_WINDOW_LIST_SKIP(SCC(*style), 1);
1507
1508 S_SET_DO_CIRCULATE_SKIP(SCF(*style), 1);
1509 S_SET_DO_CIRCULATE_SKIP(SCM(*style), 1);
1510 S_SET_DO_CIRCULATE_SKIP(SCC(*style), 1);
1511
1512 /* NeverFocus */
1513 FPS_LENIENT(S_FOCUS_POLICY(SCF(*style)), 0);
1514 FPS_LENIENT(S_FOCUS_POLICY(SCM(*style)), 1);
1515 FPS_LENIENT(S_FOCUS_POLICY(SCC(*style)), 1);
1516
1517 FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCF(*style)), 0);
1518 FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCF(*style)), 0);
1519 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCF(*style)), 0);
1520 FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCF(*style)), 0);
1521 FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCF(*style)), 0);
1522 FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCF(*style)), 0);
1523
1524 FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCM(*style)), 1);
1525 FPS_FOCUS_ENTER(S_FOCUS_POLICY(SCC(*style)), 1);
1526 FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCM(*style)), 1);
1527 FPS_UNFOCUS_LEAVE(S_FOCUS_POLICY(SCC(*style)), 1);
1528 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCM(*style)), 1);
1529 FPS_FOCUS_CLICK_CLIENT(S_FOCUS_POLICY(SCC(*style)), 1);
1530 FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCM(*style)), 1);
1531 FPS_FOCUS_CLICK_DECOR(S_FOCUS_POLICY(SCC(*style)), 1);
1532 FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCM(*style)), 1);
1533 FPS_FOCUS_CLICK_ICON(S_FOCUS_POLICY(SCC(*style)), 1);
1534 FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCM(*style)), 1);
1535 FPS_FOCUS_BY_FUNCTION(S_FOCUS_POLICY(SCC(*style)), 1);
1536
1537 return 1;
1538 }
1539
ewmh_HandleNormal(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1540 int ewmh_HandleNormal(
1541 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1542 {
1543 fw->ewmh_window_type = EWMH_WINDOW_TYPE_NORMAL_ID;
1544
1545 return 0;
1546 }
1547
ewmh_HandleToolBar(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1548 int ewmh_HandleToolBar(
1549 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1550 {
1551 fw->ewmh_window_type = EWMH_WINDOW_TYPE_TOOLBAR_ID;
1552
1553 /* this ok for KDE 2 (and 3??) but I do not think that a toolbar
1554 should be sticky */
1555 S_SET_IS_STICKY_ACROSS_PAGES(SCF(*style), 1);
1556 S_SET_IS_STICKY_ACROSS_PAGES(SCM(*style), 1);
1557 S_SET_IS_STICKY_ACROSS_PAGES(SCC(*style), 1);
1558 S_SET_IS_STICKY_ACROSS_DESKS(SCF(*style), 1);
1559 S_SET_IS_STICKY_ACROSS_DESKS(SCM(*style), 1);
1560 S_SET_IS_STICKY_ACROSS_DESKS(SCC(*style), 1);
1561
1562 S_SET_DO_WINDOW_LIST_SKIP(SCF(*style), 1);
1563 S_SET_DO_WINDOW_LIST_SKIP(SCM(*style), 1);
1564 S_SET_DO_WINDOW_LIST_SKIP(SCC(*style), 1);
1565
1566 S_SET_DO_CIRCULATE_SKIP(SCF(*style), 1);
1567 S_SET_DO_CIRCULATE_SKIP(SCM(*style), 1);
1568 S_SET_DO_CIRCULATE_SKIP(SCC(*style), 1);
1569
1570 /* no title ? MWM hints should be used by the app but ... */
1571
1572 return 1;
1573 }
1574
ewmh_HandleNotification(FvwmWindow * fw,XEvent * ev,window_style * style,unsigned long any)1575 int ewmh_HandleNotification(
1576 FvwmWindow *fw, XEvent *ev, window_style *style, unsigned long any)
1577 {
1578 /* fw->ewmh_window_type is generally used by FvwmIdent, but for this
1579 * EWMH type it is not used. Reporting on unmanaged windows with
1580 * FvwmIdent won't work anyway as the click to the window is eaten.
1581 * So although setting this is a NOP, it might be useful for things in
1582 * the future.
1583 */
1584 fw->ewmh_window_type = EWMH_WINDOW_TYPE_NOTIFICATION_ID;
1585
1586 style->flags.is_unmanaged = 1;
1587 style->flag_mask.is_unmanaged = 1;
1588 style->change_mask.is_unmanaged = 1;
1589
1590 return 1;
1591 }
1592
ewmh_HandleWindowType(FvwmWindow * fw,window_style * style)1593 void ewmh_HandleWindowType(FvwmWindow *fw, window_style *style)
1594 {
1595 CARD32 *val;
1596 unsigned int nitems;
1597 ewmh_atom *list = ewmh_atom_window_type;
1598 int size = 0;
1599 int i = 0;
1600 Bool found = False;
1601
1602 fw->ewmh_window_type = 0;
1603 if (DO_EWMH_IGNORE_WINDOW_TYPE(style))
1604 {
1605 return;
1606 }
1607 val = ewmh_AtomGetByName(
1608 FW_W(fw), "_NET_WM_WINDOW_TYPE",
1609 EWMH_ATOM_LIST_FIXED_PROPERTY, &size);
1610 if (val == NULL)
1611 {
1612 return;
1613 }
1614 /* we support only one window type: the first that we support */
1615 nitems = size / sizeof(CARD32);
1616 while(i < nitems && !found)
1617 {
1618 list = ewmh_atom_window_type;
1619 while(list->name != NULL && !found)
1620 {
1621 if (list->atom == val[i])
1622 {
1623 list->action(fw, NULL, style, 0);
1624 found = True;
1625 }
1626 list++;
1627 }
1628 i++;
1629 }
1630 free(val);
1631
1632 return;
1633 }
1634
1635 /*
1636 * a workaround for ksmserver exit windows
1637 */
1638 static
ksmserver_workarround(FvwmWindow * fw)1639 int ksmserver_workarround(FvwmWindow *fw)
1640 {
1641
1642 if (fw->name.name != NULL && fw->class.res_name != NULL &&
1643 fw->icon_name.name != NULL && fw->class.res_class != NULL &&
1644 strcmp(fw->name.name, "ksmserver") == 0 &&
1645 strcmp(fw->class.res_class, "ksmserver") == 0 &&
1646 strcmp(fw->icon_name.name, "ksmserver") == 0 &&
1647 strcmp(fw->class.res_name, "unnamed") == 0)
1648 {
1649 int layer = 0;
1650
1651 if (IS_TRANSIENT(fw))
1652 {
1653 layer = Scr.TopLayer + 2;
1654 }
1655 else
1656 {
1657 layer = Scr.TopLayer + 1;
1658 }
1659 new_layer(fw, layer);
1660
1661 return 1;
1662 }
1663
1664 return 0;
1665 }
1666
1667 /*
1668 * Window Initialisation / Destroy
1669 */
1670
EWMH_GetStyle(FvwmWindow * fw,window_style * style)1671 void EWMH_GetStyle(FvwmWindow *fw, window_style *style)
1672 {
1673 if (style->change_mask.use_layer)
1674 {
1675 fw->ewmh_normal_layer = SGET_LAYER(*style);
1676 }
1677 else if (fw->ewmh_normal_layer == 0)
1678 {
1679 fw->ewmh_normal_layer = Scr.DefaultLayer;
1680 }
1681 ewmh_WMState(fw, NULL, style, 0);
1682 ewmh_WMDesktop(fw, NULL, style, 0);
1683 /* the window type override the state hint */
1684 ewmh_HandleWindowType(fw, style);
1685
1686 return;
1687 }
1688
ewmh_check_wm_pid(FvwmWindow * fw)1689 static void ewmh_check_wm_pid(FvwmWindow *fw)
1690 {
1691 int size = 0;
1692 CARD32 *val;
1693
1694 fw->ewmh_window_type = 0;
1695 val = ewmh_AtomGetByName(
1696 FW_W(fw), "_NET_WM_PID", EWMH_ATOM_LIST_FIXED_PROPERTY, &size);
1697 if (val != NULL)
1698 {
1699 free(val);
1700 SET_HAS_EWMH_WM_PID(fw, 1);
1701 if (CR_MOTION_METHOD(fw) == CR_MOTION_METHOD_AUTO)
1702 {
1703 SET_CR_MOTION_METHOD(fw, CR_MOTION_METHOD_USE_GRAV);
1704 SET_CR_MOTION_METHOD_DETECTED(fw, 1);
1705 }
1706 }
1707
1708 return;
1709 }
1710
1711 /* see also EWMH_WMName and EWMH_WMIconName in add_window */
EWMH_WindowInit(FvwmWindow * fw)1712 void EWMH_WindowInit(FvwmWindow *fw)
1713 {
1714 /*EWMH_DLOG("Init window 0x%lx",FW_W(fw));*/
1715 EWMH_SetWMState(fw, False);
1716 EWMH_SetWMDesktop(fw);
1717 EWMH_SetAllowedActions(fw);
1718 ewmh_WMStrut(fw, NULL, NULL, 0);
1719 ewmh_WMIconGeometry(fw, NULL, NULL, 0);
1720 ewmh_AddToKdeSysTray(fw);
1721 EWMH_SetFrameStrut(fw);
1722 if (IS_EWMH_DESKTOP(FW_W(fw)))
1723 {
1724 return;
1725 }
1726 if (ksmserver_workarround(fw))
1727 {
1728 return;
1729 }
1730 ewmh_WMIcon(fw, NULL, NULL, 0);
1731 ewmh_check_wm_pid(fw);
1732 /*EWMH_DLOG("window 0x%lx initialised",FW_W(fw));*/
1733
1734 return;
1735 }
1736
1737 /* unmap or reparent: restore state */
EWMH_RestoreInitialStates(FvwmWindow * fw,int event_type)1738 void EWMH_RestoreInitialStates(FvwmWindow *fw, int event_type)
1739 {
1740 EWMH_SetWMState(fw, True);
1741 if (HAS_EWMH_INIT_WM_DESKTOP(fw) == EWMH_STATE_HAS_HINT)
1742 {
1743 ewmh_ChangeProperty(
1744 FW_W(fw), "_NET_WM_DESKTOP",
1745 EWMH_ATOM_LIST_CLIENT_WIN,
1746 (unsigned char *)&(fw->ewmh_hint_desktop), 1);
1747 }
1748 else
1749 {
1750 ewmh_DeleteProperty(
1751 FW_W(fw), "_NET_WM_DESKTOP",
1752 EWMH_ATOM_LIST_CLIENT_WIN);
1753 }
1754 if (HAS_EWMH_WM_ICON_HINT(fw) == EWMH_FVWM_ICON)
1755 {
1756 EWMH_DeleteWmIcon(fw, True, True);
1757 }
1758
1759 return;
1760 }
1761
1762 /* a window are going to be destroyed (in the add_window.c destroy_window
1763 * sens) */
EWMH_DestroyWindow(FvwmWindow * fw)1764 void EWMH_DestroyWindow(FvwmWindow *fw)
1765 {
1766 if (IS_EWMH_DESKTOP(FW_W(fw)))
1767 {
1768 Scr.EwmhDesktop = NULL;
1769 }
1770 if (fw->Desk >= fw->m->ewmhc.NumberOfDesktops)
1771 {
1772 fw->m->ewmhc.NeedsToCheckDesk = True;
1773 }
1774
1775 return;
1776 }
1777
1778 /* a window has been destroyed (unmap/reparent/destroy) */
EWMH_WindowDestroyed(void)1779 void EWMH_WindowDestroyed(void)
1780 {
1781 struct monitor *m = monitor_get_current();
1782
1783 if (m == NULL)
1784 return;
1785
1786 EWMH_SetClientList(m);
1787 EWMH_SetClientListStacking(m);
1788 if (m->ewmhc.NeedsToCheckDesk)
1789 {
1790 EWMH_SetNumberOfDesktops(m);
1791 }
1792 ewmh_ComputeAndSetWorkArea(m);
1793 ewmh_HandleDynamicWorkArea(m);
1794
1795 return;
1796 }
1797
1798 /*
1799 * Init Stuff
1800 */
1801 static
set_all_atom_in_list(ewmh_atom * list)1802 int set_all_atom_in_list(ewmh_atom *list)
1803 {
1804 int l = 0;
1805
1806 while(list->name != NULL)
1807 {
1808 list->atom = XInternAtom(dpy,list->name,False);
1809 if (list->atom_type == None)
1810 {
1811 list->atom_type = XA_UTF8_STRING;
1812 }
1813 l++;
1814 list++;
1815 }
1816
1817 return l;
1818 }
1819
1820 static
set_net_supported(int l)1821 void set_net_supported(int l)
1822 {
1823 Atom *supported;
1824 int i, k = 0;
1825
1826 supported = fxmalloc(l*sizeof(Atom));
1827 for(i=0; i < NUMBER_OF_ATOM_LISTS; i++)
1828 {
1829 ewmh_atom *list = atom_list[i].list;
1830 while(list->name != NULL)
1831 {
1832 supported[k++] = list->atom;
1833 list++;
1834 }
1835 }
1836
1837 ewmh_ChangeProperty(
1838 Scr.Root, "_NET_SUPPORTED", EWMH_ATOM_LIST_FVWM_ROOT,
1839 (unsigned char *)supported, k);
1840 free(supported);
1841
1842 return;
1843 }
1844
1845 static
clean_up(void)1846 void clean_up(void)
1847 {
1848 ewmh_ChangeProperty(
1849 Scr.Root,"_KDE_NET_SYSTEM_TRAY_WINDOWS",
1850 EWMH_ATOM_LIST_FVWM_ROOT, NULL, 0);
1851
1852 return;
1853 }
1854
EWMH_Init(struct monitor * m)1855 void EWMH_Init(struct monitor *m)
1856 {
1857 int i;
1858 int supported_count = 0;
1859 long val;
1860 XTextProperty text;
1861 unsigned char utf_name[4];
1862 char *names[1];
1863 XClassHint classhints;
1864
1865 /* initialisation of all the atoms */
1866 XA_UTF8_STRING = XInternAtom(dpy,"UTF8_STRING",False);
1867 for(i=0; i < NUMBER_OF_ATOM_LISTS; i++)
1868 {
1869 supported_count += set_all_atom_in_list(atom_list[i].list);
1870 }
1871
1872 /* the laws that we respect */
1873 set_net_supported(supported_count);
1874
1875 /* use the Scr.NoFocusWin as the WM_CHECK window */
1876 val = Scr.NoFocusWin;
1877 ewmh_ChangeProperty(
1878 Scr.Root, "_NET_SUPPORTING_WM_CHECK",
1879 EWMH_ATOM_LIST_FVWM_ROOT, (unsigned char *)&val, 1);
1880 ewmh_ChangeProperty(
1881 Scr.NoFocusWin, "_NET_SUPPORTING_WM_CHECK",
1882 EWMH_ATOM_LIST_FVWM_ROOT, (unsigned char *)&val, 1);
1883
1884 names[0] = "fvwm";
1885 classhints.res_name= "fvwm";
1886 classhints.res_class= "FVWM";
1887
1888 XSetClassHint(dpy, Scr.NoFocusWin, &classhints);
1889 if (XStringListToTextProperty(names, 1, &text))
1890 {
1891 XSetWMName(dpy, Scr.NoFocusWin, &text);
1892 XFree(text.value);
1893 }
1894
1895 /* FVWM in UTF8 */
1896 utf_name[0] = 0x46;
1897 utf_name[1] = 0x56;
1898 utf_name[2] = 0x57;
1899 utf_name[3] = 0x4D;
1900
1901 ewmh_ChangeProperty(
1902 Scr.NoFocusWin, "_NET_WM_NAME", EWMH_ATOM_LIST_PROPERTY_NOTIFY,
1903 (unsigned char *)&utf_name, 4);
1904
1905 clean_up();
1906
1907 EWMH_SetDesktopNames(m);
1908 EWMH_SetCurrentDesktop(m);
1909 EWMH_SetNumberOfDesktops(m);
1910 EWMH_SetDesktopViewPort(m);
1911 EWMH_SetDesktopGeometry(m);
1912 EWMH_SetClientList(m);
1913 EWMH_SetClientListStacking(m);
1914 ewmh_ComputeAndSetWorkArea(m);
1915
1916 return;
1917 }
1918
1919 /*
1920 * Exit Stuff
1921 */
EWMH_ExitStuff(void)1922 void EWMH_ExitStuff(void)
1923 {
1924 FvwmWindow *fw;
1925
1926 for (fw = Scr.FvwmRoot.next; fw != NULL; fw = fw->next)
1927 {
1928 EWMH_RestoreInitialStates(fw, 0);
1929 }
1930
1931 return;
1932 }
1933
1934 #ifdef EWMH_DEBUG
EWMH_DLOG(char * msg,...)1935 void EWMH_DLOG(char *msg, ...)
1936 {
1937 va_list args;
1938 clock_t time_val, time_taken;
1939 static clock_t start_time = 0;
1940 static clock_t prev_time = 0;
1941 struct tms not_used_tms;
1942 char buffer[200]; /* oversized */
1943 time_t mytime;
1944 struct tm *t_ptr;
1945
1946 time(&mytime);
1947 t_ptr = localtime(&mytime);
1948 if (start_time == 0)
1949 {
1950 /* get clock ticks */
1951 prev_time = start_time = (unsigned int)times(¬_used_tms);
1952 }
1953 /* get clock ticks */
1954 time_val = (unsigned int)times(¬_used_tms);
1955 time_taken = time_val - prev_time;
1956 prev_time = time_val;
1957 sprintf(
1958 buffer, "%.2d:%.2d:%.2d %6ld",
1959 t_ptr->tm_hour, t_ptr->tm_min, t_ptr->tm_sec, time_taken);
1960
1961 fvwm_debug(__func__, "EWMH DEBUG: ");
1962 va_start(args,msg);
1963 vfprintf(stderr, msg, args);
1964 va_end(args);
1965 fvwm_debug(__func__, "\n");
1966 fvwm_debug(__func__, " [time]: %s\n",buffer);
1967
1968 return;
1969 }
1970 #endif
1971
EWMH_fullscreen(FvwmWindow * fw)1972 void EWMH_fullscreen(FvwmWindow *fw)
1973 {
1974 fscreen_scr_arg fscr;
1975 rectangle scr_g;
1976 size_borders b;
1977 int page_x;
1978 int page_y;
1979 char cmd[128] = "\0";
1980
1981 /* maximize with ResizeMoveMaximize */
1982 if (
1983 !is_function_allowed(
1984 F_MAXIMIZE, NULL, fw, RQORIG_PROGRAM_US, False) ||
1985 !is_function_allowed(
1986 F_MOVE, NULL, fw, RQORIG_PROGRAM_US, False) ||
1987 !is_function_allowed(
1988 F_RESIZE, NULL, fw, RQORIG_PROGRAM_US, True))
1989 {
1990 return;
1991 }
1992
1993 fw->fullscreen.was_maximized = 0;
1994 fw->fullscreen.is_shaded = 0;
1995
1996 /* Keep the old geometry when restoring from fullscreen. */
1997 memcpy(&fw->fullscreen.g, &fw->g, sizeof(struct window_g));
1998
1999 if (IS_MAXIMIZED(fw))
2000 fw->fullscreen.was_maximized = 1;
2001
2002 if (IS_ICONIFIED(fw))
2003 {
2004 fw->fullscreen.is_iconified = 1;
2005 execute_function_override_window(
2006 NULL, NULL, "Iconify off", 0, fw);
2007 }
2008 if (IS_SHADED(fw))
2009 {
2010 int sas = fw->shade_anim_steps;
2011
2012 fw->fullscreen.is_shaded = 1;
2013 fw->shade_anim_steps = 0;
2014 execute_function_override_window(
2015 NULL, NULL, "WindowShade off", 0, fw);
2016 fw->shade_anim_steps = sas;
2017 }
2018 SET_EWMH_FULLSCREEN(fw,True);
2019 apply_decor_change(fw);
2020 fscr.xypos.x = fw->g.frame.x + fw->g.frame.width / 2;
2021 fscr.xypos.y = fw->g.frame.y + fw->g.frame.height / 2;
2022 FScreenGetScrRect(
2023 &fscr, FSCREEN_XYPOS, &scr_g.x, &scr_g.y,
2024 &scr_g.width, &scr_g.height);
2025 get_window_borders(fw, &b);
2026 get_page_offset_check_visible(&page_x, &page_y, fw);
2027 sprintf(
2028 cmd, "ResizeMoveMaximize %dp %dp +%dp +%dp ewmhiwa",
2029 scr_g.width, scr_g.height,
2030 scr_g.x - b.top_left.width + page_x,
2031 scr_g.y - b.top_left.height + page_y);
2032 if (DO_EWMH_USE_STACKING_HINTS(fw))
2033 {
2034 int sl = fw->ewmh_normal_layer;
2035
2036 new_layer(fw, Scr.TopLayer);
2037 if (sl == 0)
2038 {
2039 fw->ewmh_normal_layer = Scr.DefaultLayer;
2040 }
2041 else
2042 {
2043 fw->ewmh_normal_layer = sl;
2044 }
2045 }
2046 if (cmd[0] != 0)
2047 {
2048 SET_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw, 1);
2049 execute_function_override_window(NULL, NULL, cmd, 0, fw);
2050 SET_DISABLE_CONSTRAIN_SIZE_FULLSCREEN(fw, 0);
2051 }
2052
2053 return;
2054 }
2055