1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, see: <http://www.gnu.org/licenses/>
14  */
15 
16 /* ---------------------------- included header files ---------------------- */
17 
18 #include "config.h"
19 
20 #include <stdio.h>
21 #include <X11/Xproto.h>
22 #include <X11/Xatom.h>
23 
24 #include "libs/fvwmlib.h"
25 #include "libs/FShape.h"
26 #include "libs/Parse.h"
27 #include "libs/lang-strings.h"
28 #include "fvwm.h"
29 #include "externs.h"
30 #include "execcontext.h"
31 #include "commands.h"
32 #include "misc.h"
33 #include "screen.h"
34 #include "update.h"
35 #include "style.h"
36 #include "geometry.h"
37 #include "decorations.h"
38 
39 /* ---------------------------- local definitions -------------------------- */
40 
41 /* Motif window hints */
42 #define MWM_HINTS_FUNCTIONS           (1L << 0)
43 #define MWM_HINTS_DECORATIONS         (1L << 1)
44 
45 /* bit definitions for MwmHints.functions */
46 #define MWM_FUNC_ALL            (1L << 0)
47 #define MWM_FUNC_RESIZE         (1L << 1)
48 #define MWM_FUNC_MOVE           (1L << 2)
49 #define MWM_FUNC_MINIMIZE       (1L << 3)
50 #define MWM_FUNC_MAXIMIZE       (1L << 4)
51 #define MWM_FUNC_CLOSE          (1L << 5)
52 
53 /* bit definitions for MwmHints.decorations */
54 #if 0
55 #define MWM_DECOR_ALL                 (1L << 0)
56 #define MWM_DECOR_BORDER              (1L << 1)
57 #define MWM_DECOR_RESIZEH             (1L << 2)
58 #define MWM_DECOR_TITLE               (1L << 3)
59 #define MWM_DECOR_MENU                (1L << 4)
60 #define MWM_DECOR_MINIMIZE            (1L << 5)
61 #define MWM_DECOR_MAXIMIZE            (1L << 6)
62 #endif
63 
64 #define PROP_MOTIF_WM_HINTS_ELEMENTS  4
65 #define PROP_MWM_HINTS_ELEMENTS       PROP_MOTIF_WM_HINTS_ELEMENTS
66 
67 /* bit definitions for OL hints; I just
68  *  made these up, OL stores hints as atoms */
69 #define OL_DECOR_CLOSE                (1L << 0)
70 #define OL_DECOR_RESIZEH              (1L << 1)
71 #define OL_DECOR_HEADER               (1L << 2)
72 #define OL_DECOR_ICON_NAME            (1L << 3)
73 #define OL_DECOR_ALL                  \
74   (OL_DECOR_CLOSE | OL_DECOR_RESIZEH | OL_DECOR_HEADER | OL_DECOR_ICON_NAME)
75 /* indicates if there are any OL hints */
76 #define OL_ANY_HINTS                  (1L << 7)
77 
78 /* ---------------------------- local macros ------------------------------- */
79 
80 /* ---------------------------- imports ------------------------------------ */
81 
82 extern Atom _XA_MwmAtom;
83 
84 /* ---------------------------- included code files ------------------------ */
85 
86 /* ---------------------------- local types -------------------------------- */
87 
88 /* Motif  window hints */
89 typedef struct
90 {
91 	long flags;
92 	long functions;
93 	long decorations;
94 	long inputMode;
95 } PropMotifWmHints;
96 
97 typedef PropMotifWmHints PropMwmHints;
98 
99 /* ---------------------------- forward declarations ----------------------- */
100 
101 /* ---------------------------- local variables ---------------------------- */
102 
103 /* ---------------------------- exported variables (globals) --------------- */
104 
105 /* ---------------------------- local functions ---------------------------- */
106 
107 /* ---------------------------- interface functions ------------------------ */
108 
109 /*
110  *
111  * Reads the property MOTIF_WM_HINTS
112  *
113  */
GetMwmHints(FvwmWindow * t)114 void GetMwmHints(FvwmWindow *t)
115 {
116 	int actual_format;
117 	Atom actual_type;
118 	unsigned long nitems, bytesafter;
119 
120 	if (t->mwm_hints)
121 	{
122 		XFree((char *)t->mwm_hints);
123 		t->mwm_hints = NULL;
124 	}
125 	if (XGetWindowProperty(
126 		    dpy, FW_W(t), _XA_MwmAtom, 0L, 32L, False,
127 		    _XA_MwmAtom, &actual_type, &actual_format, &nitems,
128 		    &bytesafter,(unsigned char **)&t->mwm_hints)==Success)
129 	{
130 		if (nitems >= PROP_MOTIF_WM_HINTS_ELEMENTS)
131 		{
132 			return;
133 		}
134 	}
135 
136 	t->mwm_hints = NULL;
137 
138 	return;
139 }
140 
141 /*
142  *
143  * Reads the openlook properties _OL_WIN_ATTR, _OL_DECOR_ADD, _OL_DECOR_DEL
144  *
145  * _OL_WIN_ATTR - the win_type field is the either the first atom if the
146  * property has length three or the second atom if the property has
147  * length five.  It can be any of:
148  *     _OL_WT_BASE (no changes)
149  *     _OL_WT_CMD (no minimize decoration)
150  *     _OL_WT_HELP (no minimize, maximize or resize handle decorations)
151  *     _OL_WT_NOTICE (no minimize, maximize, system menu, resize handle
152  *         or titlebar decorations)
153  *     _OL_WT_OTHER (no minimize, maximize, system menu, resize handle
154  *         or titlebar decorations)
155  * In addition, if the _OL_WIN_ATTR property is in the three atom format
156  * or if the type is _OL_WT_OTHER, then the icon name is not displayed
157  * (same behavior as olvwm).
158  *
159  * _OL_DECOR_ADD or _OL_DECOR_DEL - indivdually add or remove minimize
160  * button (_OL_DECOR_CLOSE), resize handles (_OL_DECOR_RESIZE), title bar
161  * (_OL_DECOR_HEADER), or icon name (_OL_DECOR_ICON_NAME).
162  *
163  * The documentation for the Open Look hints was taken from "Advanced X
164  * Window Application Programming", Eric F. Johnson and Kevin Reichard
165  * (M&T Books), and the olvwm source code (available at ftp.x.org in
166  * /R5contrib).
167  */
GetOlHints(FvwmWindow * t)168 void GetOlHints(FvwmWindow *t)
169 {
170 	int actual_format;
171 	Atom actual_type;
172 	unsigned long nitems, bytesafter;
173 	Atom *hints;
174 	int i;
175 	Atom win_type;
176 
177 	t->ol_hints = OL_DECOR_ALL;
178 
179 	if (XGetWindowProperty(
180 		    dpy, FW_W(t), _XA_OL_WIN_ATTR, 0L, 32L, False,
181 		    _XA_OL_WIN_ATTR, &actual_type, &actual_format,
182 		    &nitems, &bytesafter, (unsigned char **)&hints) == Success)
183 	{
184 		if (nitems > 0)
185 		{
186 			t->ol_hints |= OL_ANY_HINTS;
187 
188 			if (nitems == 3)
189 			{
190 				win_type = hints[0];
191 			}
192 			else
193 			{
194 				win_type = hints[1];
195 			}
196 
197 			/* got this from olvwm and sort of mapped it to
198 			 * fvwm/MWM hints */
199 			if (win_type == _XA_OL_WT_BASE)
200 			{
201 				t->ol_hints = OL_DECOR_ALL;
202 			}
203 			else if (win_type == _XA_OL_WT_CMD)
204 			{
205 				t->ol_hints = OL_DECOR_ALL & ~OL_DECOR_CLOSE;
206 			}
207 			else if (win_type == _XA_OL_WT_HELP)
208 			{
209 				t->ol_hints = OL_DECOR_ALL &
210 					~(OL_DECOR_CLOSE | OL_DECOR_RESIZEH);
211 			}
212 			else if (win_type == _XA_OL_WT_NOTICE)
213 			{
214 				t->ol_hints = OL_DECOR_ALL &
215 					~(OL_DECOR_CLOSE | OL_DECOR_RESIZEH |
216 					  OL_DECOR_HEADER | OL_DECOR_ICON_NAME);
217 			}
218 			else if (win_type == _XA_OL_WT_OTHER)
219 			{
220 				t->ol_hints = 0;
221 			}
222 			else
223 			{
224 				t->ol_hints = OL_DECOR_ALL;
225 			}
226 
227 			if (nitems == 3)
228 			{
229 				t->ol_hints &= ~OL_DECOR_ICON_NAME;
230 			}
231 		}
232 
233 		if (hints)
234 		{
235 			XFree (hints);
236 		}
237 	}
238 
239 	if (XGetWindowProperty(
240 		    dpy, FW_W(t), _XA_OL_DECOR_ADD, 0L, 32L, False,
241 		    XA_ATOM, &actual_type, &actual_format, &nitems,
242 		    &bytesafter,(unsigned char **)&hints)==Success)
243 	{
244 		for (i = 0; i < nitems; i++)
245 		{
246 			t->ol_hints |= OL_ANY_HINTS;
247 			if (hints[i] == _XA_OL_DECOR_CLOSE)
248 			{
249 				t->ol_hints |= OL_DECOR_CLOSE;
250 			}
251 			else if (hints[i] == _XA_OL_DECOR_RESIZE)
252 			{
253 				t->ol_hints |= OL_DECOR_RESIZEH;
254 			}
255 			else if (hints[i] == _XA_OL_DECOR_HEADER)
256 			{
257 				t->ol_hints |= OL_DECOR_HEADER;
258 			}
259 			else if (hints[i] == _XA_OL_DECOR_ICON_NAME)
260 			{
261 				t->ol_hints |= OL_DECOR_ICON_NAME;
262 			}
263 		}
264 		if (hints)
265 		{
266 			XFree (hints);
267 		}
268 	}
269 
270 	if (XGetWindowProperty(
271 		    dpy, FW_W(t), _XA_OL_DECOR_DEL, 0L, 32L, False,
272 		    XA_ATOM, &actual_type, &actual_format, &nitems,
273 		    &bytesafter,(unsigned char **)&hints)==Success)
274 	{
275 		for (i = 0; i < nitems; i++)
276 		{
277 			t->ol_hints |= OL_ANY_HINTS;
278 			if (hints[i] == _XA_OL_DECOR_CLOSE)
279 			{
280 				t->ol_hints &= ~OL_DECOR_CLOSE;
281 			}
282 			else if (hints[i] == _XA_OL_DECOR_RESIZE)
283 			{
284 				t->ol_hints &= ~OL_DECOR_RESIZEH;
285 			}
286 			else if (hints[i] == _XA_OL_DECOR_HEADER)
287 			{
288 				t->ol_hints &= ~OL_DECOR_HEADER;
289 			}
290 			else if (hints[i] == _XA_OL_DECOR_ICON_NAME)
291 			{
292 				t->ol_hints &= ~OL_DECOR_ICON_NAME;
293 			}
294 		}
295 		if (hints)
296 		{
297 			XFree (hints);
298 		}
299 	}
300 
301 	return;
302 }
303 
304 
305 /*
306  *
307  * Interprets the property MOTIF_WM_HINTS, sets decoration and functions
308  * accordingly
309  *
310  */
SelectDecor(FvwmWindow * t,window_style * pstyle,short * buttons)311 void SelectDecor(FvwmWindow *t, window_style *pstyle, short *buttons)
312 {
313 	int decor;
314 	int i;
315 	int border_width;
316 	int handle_width;
317 	int used_width;
318 	PropMwmHints *prop;
319 	style_flags *sflags = &(pstyle->flags);
320 
321 	border_width = (SHAS_BORDER_WIDTH(sflags)) ?
322 		SGET_BORDER_WIDTH(*pstyle) : DEFAULT_BORDER_WIDTH;
323 	if (border_width > MAX_BORDER_WIDTH)
324 	{
325 		border_width = MAX_BORDER_WIDTH;
326 	}
327 	handle_width = (SHAS_HANDLE_WIDTH(sflags)) ?
328 		SGET_HANDLE_WIDTH(*pstyle) : DEFAULT_HANDLE_WIDTH;
329 	if (handle_width > MAX_HANDLE_WIDTH)
330 	{
331 		handle_width = MAX_HANDLE_WIDTH;
332 	}
333 
334 	*buttons = (1 << NUMBER_OF_TITLE_BUTTONS) - 1;
335 
336 	decor = MWM_DECOR_ALL;
337 	t->functions = MWM_FUNC_ALL;
338 	if (t->mwm_hints)
339 	{
340 		prop = (PropMwmHints *)t->mwm_hints;
341 		if (SHAS_MWM_DECOR(sflags))
342 		{
343 			if (prop->flags & MWM_HINTS_DECORATIONS)
344 			{
345 				decor = 0;
346 				if (prop->decorations & 0x1)
347 				{
348 					decor |= MWM_DECOR_ALL;
349 				}
350 				if (prop->decorations & 0x2)
351 				{
352 					decor |= MWM_DECOR_BORDER;
353 				}
354 				if (prop->decorations & 0x4)
355 				{
356 					decor |= MWM_DECOR_RESIZEH;
357 				}
358 				if (prop->decorations & 0x8)
359 				{
360 					decor |= MWM_DECOR_TITLE;
361 				}
362 				if (prop->decorations & 0x10)
363 				{
364 					decor |= MWM_DECOR_MENU;
365 				}
366 				if (prop->decorations & 0x20)
367 				{
368 					decor |= MWM_DECOR_MINIMIZE;
369 				}
370 				if (prop->decorations & 0x40)
371 				{
372 					decor |= MWM_DECOR_MAXIMIZE;
373 				}
374 			}
375 		}
376 		if (SHAS_MWM_FUNCTIONS(sflags))
377 		{
378 			if (prop->flags & MWM_HINTS_FUNCTIONS)
379 			{
380 				t->functions = prop->functions;
381 			}
382 		}
383 	}
384 
385 	/* functions affect the decorations! if the user says
386 	 * no iconify function, then the iconify button doesn't show
387 	 * up. */
388 	if (t->functions & MWM_FUNC_ALL)
389 	{
390 		/* If we get ALL + some other things, that means to use
391 		 * ALL except the other things... */
392 		t->functions &= ~MWM_FUNC_ALL;
393 		t->functions =
394 			(MWM_FUNC_RESIZE | MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE |
395 			 MWM_FUNC_MAXIMIZE | MWM_FUNC_CLOSE) &
396 			(~(t->functions));
397 	}
398 	if (SHAS_MWM_FUNCTIONS(sflags) && IS_TRANSIENT(t))
399 	{
400 		t->functions &= ~(MWM_FUNC_MAXIMIZE|MWM_FUNC_MINIMIZE);
401 	}
402 
403 	if (decor & MWM_DECOR_ALL)
404 	{
405 		/* If we get ALL + some other things, that means to use
406 		 * ALL except the other things... */
407 		decor &= ~MWM_DECOR_ALL;
408 		decor = MWM_DECOR_EVERYTHING & (~decor);
409 	}
410 
411 	/* now add/remove any functions specified in the OL hints */
412 	if (SHAS_OL_DECOR(sflags) && (t->ol_hints & OL_ANY_HINTS))
413 	{
414 		if (t->ol_hints & OL_DECOR_CLOSE)
415 		{
416 			t->functions |= MWM_FUNC_MINIMIZE;
417 			decor      |= MWM_FUNC_MINIMIZE;
418 		}
419 		else
420 		{
421 			t->functions &= ~MWM_FUNC_MINIMIZE;
422 			decor      &= ~MWM_FUNC_MINIMIZE;
423 		}
424 		if (t->ol_hints & OL_DECOR_RESIZEH)
425 		{
426 			t->functions |= (MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
427 			decor      |= (MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
428 		}
429 		else
430 		{
431 			t->functions &= ~(MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
432 			decor      &= ~(MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE);
433 		}
434 		if (t->ol_hints & OL_DECOR_HEADER)
435 		{
436 			t->functions |= (MWM_DECOR_MENU | MWM_FUNC_MINIMIZE |
437 					 MWM_FUNC_MAXIMIZE | MWM_DECOR_TITLE);
438 			decor      |= (MWM_DECOR_MENU | MWM_FUNC_MINIMIZE |
439 				       MWM_FUNC_MAXIMIZE | MWM_DECOR_TITLE);
440 		}
441 		else
442 		{
443 			t->functions &= ~(MWM_DECOR_MENU | MWM_FUNC_MINIMIZE |
444 					  MWM_FUNC_MAXIMIZE | MWM_DECOR_TITLE);
445 			decor      &= ~(MWM_DECOR_MENU | MWM_FUNC_MINIMIZE |
446 					MWM_FUNC_MAXIMIZE | MWM_DECOR_TITLE);
447 		}
448 		if (t->ol_hints & OL_DECOR_ICON_NAME)
449 		{
450 			SET_HAS_NO_ICON_TITLE(t, 0);
451 		}
452 		else
453 		{
454 			SET_HAS_NO_ICON_TITLE(t, 1);
455 		}
456 	}
457 
458 	/* Now I have the un-altered decor and functions, but with the
459 	 * ALL attribute cleared and interpreted. I need to modify the
460 	 * decorations that are affected by the functions */
461 	if (!(t->functions & MWM_FUNC_RESIZE))
462 	{
463 		decor &= ~MWM_DECOR_RESIZEH;
464 	}
465 	/* MWM_FUNC_MOVE has no impact on decorations. */
466 	if (!(t->functions & MWM_FUNC_MINIMIZE))
467 	{
468 		decor &= ~MWM_DECOR_MINIMIZE;
469 	}
470 	if (!(t->functions & MWM_FUNC_MAXIMIZE))
471 	{
472 		decor &= ~MWM_DECOR_MAXIMIZE;
473 	}
474 	/* MWM_FUNC_CLOSE has no impact on decorations. */
475 
476 	/* This rule is implicit, but its easier to deal with if
477 	 * I take care of it now */
478 	if (decor & (MWM_DECOR_MENU| MWM_DECOR_MINIMIZE | MWM_DECOR_MAXIMIZE))
479 	{
480 		decor |= MWM_DECOR_TITLE;
481 	}
482 
483 	/* Selected the mwm-decor field, now trim down, based on
484 	 * .fvwmrc entries */
485 	if (SHAS_NO_TITLE(sflags) ||
486 	    (!SDO_DECORATE_TRANSIENT(sflags) && IS_TRANSIENT(t)))
487 	{
488 		decor &= ~MWM_DECOR_TITLE;
489 	}
490 
491 	if (SHAS_NO_HANDLES(sflags) ||
492 	    (!SDO_DECORATE_TRANSIENT(sflags) && IS_TRANSIENT(t)))
493 	{
494 		decor &= ~MWM_DECOR_RESIZEH;
495 	}
496 
497 	if (SHAS_MWM_DECOR(sflags) && IS_TRANSIENT(t))
498 	{
499 		decor &= ~(MWM_DECOR_MAXIMIZE|MWM_DECOR_MINIMIZE);
500 	}
501 
502 	if (FShapesSupported)
503 	{
504 		if (t->wShaped)
505 		{
506 			decor &= ~(MWM_DECOR_BORDER|MWM_DECOR_RESIZEH);
507 		}
508 	}
509 	if (IS_EWMH_FULLSCREEN(t))
510 	{
511 		decor &=~(MWM_DECOR_BORDER|MWM_DECOR_RESIZEH|MWM_DECOR_TITLE);
512 	}
513 
514 	/* Assume no decorations, and build up */
515 	SET_HAS_TITLE(t, 0);
516 	SET_HAS_HANDLES(t, 0);
517 
518 	used_width = 0;
519 	if (decor & MWM_DECOR_BORDER)
520 	{
521 		/* A narrow border is displayed (5 pixels - 2 relief, 1 top,
522 		 * (2 shadow) */
523 		used_width = border_width;
524 	}
525 	if (decor & MWM_DECOR_TITLE)
526 	{
527 		/*      A title bar with no buttons in it
528 		 * window gets a 1 pixel wide black border. */
529 		SET_HAS_TITLE(t, 1);
530 	}
531 	if (decor & MWM_DECOR_RESIZEH)
532 	{
533 		/* A wide border, with corner tiles is desplayed
534 		 * (10 pixels - 2 relief, 2 shadow) */
535 		SET_HAS_HANDLES(t, 1);
536 		used_width = handle_width;
537 	}
538 	SET_HAS_NO_BORDER(t, S_HAS_NO_BORDER(SFC(*sflags)) || used_width <= 0);
539 	if (HAS_NO_BORDER(t))
540 	{
541 		used_width = 0;
542 	}
543 	SET_HAS_HANDLES(t, (!HAS_NO_BORDER(t) && HAS_HANDLES(t)));
544 	set_window_border_size(t, used_width);
545 	if (!(decor & MWM_DECOR_MENU))
546 	{
547 		/*      title-bar menu button omitted
548 		 * window gets 1 pixel wide black border */
549 		/* disable any buttons with the MWMDecorMenu flag */
550 		int i;
551 		for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
552 		{
553 			if (TB_HAS_MWM_DECOR_MENU(GetDecor(t, buttons[i])))
554 			{
555 				*buttons &= ~(1 << i);
556 			}
557 		}
558 	}
559 	if (!(decor & MWM_DECOR_MINIMIZE))
560 	{
561 		/* title-bar + iconify button, no menu button.
562 		 * window gets 1 pixel wide black border */
563 		/* disable any buttons with the MWMDecorMinimize/MWMDecorShaded
564 		 * flag */
565 		int i;
566 		for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
567 		{
568 			if (TB_HAS_MWM_DECOR_MINIMIZE(GetDecor(t, buttons[i])))
569 			{
570 				*buttons &= ~(1 << i);
571 			}
572 		}
573 	}
574 	if (!(decor & MWM_DECOR_MAXIMIZE))
575 	{
576 		/* title-bar + maximize button, no menu button, no iconify.
577 		 * window has 1 pixel wide black border */
578 		/* disable any buttons with the MWMDecorMaximize flag */
579 		int i;
580 		for (i = 0; i < NUMBER_OF_TITLE_BUTTONS; ++i)
581 		{
582 			if (TB_HAS_MWM_DECOR_MAXIMIZE(GetDecor(t, buttons[i])))
583 			{
584 				*buttons &= ~(1 << i);
585 			}
586 		}
587 	}
588 	for (i = (1 << (NUMBER_OF_TITLE_BUTTONS - 1)); i; i >>= 1)
589 	{
590 		if (t->buttons & i)
591 			*buttons &= ~i;
592 	}
593 
594 	t->nr_left_buttons = Scr.nr_left_buttons;
595 	t->nr_right_buttons = Scr.nr_right_buttons;
596 
597 	for (i = 0; i / 2 < Scr.nr_left_buttons; i += 2)
598 	{
599 		if ((*buttons & (1 << i)) == 0)
600 			t->nr_left_buttons--;
601 	}
602 	for (i = 1; i / 2 < Scr.nr_right_buttons; i += 2)
603 	{
604 		if ((*buttons & (1 << i)) == 0)
605 			t->nr_right_buttons--;
606 	}
607 
608 	return;
609 }
610 
__is_resize_allowed(const FvwmWindow * t,int functions,request_origin_t request_origin)611 static Bool __is_resize_allowed(
612 	const FvwmWindow *t, int functions, request_origin_t request_origin)
613 {
614         if (!HAS_OVERRIDE_SIZE_HINTS(t) &&
615 	    t->hints.min_width == t->hints.max_width &&
616 	    t->hints.min_height == t->hints.max_height)
617 	{
618 	        return False;
619 	}
620 	if (request_origin && IS_SIZE_FIXED(t))
621 	{
622 	        return False;
623 	}
624 	else if (!request_origin && IS_PSIZE_FIXED(t))
625 	{
626 	        return False;
627 	}
628 	if (request_origin && !(functions & MWM_FUNC_RESIZE))
629 	{
630 	        return False;
631 	}
632 
633 	return True;
634 }
635 
636 /*
637 ** seemed kind of silly to have check_allowed_function and
638 ** check_allowed_function2 partially overlapping in their checks, so I
639 ** combined them here and made them wrapper functions instead.
640 */
is_function_allowed(int function,char * action_string,const FvwmWindow * t,request_origin_t request_origin,Bool do_allow_override_mwm_hints)641 Bool is_function_allowed(
642 	int function, char *action_string, const FvwmWindow *t,
643 	request_origin_t request_origin, Bool do_allow_override_mwm_hints)
644 {
645 	unsigned int functions;
646 	char *functionlist[] = {
647 		MOVE_STRING,
648 		RESIZE_STRING1,
649 		RESIZE_STRING2,
650 		MINIMIZE_STRING,
651 		MINIMIZE_STRING2,
652 		MAXIMIZE_STRING,
653 		CLOSE_STRING1,
654 		CLOSE_STRING2,
655 		CLOSE_STRING3,
656 		CLOSE_STRING4,
657 		NULL
658 	};
659 
660 	if (t == NULL)
661 	{
662 		return True;  /* this logic come from animated menu */
663 	}
664 	if (do_allow_override_mwm_hints && HAS_MWM_OVERRIDE_HINTS(t))
665 	{
666 		/* allow everything */
667 		functions = ~0;
668 	}
669 	else
670 	{
671 		/* restrict by mwm hints */
672 		functions = t->functions;
673 	}
674 
675 	/* Hate to do it, but for lack of a better idea, check based on the
676 	 * menu entry name */
677 	/* Complex functions are a little tricky, ignore them if no menu item*/
678 	if (function == F_FUNCTION && action_string != NULL)
679 	{
680 		int i;
681 
682 		/* remap to regular actions */
683 
684 		i = GetTokenIndex(action_string, functionlist, -1, NULL);
685 		switch (i)
686 		{
687 		case 0:
688 			function = F_MOVE;
689 			break;
690 		case 1:
691 			function = F_RESIZE;
692 			break;
693 		case 2:
694 			function = F_RESIZE;
695 			break;
696 		case 3:
697 			function = F_ICONIFY;
698 			break;
699 		case 4:
700 			function = F_ICONIFY;
701 			break;
702 		case 5:
703 			function = F_MAXIMIZE;
704 			break;
705 		case 6:
706 			function = F_CLOSE;
707 			break;
708 		case 7:
709 			function = F_DELETE;
710 			break;
711 		case 8:
712 			function = F_DESTROY;
713 			break;
714 		case 9:
715 			function = F_QUIT;
716 			break;
717 		default:
718 			break;
719 		}
720 	}
721 	/* now do the real checks */
722 	switch(function)
723 	{
724 	case F_DELETE:
725 	        if (IS_UNCLOSABLE(t))
726 		{
727 		        return False;
728 		}
729 		if (IS_TEAR_OFF_MENU(t))
730 		{
731 			/* always allow this on tear off menus */
732 			break;
733 		}
734 		if (!WM_DELETES_WINDOW(t))
735 		{
736 			return False;
737 		}
738 		/* fall through to close clause */
739 	case F_CLOSE:
740 	        if (IS_UNCLOSABLE(t))
741 		{
742 		        return False;
743 		}
744 		if (IS_TEAR_OFF_MENU(t))
745 		{
746 			/* always allow this on tear off menus */
747 			break;
748 		}
749 		if (!(functions & MWM_FUNC_CLOSE))
750 		{
751 			return False;
752 		}
753 		break;
754 	case F_DESTROY: /* shouldn't destroy always be allowed??? */
755 	        if (IS_UNCLOSABLE(t))
756 		{
757 		        return False;
758 		}
759 		if (IS_TEAR_OFF_MENU(t))
760 		{
761 			/* always allow this on tear off menus */
762 			break;
763 		}
764 		if (!(functions & MWM_FUNC_CLOSE))
765 		{
766 			return False;
767 		}
768 		break;
769 	case F_RESIZE:
770 	        if(!__is_resize_allowed(t, functions, request_origin))
771 		{
772 		        return False;
773 		}
774 		break;
775 	case F_ICONIFY:
776 		if ((!IS_ICONIFIED(t) && !(functions & MWM_FUNC_MINIMIZE)) ||
777 		    IS_UNICONIFIABLE(t))
778 		{
779 			return False;
780 		}
781 		break;
782 	case F_MAXIMIZE:
783 	        if (IS_MAXIMIZE_FIXED_SIZE_DISALLOWED(t) &&
784 		    !__is_resize_allowed(t, functions, request_origin))
785 		{
786 		       return False;
787 		}
788 		if ((request_origin && !(functions & MWM_FUNC_MAXIMIZE)) ||
789 		    IS_UNMAXIMIZABLE(t))
790 		{
791 			return False;
792 		}
793 		break;
794 	case F_MOVE:
795 		/* Move is a funny hint. Keeps it out of the menu, but you're
796 		 * still allowed to move. */
797 		if (request_origin && IS_FIXED(t))
798 		{
799 			return False;
800 		}
801 		else if (!request_origin && IS_FIXED_PPOS(t))
802 		{
803 			return False;
804 		}
805 		if (request_origin && !(functions & MWM_FUNC_MOVE))
806 		{
807 			return False;
808 		}
809 		break;
810 	case F_FUNCTION:
811 	default:
812 		break;
813 	} /* end of switch */
814 
815 	/* if we fell through, just return True */
816 	return True;
817 }
818