cvsimport
[fvwm.git] / fvwm / ewmh_events.c
blob9110a791ddeea79803e492f8368ff32f71076a82
1 /* -*-c-*- */
2 /* Copyright (C) 2001 Olivier Chapuis */
3 /* This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 #include "config.h"
20 #include <stdio.h>
22 #include <X11/Xlib.h>
23 #include <X11/Xmd.h>
25 #include "libs/fvwmlib.h"
26 #include "libs/FScreen.h"
27 #include "libs/Strings.h"
28 #include "fvwm.h"
29 #include "execcontext.h"
30 #include "functions.h"
31 #include "misc.h"
32 #include "screen.h"
33 #include "virtual.h"
34 #include "commands.h"
35 #include "update.h"
36 #include "style.h"
37 #include "stack.h"
38 #include "events.h"
39 #include "ewmh.h"
40 #include "ewmh_intern.h"
41 #include "decorations.h"
42 #include "geometry.h"
43 #include "borders.h"
45 extern ewmh_atom ewmh_atom_wm_state[];
47 #define DEBUG_EWMH_INIT_STATE 0
49 * root
51 int ewmh_CurrentDesktop(EWMH_CMD_ARGS)
53 if (ev->xclient.data.l[0] < 0 || ev->xclient.data.l[0] > 0x7fffffff)
55 fvwm_msg(
56 WARN, "ewmh_CurrentDesktop",
57 "The application window (id %#lx)\n"
58 " \"%s\" tried to switch to an invalid desktop (%ld)\n"
59 " using an EWMH client message.\n"
60 " fvwm is ignoring this request.\n",
61 fw ? FW_W(fw) : 0, fw ? fw->name.name : "(none)",
62 ev->xclient.data.l[0]);
63 fvwm_msg_report_app_and_workers();
65 return -1;
67 goto_desk(ev->xclient.data.l[0]);
69 return -1;
72 int ewmh_DesktopGeometry(EWMH_CMD_ARGS)
74 char action[256];
75 long width = ev->xclient.data.l[0];
76 long height = ev->xclient.data.l[1];
78 width = width / Scr.MyDisplayWidth;
79 height = height / Scr.MyDisplayHeight;
81 if (width <= 0 || height <= 0)
83 fvwm_msg(
84 WARN, "ewmh_DesktopGeometry",
85 "The application window (id %#lx)\n"
86 " \"%s\" tried to set an invalid desktop geometry"
87 " (%ldx%ld)\n"
88 " using an EWMH client message.\n"
89 " fvwm is ignoring this request.\n",
90 fw ? FW_W(fw) : 0, fw ? fw->name.name : "(none)",
91 ev->xclient.data.l[0], ev->xclient.data.l[1]);
92 fvwm_msg_report_app_and_workers();
94 return -1;
96 sprintf(action, "DesktopSize %ld %ld", width, height);
97 execute_function_override_window(NULL, NULL, action, 0, NULL);
99 return -1;
102 int ewmh_DesktopViewPort(EWMH_CMD_ARGS)
104 if (
105 ev->xclient.data.l[0] < 0 ||
106 ev->xclient.data.l[0] > 0x7fffffff ||
107 ev->xclient.data.l[1] < 0 ||
108 ev->xclient.data.l[1] > 0x7fffffff)
110 fvwm_msg(
111 WARN, "ewmh_DesktopViewPort",
112 "The application window (id %#lx)\n"
113 " \"%s\" tried to switch to an invalid page"
114 " (%ldx%ld)\n"
115 " using an EWMH client message.\n"
116 " fvwm is ignoring this request.\n",
117 fw ? FW_W(fw) : 0, fw ? fw->name.name : "(none)",
118 ev->xclient.data.l[0], ev->xclient.data.l[1]);
119 fvwm_msg_report_app_and_workers();
121 return -1;
123 MoveViewport(ev->xclient.data.l[0], ev->xclient.data.l[1], 1);
124 return -1;
127 int ewmh_NumberOfDesktops(EWMH_CMD_ARGS)
129 int d = ev->xclient.data.l[0];
131 /* not a lot of sinification for fvwm */
132 if (d > 0 && (d <= ewmhc.MaxDesktops || ewmhc.MaxDesktops == 0))
134 ewmhc.NumberOfDesktops = d;
135 EWMH_SetNumberOfDesktops();
137 else
139 fvwm_msg(
140 WARN, "ewmh_NumberOfDesktops",
141 "The application window (id %#lx)\n"
142 " \"%s\" tried to set an invalid number of desktops"
143 " (%ld)\n"
144 " using an EWMH client message.\n"
145 " fvwm is ignoring this request.\n",
146 fw ? FW_W(fw) : 0, fw ? fw->name.name : "(none)",
147 ev->xclient.data.l[0]);
148 fvwm_msg_report_app_and_workers();
151 return -1;
155 * window
158 int ewmh_ActiveWindow(EWMH_CMD_ARGS)
160 if (ev == NULL)
162 return 0;
164 execute_function_override_window(
165 NULL, NULL, "EWMHActivateWindowFunc", 0, fw);
167 return 0;
170 int ewmh_CloseWindow(EWMH_CMD_ARGS)
172 if (ev == NULL)
174 return 0;
176 if (!is_function_allowed(F_CLOSE, NULL, fw, RQORIG_PROGRAM_US, False))
178 return 0;
180 execute_function_override_window(NULL, NULL, "Close", 0, fw);
182 return 0;
185 int ewmh_MoveResizeWindow(EWMH_CMD_ARGS)
187 XConfigureRequestEvent cre;
188 int do_reconfigure;
189 int win_gravity;
190 int value_mask;
191 int source;
193 if (ev == NULL)
195 return 0;
197 win_gravity = ev->xclient.data.l[0] & 0xff;
198 value_mask = (ev->xclient.data.l[0] >> 8) & 0xf;
199 source = (ev->xclient.data.l[0] >> 12) & 0xf;
200 if (fw == NULL)
202 /* unmanaged window */
203 do_reconfigure = 1;
205 else
207 int func;
209 if (
210 ((value_mask & CWWidth) == 0 ||
211 ev->xclient.data.l[3] == fw->g.normal.width) &&
212 ((value_mask & CWHeight) == 0 ||
213 ev->xclient.data.l[4] == fw->g.normal.height))
215 func = F_MOVE;
217 else
219 func = F_RESIZE;
221 do_reconfigure = !!is_function_allowed(
222 func, NULL, fw, RQORIG_PROGRAM, False);
224 if (do_reconfigure == 1)
226 cre.value_mask = value_mask;
227 cre.x = ev->xclient.data.l[1];
228 cre.y = ev->xclient.data.l[2];
229 cre.width = ev->xclient.data.l[3];
230 cre.height = ev->xclient.data.l[4];
231 cre.window = ev->xclient.window;
232 events_handle_configure_request(cre, fw, True, win_gravity);
235 return 0;
238 int ewmh_RestackWindow(EWMH_CMD_ARGS)
240 XConfigureRequestEvent cre;
241 int do_restack;
243 if (ev == NULL)
245 return 0;
247 if (fw == NULL)
249 /* unmanaged window */
250 do_restack = 1;
252 else
254 do_restack = !!DO_EWMH_USE_STACKING_HINTS(fw);
256 if (do_restack == 1)
258 cre.value_mask = CWSibling | CWStackMode;
259 cre.above = ev->xclient.data.l[1];
260 cre.detail = ev->xclient.data.l[2];
261 cre.window = ev->xclient.window;
262 events_handle_configure_request(cre, fw, True, ForgetGravity);
265 return 0;
268 int ewmh_WMDesktop(EWMH_CMD_ARGS)
270 if (ev != NULL && style == NULL)
272 /* client message */
273 unsigned long d = (unsigned long)ev->xclient.data.l[0];
275 /* the spec says that if d = 0xFFFFFFFF then we have to Stick
276 * the window however KDE use 0xFFFFFFFE :o) */
277 if (d == (unsigned long)-2 || d == (unsigned long)-1)
279 execute_function_override_window(
280 NULL, NULL, "Stick on", 0, fw);
282 else if (d >= 0)
284 if (IS_STICKY_ACROSS_PAGES(fw) ||
285 IS_STICKY_ACROSS_DESKS(fw))
287 execute_function_override_window(
288 NULL, NULL, "Stick off", 0, fw);
290 if (fw->Desk != d)
292 do_move_window_to_desk(fw, (int)d);
295 else
297 fvwm_msg(
298 WARN, "ewmh_WMDesktop",
299 "The application window (id %#lx)\n"
300 " \"%s\" tried to move to an invalid desk"
301 " (%ld)\n"
302 " using an EWMH client message.\n"
303 " fvwm is ignoring this request.\n",
304 fw ? FW_W(fw) : 0,
305 fw ? fw->name.name : "(none)",
306 ev->xclient.data.l[0]);
307 fvwm_msg_report_app_and_workers();
310 return 0;
313 if (style != NULL && ev == NULL)
315 /* start on desk */
316 CARD32 *val;
317 int size = 0;
319 if (DO_EWMH_IGNORE_STATE_HINTS(style))
321 SET_HAS_EWMH_INIT_WM_DESKTOP(
322 fw, EWMH_STATE_UNDEFINED_HINT);
324 return 0;
326 if (HAS_EWMH_INIT_WM_DESKTOP(fw) != EWMH_STATE_UNDEFINED_HINT)
328 return 0;
330 val = ewmh_AtomGetByName(
331 FW_W(fw), "_NET_WM_DESKTOP", EWMH_ATOM_LIST_CLIENT_WIN,
332 &size);
333 if (val == NULL)
335 SET_HAS_EWMH_INIT_WM_DESKTOP(fw, EWMH_STATE_NO_HINT);
337 return 0;
339 #if DEBUG_EWMH_INIT_STATE
340 fprintf(
341 stderr, "ewmh WM_DESKTOP hint for window 0x%lx "
342 "(%i,%lu,%u)\n", FW_W(fw),
343 HAS_EWMH_INIT_WM_DESKTOP(fw),
344 fw->ewmh_hint_desktop, val[0]);
345 #endif
346 if (val[0] == (CARD32)-2 || val[0] == (CARD32)-1)
348 S_SET_IS_STICKY_ACROSS_PAGES(SCF(*style), 1);
349 S_SET_IS_STICKY_ACROSS_PAGES(SCM(*style), 1);
350 S_SET_IS_STICKY_ACROSS_PAGES(SCC(*style), 1);
351 S_SET_IS_STICKY_ACROSS_DESKS(SCF(*style), 1);
352 S_SET_IS_STICKY_ACROSS_DESKS(SCM(*style), 1);
353 S_SET_IS_STICKY_ACROSS_DESKS(SCC(*style), 1);
355 else if (val[0] < 256)
357 /* prevent crazy hints ?? */
358 style->flags.use_start_on_desk = 1;
359 style->flag_mask.use_start_on_desk = 1;
360 style->change_mask.use_start_on_desk = 1;
361 SSET_START_DESK(*style, val[0]);
363 SET_HAS_EWMH_INIT_WM_DESKTOP(fw, EWMH_STATE_HAS_HINT);
364 fw->ewmh_hint_desktop = val[0];
365 free(val);
367 return 0;
370 int ewmh_MoveResize(EWMH_CMD_ARGS)
372 int dir = -1;
373 int x_warp = 0;
374 int y_warp = 0;
375 Bool move = False;
376 char cmd[256];
378 if (ev == NULL)
380 return 0;
383 dir = ev->xclient.data.l[2];
384 switch(dir)
386 case _NET_WM_MOVERESIZE_SIZE_TOPLEFT:
387 break;
388 case _NET_WM_MOVERESIZE_SIZE_TOP:
389 x_warp = 50;
390 break;
391 case _NET_WM_MOVERESIZE_SIZE_TOPRIGHT:
392 x_warp = 100;
393 break;
394 case _NET_WM_MOVERESIZE_SIZE_RIGHT:
395 x_warp = 100; y_warp = 50;
396 break;
397 case _NET_WM_MOVERESIZE_SIZE_KEYBOARD:
398 case _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT:
399 x_warp = 100; y_warp = 100;
400 break;
401 case _NET_WM_MOVERESIZE_SIZE_BOTTOM:
402 x_warp = 50; y_warp = 100;
403 break;
404 case _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT:
405 y_warp = 100;
406 break;
407 case _NET_WM_MOVERESIZE_SIZE_LEFT:
408 y_warp = 50;
409 break;
410 case _NET_WM_MOVERESIZE_MOVE_KEYBOARD:
411 case _NET_WM_MOVERESIZE_MOVE:
412 move = True;
413 break;
414 default:
415 return 0;
418 if (move)
420 if (
421 !is_function_allowed(
422 F_MOVE, NULL, fw, RQORIG_PROGRAM_US, False))
424 return 0;
427 else
429 if (
430 !is_function_allowed(
431 F_RESIZE, NULL, fw, RQORIG_PROGRAM_US, False))
433 return 0;
437 if (!move)
439 sprintf(cmd, "WarpToWindow %i %i",x_warp,y_warp);
440 execute_function_override_window(NULL, NULL, cmd, 0, fw);
443 if (move)
445 execute_function_override_window(
446 NULL, NULL, "Move", 0, fw);
448 else
450 execute_function_override_window(
451 NULL, NULL, "Resize", 0, fw);
454 return 0;
458 * WM_STATE*
460 int ewmh_WMState(EWMH_CMD_ARGS)
462 unsigned long maximize = 0;
464 if (ev != NULL)
466 ewmh_atom *a1,*a2;
468 a1 = ewmh_GetEwmhAtomByAtom(
469 ev->xclient.data.l[1], EWMH_ATOM_LIST_WM_STATE);
470 a2 = ewmh_GetEwmhAtomByAtom(
471 ev->xclient.data.l[2], EWMH_ATOM_LIST_WM_STATE);
473 if (a1 != NULL)
475 maximize |= a1->action(fw, ev, NULL, 0);
477 if (a2 != NULL)
479 maximize |= a2->action(fw, ev, NULL, 0);
482 else if (style != NULL)
484 CARD32 *val;
485 unsigned int nitems;
486 int size = 0;
487 int i;
488 ewmh_atom *list = ewmh_atom_wm_state;
489 int has_hint = 0;
491 val = ewmh_AtomGetByName(
492 FW_W(fw), "_NET_WM_STATE", EWMH_ATOM_LIST_CLIENT_WIN,
493 &size);
495 if (val == NULL)
497 size = 0;
500 #if DEBUG_EWMH_INIT_STATE
501 if (size != 0)
503 fprintf(
504 stderr, "Window 0x%lx has an init"
505 " _NET_WM_STATE hint\n",FW_W(fw));
507 #endif
508 nitems = size / sizeof(CARD32);
509 while(list->name != NULL)
511 has_hint = 0;
512 for(i = 0; i < nitems; i++)
514 if (list->atom == val[i])
516 has_hint = 1;
519 list->action(fw, NULL, style, has_hint);
520 list++;
522 if (val != NULL)
524 free(val);
526 return 0;
529 if (maximize != 0)
531 int max_vert = (maximize & EWMH_MAXIMIZE_VERT)? 100:0;
532 int max_horiz = (maximize & EWMH_MAXIMIZE_HORIZ)? 100:0;
533 char cmd[256];
535 if (maximize & EWMH_MAXIMIZE_REMOVE)
537 sprintf(cmd,"Maximize off");
539 else
541 if (!is_function_allowed(
542 F_MAXIMIZE, NULL, fw, RQORIG_PROGRAM_US,
543 False))
545 return 0;
547 sprintf(cmd,"Maximize on %i %i", max_horiz, max_vert);
549 execute_function_override_window(NULL, NULL, cmd, 0, fw);
551 return 0;
554 int ewmh_WMStateFullScreen(EWMH_CMD_ARGS)
556 if (ev == NULL && style == NULL)
558 return (IS_EWMH_FULLSCREEN(fw));
561 if (ev == NULL && style != NULL)
563 /* start full screen */
564 unsigned long has_hint = any;
566 #if DEBUG_EWMH_INIT_STATE
567 if (has_hint)
569 fprintf(stderr,"\tFullscreen\n");
571 #endif
572 if (DO_EWMH_IGNORE_STATE_HINTS(style))
574 SET_HAS_EWMH_INIT_FULLSCREEN_STATE(
575 fw, EWMH_STATE_UNDEFINED_HINT);
576 return 0;
578 if (HAS_EWMH_INIT_FULLSCREEN_STATE(fw) !=
579 EWMH_STATE_UNDEFINED_HINT)
581 return 0;
583 if (!has_hint)
585 SET_HAS_EWMH_INIT_FULLSCREEN_STATE(
586 fw, EWMH_STATE_NO_HINT);
587 return 0;
589 SET_EWMH_FULLSCREEN(fw,True);
590 SET_HAS_EWMH_INIT_FULLSCREEN_STATE(fw, EWMH_STATE_HAS_HINT);
591 return 0;
594 if (ev != NULL)
596 /* client message */
597 int bool_arg = ev->xclient.data.l[0];
598 int is_full_screen;
600 is_full_screen = IS_EWMH_FULLSCREEN(fw);
601 if ((bool_arg == NET_WM_STATE_TOGGLE && !is_full_screen) ||
602 bool_arg == NET_WM_STATE_ADD)
604 EWMH_fullscreen(fw);
606 else
608 if (HAS_EWMH_INIT_FULLSCREEN_STATE(fw) ==
609 EWMH_STATE_HAS_HINT)
611 /* the application started fullscreen */
612 SET_HAS_EWMH_INIT_FULLSCREEN_STATE(
613 fw, EWMH_STATE_NO_HINT);
615 /* unmaximize will restore is_ewmh_fullscreen,
616 * layer and apply_decor_change */
617 execute_function_override_window(
618 NULL, NULL, "Maximize off", 0, fw);
620 if ((IS_EWMH_FULLSCREEN(fw) &&
621 !DO_EWMH_USE_STACKING_HINTS(fw)) ||
622 (!IS_EWMH_FULLSCREEN(fw) &&
623 DO_EWMH_USE_STACKING_HINTS(fw)))
625 /* On: if not raised by a layer cmd raise
626 * Off: if lowered by a layer cmd raise */
627 execute_function_override_window(
628 NULL, NULL, "Raise", 0, fw);
632 return 0;
635 int ewmh_WMStateHidden(EWMH_CMD_ARGS)
637 if (ev == NULL && style == NULL)
639 unsigned long do_restore = any;
641 if (do_restore)
643 if (HAS_EWMH_INIT_HIDDEN_STATE(fw) ==
644 EWMH_STATE_HAS_HINT)
646 return True;
648 return False;
650 return IS_ICONIFIED(fw);
653 if (ev == NULL && style != NULL)
655 /* start iconified */
656 unsigned long has_hint = any;
658 #if DEBUG_EWMH_INIT_STATE
659 if (has_hint)
660 fprintf(stderr,"\tHidden\n");
661 #endif
662 if (DO_EWMH_IGNORE_STATE_HINTS(style))
664 SET_HAS_EWMH_INIT_HIDDEN_STATE(
665 fw, EWMH_STATE_UNDEFINED_HINT);
666 return 0;
668 if (HAS_EWMH_INIT_HIDDEN_STATE(fw) !=
669 EWMH_STATE_UNDEFINED_HINT)
671 return 0;
673 if (!has_hint)
675 SET_HAS_EWMH_INIT_HIDDEN_STATE(fw, EWMH_STATE_NO_HINT);
676 return 0;
678 style->flags.do_start_iconic = 1;
679 style->flag_mask.do_start_iconic = 1;
680 style->change_mask.do_start_iconic = 1;
681 SET_HAS_EWMH_INIT_HIDDEN_STATE(fw, EWMH_STATE_HAS_HINT);
682 return 0;
685 if (ev != NULL)
687 /* client message */
688 char cmd[16];
689 int bool_arg = ev->xclient.data.l[0];
691 if ((bool_arg == NET_WM_STATE_TOGGLE && !IS_ICONIFIED(fw)) ||
692 bool_arg == NET_WM_STATE_ADD)
694 /* iconify */
695 if (
696 !is_function_allowed(
697 F_ICONIFY, NULL, fw, RQORIG_PROGRAM_US,
698 False))
700 return 0;
702 sprintf(cmd, "Iconify on");
704 else
706 /* deiconify */
707 sprintf(cmd, "Iconify off");
709 execute_function_override_window(NULL, NULL, cmd, 0, fw);
711 return 0;
714 int ewmh_WMStateMaxHoriz(EWMH_CMD_ARGS)
717 if (ev == NULL && style == NULL)
719 #if 0
720 return (IS_MAXIMIZED(fw) && !IS_EWMH_FULLSCREEN(fw));
721 #else
722 /* DV: the notion of vertical/horizontal maximization does not
723 * make any sense in fvwm, so just claim we're never maximized
725 return 0;
726 #endif
729 if (ev == NULL && style != NULL)
731 unsigned long has_hint = any;
732 #if DEBUG_EWMH_INIT_STATE
733 if (has_hint)
735 fprintf(
736 stderr, "\t Maxhoriz %i\n",
737 HAS_EWMH_INIT_MAXHORIZ_STATE(fw));
739 #endif
740 if (DO_EWMH_IGNORE_STATE_HINTS(style))
742 SET_HAS_EWMH_INIT_MAXHORIZ_STATE(
743 fw, EWMH_STATE_UNDEFINED_HINT);
744 return 0;
747 /* If the initial state is STATE_NO_HINT we still want to
748 * override it, since having just one of MAXIMIZED_HORIZ or
749 * MAXIMIZED_HORZ is enough to make the window maximized.
751 if (HAS_EWMH_INIT_MAXHORIZ_STATE(fw) ==
752 EWMH_STATE_HAS_HINT)
754 return 0;
756 if (!has_hint)
758 SET_HAS_EWMH_INIT_MAXHORIZ_STATE(
759 fw, EWMH_STATE_NO_HINT);
760 return 0;
762 SET_HAS_EWMH_INIT_MAXHORIZ_STATE(fw, EWMH_STATE_HAS_HINT);
763 return 0;
766 if (ev != NULL)
768 /* client message */
769 int cmd_arg = ev->xclient.data.l[0];
770 if (
771 !IS_MAXIMIZED(fw) &&
772 (cmd_arg == NET_WM_STATE_TOGGLE ||
773 cmd_arg == NET_WM_STATE_ADD))
775 return EWMH_MAXIMIZE_HORIZ;
777 else if (
778 IS_MAXIMIZED(fw) &&
779 (cmd_arg == NET_WM_STATE_TOGGLE ||
780 cmd_arg == NET_WM_STATE_REMOVE))
782 return EWMH_MAXIMIZE_REMOVE;
786 return 0;
789 int ewmh_WMStateMaxVert(EWMH_CMD_ARGS)
792 if (ev == NULL && style == NULL)
794 #if 0
795 return (IS_MAXIMIZED(fw) && !IS_EWMH_FULLSCREEN(fw));
796 #else
797 /* DV: the notion of vertical/horizontal maximization does not
798 * make any sense in fvwm, so just claim we're never maximized
800 return 0;
801 #endif
804 if (ev == NULL && style != NULL)
806 unsigned long has_hint = any;
807 #if DEBUG_EWMH_INIT_STATE
808 if (has_hint)
810 fprintf(
811 stderr, "\t Maxvert %i\n",
812 HAS_EWMH_INIT_MAXVERT_STATE(fw));
814 #endif
815 if (DO_EWMH_IGNORE_STATE_HINTS(style))
817 SET_HAS_EWMH_INIT_MAXVERT_STATE(
818 fw, EWMH_STATE_UNDEFINED_HINT);
819 return 0;
821 if (HAS_EWMH_INIT_MAXVERT_STATE(fw) !=
822 EWMH_STATE_UNDEFINED_HINT)
824 return 0;
826 if (!has_hint)
828 SET_HAS_EWMH_INIT_MAXVERT_STATE(
829 fw, EWMH_STATE_NO_HINT);
830 return 0;
832 SET_HAS_EWMH_INIT_MAXVERT_STATE(fw, EWMH_STATE_HAS_HINT);
833 return 0;
836 if (ev != NULL)
838 /* client message */
839 int cmd_arg = ev->xclient.data.l[0];
840 if (
841 !IS_MAXIMIZED(fw) &&
842 (cmd_arg == NET_WM_STATE_TOGGLE ||
843 cmd_arg == NET_WM_STATE_ADD))
845 return EWMH_MAXIMIZE_VERT;
847 else if (
848 IS_MAXIMIZED(fw) &&
849 (cmd_arg == NET_WM_STATE_TOGGLE ||
850 cmd_arg == NET_WM_STATE_REMOVE))
852 return EWMH_MAXIMIZE_REMOVE;
856 return 0;
859 int ewmh_WMStateModal(EWMH_CMD_ARGS)
861 if (ev == NULL && style == NULL)
863 unsigned long do_restore = any;
865 if (do_restore)
867 if (HAS_EWMH_INIT_MODAL_STATE(fw) ==
868 EWMH_STATE_HAS_HINT)
870 return True;
872 return False;
874 return IS_EWMH_MODAL(fw);
877 if (ev == NULL && style != NULL)
879 unsigned long has_hint = any;
880 #if DEBUG_EWMH_INIT_STATE
881 if (has_hint)
883 fprintf(
884 stderr, "\t Modal %i\n",
885 HAS_EWMH_INIT_MODAL_STATE(fw));
887 #endif
888 if (DO_EWMH_IGNORE_STATE_HINTS(style))
890 SET_HAS_EWMH_INIT_MODAL_STATE(
891 fw, EWMH_STATE_UNDEFINED_HINT);
892 return 0;
894 if (HAS_EWMH_INIT_MODAL_STATE(fw) != EWMH_STATE_UNDEFINED_HINT)
896 return 0;
898 if (!has_hint)
900 SET_HAS_EWMH_INIT_MODAL_STATE(fw, EWMH_STATE_NO_HINT);
901 return 0;
904 /* the window map or had mapped with a modal hint */
905 if (IS_TRANSIENT(fw))
907 SET_EWMH_MODAL(fw, True);
908 /* the window is a modal transient window so we grab
909 * the focus it will be good to raise it but ... */
910 FPS_GRAB_FOCUS_TRANSIENT(
911 S_FOCUS_POLICY(SCF(*style)), 1);
912 FPS_GRAB_FOCUS_TRANSIENT(
913 S_FOCUS_POLICY(SCM(*style)), 1);
914 FPS_GRAB_FOCUS_TRANSIENT(
915 S_FOCUS_POLICY(SCC(*style)), 1);
916 SET_HAS_EWMH_INIT_MODAL_STATE(
917 fw, EWMH_STATE_HAS_HINT);
919 else
921 SET_EWMH_MODAL(fw, False);
922 if (!FP_DO_GRAB_FOCUS_TRANSIENT(
923 S_FOCUS_POLICY(SCF(*style))))
925 FPS_GRAB_FOCUS_TRANSIENT(
926 S_FOCUS_POLICY(SCF(*style)), 0);
927 FPS_GRAB_FOCUS_TRANSIENT(
928 S_FOCUS_POLICY(SCM(*style)), 1);
929 FPS_GRAB_FOCUS_TRANSIENT(
930 S_FOCUS_POLICY(SCC(*style)), 1);
933 return 0;
936 if (ev != NULL && fw != NULL)
938 /* client message: I do not think we can get such message */
939 /* java sends this message */
940 int cmd_arg = ev->xclient.data.l[0];
941 if (
942 !IS_EWMH_MODAL(fw) &&
943 (cmd_arg == NET_WM_STATE_TOGGLE ||
944 cmd_arg == NET_WM_STATE_ADD))
946 /* ON */
948 else if (
949 IS_EWMH_MODAL(fw) &&
950 (cmd_arg == NET_WM_STATE_TOGGLE ||
951 cmd_arg == NET_WM_STATE_REMOVE))
953 /* OFF */
955 /* !MODAL MODAL
956 * CMD
957 * STATE_ADD ON do nothing
958 * STATE_TOGGLE ON OFF
959 * STATE_REMOVE do nothing OFF
962 return 0;
965 int ewmh_WMStateShaded(EWMH_CMD_ARGS)
968 if (ev == NULL && style == NULL)
970 unsigned long do_restore = any;
972 if (do_restore)
974 if (HAS_EWMH_INIT_SHADED_STATE(fw) ==
975 EWMH_STATE_HAS_HINT)
977 return True;
979 return False;
981 return IS_SHADED(fw);
984 if (ev == NULL && style != NULL)
986 /* start shaded */
987 unsigned long has_hint = any;
988 #if DEBUG_EWMH_INIT_STATE
989 if (has_hint)
991 fprintf(
992 stderr, "\t Shaded %i\n",
993 HAS_EWMH_INIT_SHADED_STATE(fw));
995 #endif
996 if (DO_EWMH_IGNORE_STATE_HINTS(style))
998 SET_HAS_EWMH_INIT_SHADED_STATE(
999 fw, EWMH_STATE_UNDEFINED_HINT);
1000 return 0;
1002 if (HAS_EWMH_INIT_SHADED_STATE(fw) !=
1003 EWMH_STATE_UNDEFINED_HINT)
1005 return 0;
1007 if (!has_hint)
1009 SET_HAS_EWMH_INIT_SHADED_STATE(
1010 fw, EWMH_STATE_NO_HINT);
1011 return 0;
1014 SET_SHADED(fw, 1);
1015 SET_SHADED_DIR(fw, GET_TITLE_DIR(fw));
1016 SET_HAS_EWMH_INIT_SHADED_STATE(fw, EWMH_STATE_HAS_HINT);
1017 return 0;
1020 if (ev != NULL)
1022 /* client message */
1023 int cmd_arg = ev->xclient.data.l[0];
1024 if (
1025 !IS_SHADED(fw) &&
1026 (cmd_arg == NET_WM_STATE_TOGGLE ||
1027 cmd_arg == NET_WM_STATE_ADD))
1029 execute_function_override_window(
1030 NULL, NULL, "Windowshade on", 0, fw);
1032 else if (
1033 IS_SHADED(fw) &&
1034 (cmd_arg == NET_WM_STATE_TOGGLE ||
1035 cmd_arg == NET_WM_STATE_REMOVE))
1037 execute_function_override_window(
1038 NULL, NULL, "Windowshade off", 0, fw);
1041 return 0;
1044 int ewmh_WMStateSkipPager(EWMH_CMD_ARGS)
1046 if (ev == NULL && style == NULL)
1048 unsigned long do_restore = any;
1050 if (do_restore)
1052 if (HAS_EWMH_INIT_SKIP_PAGER_STATE(fw) ==
1053 EWMH_STATE_HAS_HINT)
1055 return True;
1057 return False;
1059 return DO_SKIP_WINDOW_LIST(fw);
1062 if (ev == NULL && style != NULL)
1064 unsigned long has_hint = any;
1065 #if DEBUG_EWMH_INIT_STATE
1066 /*if (has_hint)*/
1067 fprintf(
1068 stderr, "\t Skip_Pager %lu, %i, %i\n", has_hint,
1069 HAS_EWMH_INIT_SKIP_PAGER_STATE(fw),
1070 DO_EWMH_IGNORE_STATE_HINTS(style));
1071 #endif
1072 if (DO_EWMH_IGNORE_STATE_HINTS(style))
1074 SET_HAS_EWMH_INIT_SKIP_PAGER_STATE(
1075 fw, EWMH_STATE_UNDEFINED_HINT);
1076 return 0;
1078 if (HAS_EWMH_INIT_SKIP_PAGER_STATE(fw) !=
1079 EWMH_STATE_UNDEFINED_HINT)
1081 return 0;
1083 if (!has_hint)
1085 SET_HAS_EWMH_INIT_SKIP_PAGER_STATE(
1086 fw, EWMH_STATE_NO_HINT);
1087 return 0;
1090 S_SET_DO_WINDOW_LIST_SKIP(SCF(*style), 1);
1091 S_SET_DO_WINDOW_LIST_SKIP(SCM(*style), 1);
1092 S_SET_DO_WINDOW_LIST_SKIP(SCC(*style), 1);
1093 SET_HAS_EWMH_INIT_SKIP_PAGER_STATE(fw, EWMH_STATE_HAS_HINT);
1094 return 0;
1097 if (ev != NULL)
1099 /* I do not think we can get such client message */
1100 int bool_arg = ev->xclient.data.l[0];
1102 if ((bool_arg == NET_WM_STATE_TOGGLE &&
1103 !DO_SKIP_WINDOW_LIST(fw)) ||
1104 bool_arg == NET_WM_STATE_ADD)
1107 else
1111 return 0;
1114 int ewmh_WMStateSkipTaskBar(EWMH_CMD_ARGS)
1116 if (ev == NULL && style == NULL)
1118 unsigned long do_restore = any;
1120 if (do_restore)
1122 if (HAS_EWMH_INIT_SKIP_TASKBAR_STATE(fw) ==
1123 EWMH_STATE_HAS_HINT)
1125 return True;
1127 return False;
1129 return DO_SKIP_WINDOW_LIST(fw);
1132 if (ev == NULL && style != NULL)
1134 unsigned long has_hint = any;
1135 #if DEBUG_EWMH_INIT_STATE
1136 /*if (has_hint)*/
1137 fprintf(stderr,"\t Skip_Taskbar %lu, %i, %i\n",
1138 has_hint,
1139 HAS_EWMH_INIT_SKIP_TASKBAR_STATE(fw),
1140 DO_EWMH_IGNORE_STATE_HINTS(style));
1141 #endif
1142 if (DO_EWMH_IGNORE_STATE_HINTS(style))
1144 SET_HAS_EWMH_INIT_SKIP_TASKBAR_STATE(
1145 fw, EWMH_STATE_UNDEFINED_HINT);
1146 return 0;
1148 if (HAS_EWMH_INIT_SKIP_TASKBAR_STATE(fw) !=
1149 EWMH_STATE_UNDEFINED_HINT)
1151 return 0;
1153 if (!has_hint)
1155 SET_HAS_EWMH_INIT_SKIP_TASKBAR_STATE(
1156 fw, EWMH_STATE_NO_HINT);
1157 return 0;
1160 S_SET_DO_WINDOW_LIST_SKIP(SCF(*style), 1);
1161 S_SET_DO_WINDOW_LIST_SKIP(SCM(*style), 1);
1162 S_SET_DO_WINDOW_LIST_SKIP(SCC(*style), 1);
1163 SET_HAS_EWMH_INIT_SKIP_TASKBAR_STATE(
1164 fw, EWMH_STATE_HAS_HINT);
1165 return 0;
1168 if (ev != NULL)
1170 /* I do not think we can get such client message */
1171 int bool_arg = ev->xclient.data.l[0];
1173 if ((bool_arg == NET_WM_STATE_TOGGLE &&
1174 !DO_SKIP_WINDOW_LIST(fw)) ||
1175 bool_arg == NET_WM_STATE_ADD)
1178 else
1182 return 0;
1185 int ewmh_WMStateStaysOnTop(EWMH_CMD_ARGS)
1187 if (ev == NULL && style == NULL)
1189 unsigned long do_restore = any;
1191 if (do_restore)
1193 if (fw->ewmh_hint_layer == Scr.TopLayer)
1195 return True;
1197 return False;
1199 if (fw->layer >= Scr.TopLayer)
1201 return True;
1203 return False;
1206 if (ev == NULL && style != NULL)
1208 unsigned long has_hint = any;
1209 #if DEBUG_EWMH_INIT_STATE
1210 if (has_hint)
1212 fprintf(stderr,"\tStaysOnTop\n");
1214 #endif
1215 if (!DO_EWMH_USE_STACKING_HINTS(style))
1217 return 0;
1219 if (!has_hint && fw->ewmh_hint_layer == 0)
1221 fw->ewmh_hint_layer = -1;
1222 return 0;
1224 if (fw->ewmh_hint_layer == -1)
1226 return 0;
1229 fw->ewmh_hint_layer = Scr.TopLayer;
1230 SSET_LAYER(*style, Scr.TopLayer);
1231 style->flags.use_layer = 1;
1232 style->flag_mask.use_layer = 1;
1233 style->change_mask.use_layer = 1;
1234 return 0;
1237 if (ev != NULL)
1239 /* client message */
1240 int cmd_arg = ev->xclient.data.l[0];
1242 if (!DO_EWMH_USE_STACKING_HINTS(fw))
1244 /* if we don't pay attention to the hints,
1245 * I don't think we should honor this request also
1247 return 0;
1249 if (fw->layer < Scr.TopLayer &&
1250 (cmd_arg == NET_WM_STATE_TOGGLE ||
1251 cmd_arg == NET_WM_STATE_ADD))
1253 new_layer(fw, Scr.TopLayer);
1255 else if (
1256 fw->layer == Scr.TopLayer &&
1257 (cmd_arg == NET_WM_STATE_TOGGLE ||
1258 cmd_arg == NET_WM_STATE_REMOVE))
1260 new_layer(fw, Scr.DefaultLayer);
1262 /* layer < TopLayer layer == TopLayer
1263 * CMD
1264 * STATE_ADD new_layer(TOP) do nothing
1265 * STATE_TOGGLE new_layer(TOP) new_layer(DEFAULT)
1266 * STATE_REMOVE do nothing new_layer(DEFAULT)
1269 return 0;
1272 int ewmh_WMStateStaysOnBottom(EWMH_CMD_ARGS)
1274 if (ev == NULL && style == NULL)
1276 unsigned long do_restore = any;
1278 if (do_restore)
1280 if (fw->ewmh_hint_layer == Scr.BottomLayer)
1282 return True;
1284 return False;
1286 if (fw->layer <= Scr.BottomLayer)
1288 return True;
1290 return False;
1293 if (ev == NULL && style != NULL)
1295 unsigned long has_hint = any;
1296 #if DEBUG_EWMH_INIT_STATE
1297 if (has_hint)
1298 fprintf(stderr,"\tStaysOnBottom\n");
1299 #endif
1300 if (!DO_EWMH_USE_STACKING_HINTS(style))
1302 return 0;
1304 if (!has_hint && fw->ewmh_hint_layer == 0)
1306 fw->ewmh_hint_layer = -1;
1307 return 0;
1309 if (fw->ewmh_hint_layer == -1)
1311 return 0;
1314 fw->ewmh_hint_layer = Scr.BottomLayer;
1315 SSET_LAYER(*style, Scr.BottomLayer);
1316 style->flags.use_layer = 1;
1317 style->flag_mask.use_layer = 1;
1318 style->change_mask.use_layer = 1;
1319 return 0;
1322 if (ev != NULL)
1324 /* client message */
1325 int cmd_arg = ev->xclient.data.l[0];
1327 if (!DO_EWMH_USE_STACKING_HINTS(fw))
1329 /* if we don't pay attention to the hints,
1330 * I don't think we should honor this request also
1332 return 0;
1334 if (
1335 fw->layer > Scr.BottomLayer &&
1336 (cmd_arg == NET_WM_STATE_TOGGLE ||
1337 cmd_arg == NET_WM_STATE_ADD))
1339 new_layer(fw, Scr.BottomLayer);
1341 else if (
1342 fw->layer == Scr.BottomLayer &&
1343 (cmd_arg == NET_WM_STATE_TOGGLE ||
1344 cmd_arg == NET_WM_STATE_REMOVE))
1346 new_layer(fw, Scr.DefaultLayer);
1348 /* layer > BottomLayer layer == BottomLayer
1349 * CMD
1350 * STATE_ADD new_layer(BOTTOM) do nothing
1351 * STATE_TOGGLE new_layer(BOTTOM) new_layer(DEFAULT)
1352 * STATE_REMOVE do nothing new_layer(DEFAULT)
1355 return 0;
1358 int ewmh_WMStateSticky(EWMH_CMD_ARGS)
1361 if (ev == NULL && style == NULL)
1363 unsigned long do_restore = any;
1365 if (do_restore)
1367 if (HAS_EWMH_INIT_STICKY_STATE(fw) ==
1368 EWMH_STATE_HAS_HINT)
1370 return True;
1372 return False;
1374 return (IS_STICKY_ACROSS_PAGES(fw) &&
1375 IS_STICKY_ACROSS_DESKS(fw));
1378 if (ev == NULL && style != NULL)
1380 /* start sticky */
1381 unsigned long has_hint = any;
1382 #if DEBUG_EWMH_INIT_STATE
1383 if (has_hint)
1385 fprintf(stderr,"\t Sticky\n");
1387 #endif
1388 if (DO_EWMH_IGNORE_STATE_HINTS(style))
1390 SET_HAS_EWMH_INIT_STICKY_STATE(
1391 fw, EWMH_STATE_UNDEFINED_HINT);
1392 return 0;
1394 if (HAS_EWMH_INIT_STICKY_STATE(fw) !=
1395 EWMH_STATE_UNDEFINED_HINT)
1397 return 0;
1399 if (!has_hint)
1401 SET_HAS_EWMH_INIT_STICKY_STATE(
1402 fw, EWMH_STATE_NO_HINT);
1403 return 0;
1405 S_SET_IS_STICKY_ACROSS_PAGES(SCF(*style), 1);
1406 S_SET_IS_STICKY_ACROSS_PAGES(SCM(*style), 1);
1407 S_SET_IS_STICKY_ACROSS_PAGES(SCC(*style), 1);
1408 S_SET_IS_STICKY_ACROSS_DESKS(SCF(*style), 1);
1409 S_SET_IS_STICKY_ACROSS_DESKS(SCM(*style), 1);
1410 S_SET_IS_STICKY_ACROSS_DESKS(SCC(*style), 1);
1411 SET_HAS_EWMH_INIT_STICKY_STATE(fw, EWMH_STATE_HAS_HINT);
1412 return 0;
1415 if (ev != NULL)
1417 /* client message */
1418 int bool_arg = ev->xclient.data.l[0];
1419 if ((bool_arg == NET_WM_STATE_TOGGLE &&
1420 (!IS_STICKY_ACROSS_PAGES(fw) ||
1421 !IS_STICKY_ACROSS_DESKS(fw))) ||
1422 bool_arg == NET_WM_STATE_ADD)
1424 execute_function_override_window(
1425 NULL, NULL, "Stick on", 0, fw);
1427 else
1429 execute_function_override_window(
1430 NULL, NULL, "Stick on", 1, fw);
1433 return 0;
1437 * Property Notify (_NET_WM_ICON is in ewmh_icon.c, _NET_WM_*NAME are in
1438 * ewmh_name) *
1440 int ewmh_WMIconGeometry(EWMH_CMD_ARGS)
1442 int size;
1443 CARD32 *val;
1445 /* FIXME: After a (un)slide of kicker the geometry are wrong (not
1446 * because we set the geometry just after the property notify). This
1447 * does not happen with kwin */
1448 val = ewmh_AtomGetByName(
1449 FW_W(fw), "_NET_WM_ICON_GEOMETRY",
1450 EWMH_ATOM_LIST_PROPERTY_NOTIFY, &size);
1452 if (val != NULL && size < 4 * sizeof(CARD32))
1454 fvwm_msg(
1455 WARN, "ewmh_WMIconGeometry",
1456 "The application window (id %#lx)\n"
1457 " \"%s\" tried to set to an icon geometry via EWMH\n"
1458 " but provided only %d of the 4 values required.\n"
1459 " fvwm is ignoring this request.\n",
1460 fw ? FW_W(fw) : 0, fw ? fw->name.name : "(none)",
1461 (int)(size / sizeof(CARD32)));
1462 fvwm_msg_report_app_and_workers();
1463 free(val);
1464 val = NULL;
1466 if (val == NULL)
1468 fw->ewmh_icon_geometry.x = 0;
1469 fw->ewmh_icon_geometry.y = 0;
1470 fw->ewmh_icon_geometry.width = 0;
1471 fw->ewmh_icon_geometry.height = 0;
1473 return 0;
1475 fw->ewmh_icon_geometry.x = val[0];
1476 fw->ewmh_icon_geometry.y = val[1];
1477 fw->ewmh_icon_geometry.width = val[2];
1478 fw->ewmh_icon_geometry.height = val[3];
1479 free(val);
1481 return 0;
1484 /**** for animation ****/
1485 void EWMH_GetIconGeometry(FvwmWindow *fw, rectangle *icon_rect)
1487 if (!IS_ICON_SUPPRESSED(fw) ||
1488 (fw->ewmh_icon_geometry.x == 0 &&
1489 fw->ewmh_icon_geometry.y == 0 &&
1490 fw->ewmh_icon_geometry.width == 0 &&
1491 fw->ewmh_icon_geometry.height == 0))
1493 return;
1495 icon_rect->x = fw->ewmh_icon_geometry.x;
1496 icon_rect->y = fw->ewmh_icon_geometry.y;
1497 icon_rect->width = fw->ewmh_icon_geometry.width;
1498 icon_rect->height = fw->ewmh_icon_geometry.height;
1500 return;
1503 int ewmh_WMStrut(EWMH_CMD_ARGS)
1505 int size = 0;
1506 CARD32 *val;
1508 if (ev == NULL)
1510 fw->dyn_strut.left = fw->strut.left = 0;
1511 fw->dyn_strut.right = fw->strut.right = 0;
1512 fw->dyn_strut.top = fw->strut.top = 0;
1513 fw->dyn_strut.bottom = fw->strut.bottom = 0;
1516 val = ewmh_AtomGetByName(
1517 FW_W(fw), "_NET_WM_STRUT",
1518 EWMH_ATOM_LIST_PROPERTY_NOTIFY, &size);
1520 if (val == NULL)
1522 return 0;
1525 if ((val[0] > 0 || val[1] > 0 || val[2] > 0 || val[3] > 0)
1527 (val[0] != fw->strut.left || val[1] != fw->strut.right ||
1528 val[2] != fw->strut.top || val[3] != fw->strut.bottom))
1530 fw->strut.left = val[0];
1531 fw->strut.right = val[1];
1532 fw->strut.top = val[2];
1533 fw->strut.bottom = val[3];
1534 ewmh_ComputeAndSetWorkArea();
1536 if (val[0] != fw->dyn_strut.left ||
1537 val[1] != fw->dyn_strut.right ||
1538 val[2] != fw->dyn_strut.top ||
1539 val[3] != fw->dyn_strut.bottom)
1541 fw->dyn_strut.left = val[0];
1542 fw->dyn_strut.right = val[1];
1543 fw->dyn_strut.top = val[2];
1544 fw->dyn_strut.bottom = val[3];
1545 ewmh_HandleDynamicWorkArea();
1547 free(val);
1549 return 0;
1552 Bool EWMH_ProcessClientMessage(const exec_context_t *exc)
1554 ewmh_atom *ewmh_a = NULL;
1555 FvwmWindow *fw = exc->w.fw;
1556 XEvent *ev = exc->x.elast;
1558 if ((ewmh_a = (ewmh_atom *)ewmh_GetEwmhAtomByAtom(
1559 ev->xclient.message_type, EWMH_ATOM_LIST_CLIENT_ROOT)) !=
1560 NULL)
1562 if (ewmh_a->action != None)
1564 ewmh_a->action(fw, ev, NULL, 0);
1566 return True;
1569 if ((ewmh_a = (ewmh_atom *)ewmh_GetEwmhAtomByAtom(
1570 ev->xclient.message_type, EWMH_ATOM_LIST_CLIENT_WIN))
1571 == NULL)
1573 return False;
1576 if (ev->xclient.window == None)
1578 return False;
1581 /* these one are special: we can get it on an unamaged window */
1582 if (StrEquals(ewmh_a->name, "_NET_MOVERESIZE_WINDOW") ||
1583 StrEquals(ewmh_a->name, "_NET_RESTACK_WINDOW"))
1585 ewmh_a->action(fw, ev, NULL, 0);
1586 return True;
1589 if (fw == NULL)
1591 return False;
1595 if ((ewmh_a = (ewmh_atom *)ewmh_GetEwmhAtomByAtom(
1596 ev->xclient.message_type, EWMH_ATOM_LIST_CLIENT_WIN)) !=
1597 NULL)
1599 if (ewmh_a->action != None)
1601 ewmh_a->action(fw, ev, NULL, 0);
1603 return True;
1606 return False;
1609 void EWMH_ProcessPropertyNotify(const exec_context_t *exc)
1611 ewmh_atom *ewmh_a = NULL;
1612 FvwmWindow *fw = exc->w.fw;
1613 XEvent *ev = exc->x.elast;
1615 if ((ewmh_a = (ewmh_atom *)ewmh_GetEwmhAtomByAtom(
1616 ev->xproperty.atom, EWMH_ATOM_LIST_PROPERTY_NOTIFY)) !=
1617 NULL)
1619 if (ewmh_a->action != None)
1621 flush_property_notify(ewmh_a->atom, FW_W(fw));
1622 ewmh_a->action(fw, ev, NULL, 0);