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(&not_used_tms);
1952 	}
1953 	/* get clock ticks */
1954 	time_val = (unsigned int)times(&not_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