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.
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.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * This is all original code by Robert Nation
20 * which reads motif mwm window manager
21 * hints from a window, and makes necessary adjustments for fvwm.
25 /* ---------------------------- included header files ---------------------- */
30 #include <X11/Xproto.h>
31 #include <X11/Xatom.h>
33 #include "libs/fvwmlib.h"
34 #include "libs/FShape.h"
35 #include "libs/Parse.h"
36 #include "libs/lang-strings.h"
39 #include "execcontext.h"
46 #include "decorations.h"
48 /* ---------------------------- local definitions -------------------------- */
50 /* Motif window hints */
51 #define MWM_HINTS_FUNCTIONS (1L << 0)
52 #define MWM_HINTS_DECORATIONS (1L << 1)
54 /* bit definitions for MwmHints.functions */
55 #define MWM_FUNC_ALL (1L << 0)
56 #define MWM_FUNC_RESIZE (1L << 1)
57 #define MWM_FUNC_MOVE (1L << 2)
58 #define MWM_FUNC_MINIMIZE (1L << 3)
59 #define MWM_FUNC_MAXIMIZE (1L << 4)
60 #define MWM_FUNC_CLOSE (1L << 5)
62 /* bit definitions for MwmHints.decorations */
64 #define MWM_DECOR_ALL (1L << 0)
65 #define MWM_DECOR_BORDER (1L << 1)
66 #define MWM_DECOR_RESIZEH (1L << 2)
67 #define MWM_DECOR_TITLE (1L << 3)
68 #define MWM_DECOR_MENU (1L << 4)
69 #define MWM_DECOR_MINIMIZE (1L << 5)
70 #define MWM_DECOR_MAXIMIZE (1L << 6)
73 #define PROP_MOTIF_WM_HINTS_ELEMENTS 4
74 #define PROP_MWM_HINTS_ELEMENTS PROP_MOTIF_WM_HINTS_ELEMENTS
76 /* bit definitions for OL hints; I just
77 * made these up, OL stores hints as atoms */
78 #define OL_DECOR_CLOSE (1L << 0)
79 #define OL_DECOR_RESIZEH (1L << 1)
80 #define OL_DECOR_HEADER (1L << 2)
81 #define OL_DECOR_ICON_NAME (1L << 3)
82 #define OL_DECOR_ALL \
83 (OL_DECOR_CLOSE | OL_DECOR_RESIZEH | OL_DECOR_HEADER | OL_DECOR_ICON_NAME)
84 /* indicates if there are any OL hints */
85 #define OL_ANY_HINTS (1L << 7)
87 /* ---------------------------- local macros ------------------------------- */
89 /* ---------------------------- imports ------------------------------------ */
91 extern Atom _XA_MwmAtom
;
93 /* ---------------------------- included code files ------------------------ */
95 /* ---------------------------- local types -------------------------------- */
97 /* Motif window hints */
106 typedef PropMotifWmHints PropMwmHints
;
108 /* ---------------------------- forward declarations ----------------------- */
110 /* ---------------------------- local variables ---------------------------- */
112 /* ---------------------------- exported variables (globals) --------------- */
114 /* ---------------------------- local functions ---------------------------- */
116 /* ---------------------------- interface functions ------------------------ */
120 * Reads the property MOTIF_WM_HINTS
123 void GetMwmHints(FvwmWindow
*t
)
127 unsigned long nitems
, bytesafter
;
131 XFree((char *)t
->mwm_hints
);
134 if (XGetWindowProperty(
135 dpy
, FW_W(t
), _XA_MwmAtom
, 0L, 32L, False
,
136 _XA_MwmAtom
, &actual_type
, &actual_format
, &nitems
,
137 &bytesafter
,(unsigned char **)&t
->mwm_hints
)==Success
)
139 if (nitems
>= PROP_MOTIF_WM_HINTS_ELEMENTS
)
152 * Reads the openlook properties _OL_WIN_ATTR, _OL_DECOR_ADD, _OL_DECOR_DEL
154 * _OL_WIN_ATTR - the win_type field is the either the first atom if the
155 * property has length three or the second atom if the property has
156 * length five. It can be any of:
157 * _OL_WT_BASE (no changes)
158 * _OL_WT_CMD (no minimize decoration)
159 * _OL_WT_HELP (no minimize, maximize or resize handle decorations)
160 * _OL_WT_NOTICE (no minimize, maximize, system menu, resize handle
161 * or titlebar decorations)
162 * _OL_WT_OTHER (no minimize, maximize, system menu, resize handle
163 * or titlebar decorations)
164 * In addition, if the _OL_WIN_ATTR property is in the three atom format
165 * or if the type is _OL_WT_OTHER, then the icon name is not displayed
166 * (same behavior as olvwm).
168 * _OL_DECOR_ADD or _OL_DECOR_DEL - indivdually add or remove minimize
169 * button (_OL_DECOR_CLOSE), resize handles (_OL_DECOR_RESIZE), title bar
170 * (_OL_DECOR_HEADER), or icon name (_OL_DECOR_ICON_NAME).
172 * The documentation for the Open Look hints was taken from "Advanced X
173 * Window Application Programming", Eric F. Johnson and Kevin Reichard
174 * (M&T Books), and the olvwm source code (available at ftp.x.org in
177 void GetOlHints(FvwmWindow
*t
)
181 unsigned long nitems
, bytesafter
;
186 t
->ol_hints
= OL_DECOR_ALL
;
188 if (XGetWindowProperty(
189 dpy
, FW_W(t
), _XA_OL_WIN_ATTR
, 0L, 32L, False
,
190 _XA_OL_WIN_ATTR
, &actual_type
, &actual_format
,
191 &nitems
, &bytesafter
, (unsigned char **)&hints
) == Success
)
195 t
->ol_hints
|= OL_ANY_HINTS
;
206 /* got this from olvwm and sort of mapped it to
208 if (win_type
== _XA_OL_WT_BASE
)
210 t
->ol_hints
= OL_DECOR_ALL
;
212 else if (win_type
== _XA_OL_WT_CMD
)
214 t
->ol_hints
= OL_DECOR_ALL
& ~OL_DECOR_CLOSE
;
216 else if (win_type
== _XA_OL_WT_HELP
)
218 t
->ol_hints
= OL_DECOR_ALL
&
219 ~(OL_DECOR_CLOSE
| OL_DECOR_RESIZEH
);
221 else if (win_type
== _XA_OL_WT_NOTICE
)
223 t
->ol_hints
= OL_DECOR_ALL
&
224 ~(OL_DECOR_CLOSE
| OL_DECOR_RESIZEH
|
225 OL_DECOR_HEADER
| OL_DECOR_ICON_NAME
);
227 else if (win_type
== _XA_OL_WT_OTHER
)
233 t
->ol_hints
= OL_DECOR_ALL
;
238 t
->ol_hints
&= ~OL_DECOR_ICON_NAME
;
248 if (XGetWindowProperty(
249 dpy
, FW_W(t
), _XA_OL_DECOR_ADD
, 0L, 32L, False
,
250 XA_ATOM
, &actual_type
, &actual_format
, &nitems
,
251 &bytesafter
,(unsigned char **)&hints
)==Success
)
253 for (i
= 0; i
< nitems
; i
++)
255 t
->ol_hints
|= OL_ANY_HINTS
;
256 if (hints
[i
] == _XA_OL_DECOR_CLOSE
)
258 t
->ol_hints
|= OL_DECOR_CLOSE
;
260 else if (hints
[i
] == _XA_OL_DECOR_RESIZE
)
262 t
->ol_hints
|= OL_DECOR_RESIZEH
;
264 else if (hints
[i
] == _XA_OL_DECOR_HEADER
)
266 t
->ol_hints
|= OL_DECOR_HEADER
;
268 else if (hints
[i
] == _XA_OL_DECOR_ICON_NAME
)
270 t
->ol_hints
|= OL_DECOR_ICON_NAME
;
279 if (XGetWindowProperty(
280 dpy
, FW_W(t
), _XA_OL_DECOR_DEL
, 0L, 32L, False
,
281 XA_ATOM
, &actual_type
, &actual_format
, &nitems
,
282 &bytesafter
,(unsigned char **)&hints
)==Success
)
284 for (i
= 0; i
< nitems
; i
++)
286 t
->ol_hints
|= OL_ANY_HINTS
;
287 if (hints
[i
] == _XA_OL_DECOR_CLOSE
)
289 t
->ol_hints
&= ~OL_DECOR_CLOSE
;
291 else if (hints
[i
] == _XA_OL_DECOR_RESIZE
)
293 t
->ol_hints
&= ~OL_DECOR_RESIZEH
;
295 else if (hints
[i
] == _XA_OL_DECOR_HEADER
)
297 t
->ol_hints
&= ~OL_DECOR_HEADER
;
299 else if (hints
[i
] == _XA_OL_DECOR_ICON_NAME
)
301 t
->ol_hints
&= ~OL_DECOR_ICON_NAME
;
316 * Interprets the property MOTIF_WM_HINTS, sets decoration and functions
320 void SelectDecor(FvwmWindow
*t
, window_style
*pstyle
, short *buttons
)
328 style_flags
*sflags
= &(pstyle
->flags
);
330 border_width
= (SHAS_BORDER_WIDTH(sflags
)) ?
331 SGET_BORDER_WIDTH(*pstyle
) : DEFAULT_BORDER_WIDTH
;
332 if (border_width
> MAX_BORDER_WIDTH
)
334 border_width
= MAX_BORDER_WIDTH
;
336 handle_width
= (SHAS_HANDLE_WIDTH(sflags
)) ?
337 SGET_HANDLE_WIDTH(*pstyle
) : DEFAULT_HANDLE_WIDTH
;
338 if (handle_width
> MAX_HANDLE_WIDTH
)
340 handle_width
= MAX_HANDLE_WIDTH
;
343 *buttons
= (1 << NUMBER_OF_TITLE_BUTTONS
) - 1;
345 decor
= MWM_DECOR_ALL
;
346 t
->functions
= MWM_FUNC_ALL
;
349 prop
= (PropMwmHints
*)t
->mwm_hints
;
350 if (SHAS_MWM_DECOR(sflags
))
352 if (prop
->flags
& MWM_HINTS_DECORATIONS
)
355 if (prop
->decorations
& 0x1)
357 decor
|= MWM_DECOR_ALL
;
359 if (prop
->decorations
& 0x2)
361 decor
|= MWM_DECOR_BORDER
;
363 if (prop
->decorations
& 0x4)
365 decor
|= MWM_DECOR_RESIZEH
;
367 if (prop
->decorations
& 0x8)
369 decor
|= MWM_DECOR_TITLE
;
371 if (prop
->decorations
& 0x10)
373 decor
|= MWM_DECOR_MENU
;
375 if (prop
->decorations
& 0x20)
377 decor
|= MWM_DECOR_MINIMIZE
;
379 if (prop
->decorations
& 0x40)
381 decor
|= MWM_DECOR_MAXIMIZE
;
385 if (SHAS_MWM_FUNCTIONS(sflags
))
387 if (prop
->flags
& MWM_HINTS_FUNCTIONS
)
389 t
->functions
= prop
->functions
;
394 /* functions affect the decorations! if the user says
395 * no iconify function, then the iconify button doesn't show
397 if (t
->functions
& MWM_FUNC_ALL
)
399 /* If we get ALL + some other things, that means to use
400 * ALL except the other things... */
401 t
->functions
&= ~MWM_FUNC_ALL
;
403 (MWM_FUNC_RESIZE
| MWM_FUNC_MOVE
| MWM_FUNC_MINIMIZE
|
404 MWM_FUNC_MAXIMIZE
| MWM_FUNC_CLOSE
) &
407 if (SHAS_MWM_FUNCTIONS(sflags
) && IS_TRANSIENT(t
))
409 t
->functions
&= ~(MWM_FUNC_MAXIMIZE
|MWM_FUNC_MINIMIZE
);
412 if (decor
& MWM_DECOR_ALL
)
414 /* If we get ALL + some other things, that means to use
415 * ALL except the other things... */
416 decor
&= ~MWM_DECOR_ALL
;
417 decor
= MWM_DECOR_EVERYTHING
& (~decor
);
420 /* now add/remove any functions specified in the OL hints */
421 if (SHAS_OL_DECOR(sflags
) && (t
->ol_hints
& OL_ANY_HINTS
))
423 if (t
->ol_hints
& OL_DECOR_CLOSE
)
425 t
->functions
|= MWM_FUNC_MINIMIZE
;
426 decor
|= MWM_FUNC_MINIMIZE
;
430 t
->functions
&= ~MWM_FUNC_MINIMIZE
;
431 decor
&= ~MWM_FUNC_MINIMIZE
;
433 if (t
->ol_hints
& OL_DECOR_RESIZEH
)
435 t
->functions
|= (MWM_FUNC_RESIZE
| MWM_FUNC_MAXIMIZE
);
436 decor
|= (MWM_FUNC_RESIZE
| MWM_FUNC_MAXIMIZE
);
440 t
->functions
&= ~(MWM_FUNC_RESIZE
| MWM_FUNC_MAXIMIZE
);
441 decor
&= ~(MWM_FUNC_RESIZE
| MWM_FUNC_MAXIMIZE
);
443 if (t
->ol_hints
& OL_DECOR_HEADER
)
445 t
->functions
|= (MWM_DECOR_MENU
| MWM_FUNC_MINIMIZE
|
446 MWM_FUNC_MAXIMIZE
| MWM_DECOR_TITLE
);
447 decor
|= (MWM_DECOR_MENU
| MWM_FUNC_MINIMIZE
|
448 MWM_FUNC_MAXIMIZE
| MWM_DECOR_TITLE
);
452 t
->functions
&= ~(MWM_DECOR_MENU
| MWM_FUNC_MINIMIZE
|
453 MWM_FUNC_MAXIMIZE
| MWM_DECOR_TITLE
);
454 decor
&= ~(MWM_DECOR_MENU
| MWM_FUNC_MINIMIZE
|
455 MWM_FUNC_MAXIMIZE
| MWM_DECOR_TITLE
);
457 if (t
->ol_hints
& OL_DECOR_ICON_NAME
)
459 SET_HAS_NO_ICON_TITLE(t
, 0);
463 SET_HAS_NO_ICON_TITLE(t
, 1);
467 /* Now I have the un-altered decor and functions, but with the
468 * ALL attribute cleared and interpreted. I need to modify the
469 * decorations that are affected by the functions */
470 if (!(t
->functions
& MWM_FUNC_RESIZE
))
472 decor
&= ~MWM_DECOR_RESIZEH
;
474 /* MWM_FUNC_MOVE has no impact on decorations. */
475 if (!(t
->functions
& MWM_FUNC_MINIMIZE
))
477 decor
&= ~MWM_DECOR_MINIMIZE
;
479 if (!(t
->functions
& MWM_FUNC_MAXIMIZE
))
481 decor
&= ~MWM_DECOR_MAXIMIZE
;
483 /* MWM_FUNC_CLOSE has no impact on decorations. */
485 /* This rule is implicit, but its easier to deal with if
486 * I take care of it now */
487 if (decor
& (MWM_DECOR_MENU
| MWM_DECOR_MINIMIZE
| MWM_DECOR_MAXIMIZE
))
489 decor
|= MWM_DECOR_TITLE
;
492 /* Selected the mwm-decor field, now trim down, based on
494 if (SHAS_NO_TITLE(sflags
) ||
495 (!SDO_DECORATE_TRANSIENT(sflags
) && IS_TRANSIENT(t
)))
497 decor
&= ~MWM_DECOR_TITLE
;
500 if (SHAS_NO_HANDLES(sflags
) ||
501 (!SDO_DECORATE_TRANSIENT(sflags
) && IS_TRANSIENT(t
)))
503 decor
&= ~MWM_DECOR_RESIZEH
;
506 if (SHAS_MWM_DECOR(sflags
) && IS_TRANSIENT(t
))
508 decor
&= ~(MWM_DECOR_MAXIMIZE
|MWM_DECOR_MINIMIZE
);
511 if (FShapesSupported
)
515 decor
&= ~(MWM_DECOR_BORDER
|MWM_DECOR_RESIZEH
);
518 if (IS_EWMH_FULLSCREEN(t
))
520 decor
&=~(MWM_DECOR_BORDER
|MWM_DECOR_RESIZEH
|MWM_DECOR_TITLE
);
523 /* Assume no decorations, and build up */
525 SET_HAS_HANDLES(t
, 0);
528 if (decor
& MWM_DECOR_BORDER
)
530 /* A narrow border is displayed (5 pixels - 2 relief, 1 top,
532 used_width
= border_width
;
534 if (decor
& MWM_DECOR_TITLE
)
536 /* A title bar with no buttons in it
537 * window gets a 1 pixel wide black border. */
540 if (decor
& MWM_DECOR_RESIZEH
)
542 /* A wide border, with corner tiles is desplayed
543 * (10 pixels - 2 relief, 2 shadow) */
544 SET_HAS_HANDLES(t
, 1);
545 used_width
= handle_width
;
547 SET_HAS_NO_BORDER(t
, S_HAS_NO_BORDER(SFC(*sflags
)) || used_width
<= 0);
548 if (HAS_NO_BORDER(t
))
552 SET_HAS_HANDLES(t
, (!HAS_NO_BORDER(t
) && HAS_HANDLES(t
)));
553 set_window_border_size(t
, used_width
);
554 if (!(decor
& MWM_DECOR_MENU
))
556 /* title-bar menu button omitted
557 * window gets 1 pixel wide black border */
558 /* disable any buttons with the MWMDecorMenu flag */
560 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
562 if (TB_HAS_MWM_DECOR_MENU(GetDecor(t
, buttons
[i
])))
564 *buttons
&= ~(1 << i
);
568 if (!(decor
& MWM_DECOR_MINIMIZE
))
570 /* title-bar + iconify button, no menu button.
571 * window gets 1 pixel wide black border */
572 /* disable any buttons with the MWMDecorMinimize/MWMDecorShaded
575 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
577 if (TB_HAS_MWM_DECOR_MINIMIZE(GetDecor(t
, buttons
[i
])))
579 *buttons
&= ~(1 << i
);
583 if (!(decor
& MWM_DECOR_MAXIMIZE
))
585 /* title-bar + maximize button, no menu button, no iconify.
586 * window has 1 pixel wide black border */
587 /* disable any buttons with the MWMDecorMaximize flag */
589 for (i
= 0; i
< NUMBER_OF_TITLE_BUTTONS
; ++i
)
591 if (TB_HAS_MWM_DECOR_MAXIMIZE(GetDecor(t
, buttons
[i
])))
593 *buttons
&= ~(1 << i
);
597 for (i
= (1 << (NUMBER_OF_TITLE_BUTTONS
- 1)); i
; i
>>= 1)
603 t
->nr_left_buttons
= Scr
.nr_left_buttons
;
604 t
->nr_right_buttons
= Scr
.nr_right_buttons
;
606 for (i
= 0; i
/ 2 < Scr
.nr_left_buttons
; i
+= 2)
608 if ((*buttons
& (1 << i
)) == 0)
609 t
->nr_left_buttons
--;
611 for (i
= 1; i
/ 2 < Scr
.nr_right_buttons
; i
+= 2)
613 if ((*buttons
& (1 << i
)) == 0)
614 t
->nr_right_buttons
--;
620 static Bool
__is_resize_allowed(
621 const FvwmWindow
*t
, int functions
, request_origin_t request_origin
)
623 if (!HAS_OVERRIDE_SIZE_HINTS(t
) &&
624 t
->hints
.min_width
== t
->hints
.max_width
&&
625 t
->hints
.min_height
== t
->hints
.max_height
)
629 if (request_origin
&& IS_SIZE_FIXED(t
))
633 else if (!request_origin
&& IS_PSIZE_FIXED(t
))
637 if (request_origin
&& !(functions
& MWM_FUNC_RESIZE
))
646 ** seemed kind of silly to have check_allowed_function and
647 ** check_allowed_function2 partially overlapping in their checks, so I
648 ** combined them here and made them wrapper functions instead.
650 Bool
is_function_allowed(
651 int function
, char *action_string
, const FvwmWindow
*t
,
652 request_origin_t request_origin
, Bool do_allow_override_mwm_hints
)
654 unsigned int functions
;
655 char *functionlist
[] = {
671 return True
; /* this logic come from animated menu */
673 if (do_allow_override_mwm_hints
&& HAS_MWM_OVERRIDE_HINTS(t
))
675 /* allow everything */
680 /* restrict by mwm hints */
681 functions
= t
->functions
;
684 /* Hate to do it, but for lack of a better idea, check based on the
686 /* Complex functions are a little tricky, ignore them if no menu item*/
687 if (function
== F_FUNCTION
&& action_string
!= NULL
)
691 /* remap to regular actions */
693 i
= GetTokenIndex(action_string
, functionlist
, -1, NULL
);
706 function
= F_ICONIFY
;
709 function
= F_ICONIFY
;
712 function
= F_MAXIMIZE
;
721 function
= F_DESTROY
;
730 /* now do the real checks */
734 if (IS_UNCLOSABLE(t
))
738 if (IS_TEAR_OFF_MENU(t
))
740 /* always allow this on tear off menus */
743 if (!WM_DELETES_WINDOW(t
))
747 /* fall through to close clause */
749 if (IS_UNCLOSABLE(t
))
753 if (IS_TEAR_OFF_MENU(t
))
755 /* always allow this on tear off menus */
758 if (!(functions
& MWM_FUNC_CLOSE
))
763 case F_DESTROY
: /* shouldn't destroy always be allowed??? */
764 if (IS_UNCLOSABLE(t
))
768 if (IS_TEAR_OFF_MENU(t
))
770 /* always allow this on tear off menus */
773 if (!(functions
& MWM_FUNC_CLOSE
))
779 if(!__is_resize_allowed(t
, functions
, request_origin
))
785 if ((!IS_ICONIFIED(t
) && !(functions
& MWM_FUNC_MINIMIZE
)) ||
792 if (IS_MAXIMIZE_FIXED_SIZE_DISALLOWED(t
) &&
793 !__is_resize_allowed(t
, functions
, request_origin
))
797 if ((request_origin
&& !(functions
& MWM_FUNC_MAXIMIZE
)) ||
804 /* Move is a funny hint. Keeps it out of the menu, but you're
805 * still allowed to move. */
806 if (request_origin
&& IS_FIXED(t
))
810 else if (!request_origin
&& IS_FIXED_PPOS(t
))
814 if (request_origin
&& !(functions
& MWM_FUNC_MOVE
))
822 } /* end of switch */
824 /* if we fell through, just return True */