1 /* kwm.c-- stuff for support for kwm hints
3 * Window Maker window manager
5 * Copyright (c) 1998, 1999 Alfredo K. Kojima
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
27 * kwm.h function/method Notes
28 *----------------------------------------------------------------------------
29 * setUnsavedDataHint() currently, only gives visual clue that
30 * there is unsaved data (broken X close button)
32 * setIcon() std X thing...
36 * setWmCommand() std X thing
40 * isKWMInitialized() not trustworthy
41 * activeWindow() dunno it's use, but since it's easy to
42 * implement it won't hurt to support
44 * (set/get)WindowRegion()
45 * (set)numberOfDesktops() KDE limits to 32, but wmaker is virtually
46 * unlimited. May raise some incompatibility
47 * in badly written KDE modules?
48 * (set/get)DesktopName()
49 * sendKWMCommand() also does the message relay thing
55 * moveToDesktop() WARNING: evil mechanism
56 * setGeometryRestore() WARNING: evil mechanism
57 * setMaximize() woo hoo! wanna race?
58 * setIconify() BAH!: why reinvent the f'ing wheel!?
61 * setGeometry() std X thing
67 * prepareForSwallowing() std X thing
68 * doNotManage() klugy thing...
69 * getBlablablaString()
70 * setKWMDockModule() maybe we can make the Dock behave as the KDE
71 * dock, but must figure where to show the windows
74 * Unsupported stuff (superfluous/not-essential/nonsense):
75 * =======================================================
81 * registerSoundEvent()
82 * unregisterSoundEvent()
85 * geometry() kde lib code makes it unnecessary
91 * These are clientmessage-type messages specific to Window Maker:
92 * wmaker:info - show info panel
93 * wmaker:legal - show legal panel
94 * wmaker:arrangeIcons - arrange icons
95 * wmaker:showAll - show all windows
96 * wmaker:hideOthers - hide others
97 * wmaker:restart - restart wmaker
98 * wmaker:exit - exit wmaker
103 * different WORKAREA for each workspace
111 #include <X11/Xlib.h>
112 #include <X11/Xutil.h>
113 #include <X11/Xatom.h>
120 #include "WindowMaker.h"
124 #include "framewin.h"
126 #include "properties.h"
131 #include "workspace.h"
138 /******* Global ******/
140 extern Time LastFocusChange
;
141 extern Time LastTimestamp
;
144 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
;
145 extern Atom _XA_WM_DELETE_WINDOW
;
149 static Atom _XA_KWM_COMMAND
= 0;
150 static Atom _XA_KWM_ACTIVATE_WINDOW
= 0;
151 static Atom _XA_KWM_ACTIVE_WINDOW
= 0;
152 static Atom _XA_KWM_DO_NOT_MANAGE
= 0;
153 static Atom _XA_KWM_DOCKWINDOW
= 0;
154 static Atom _XA_KWM_RUNNING
= 0;
156 static Atom _XA_KWM_MODULE
= 0;
158 static Atom _XA_KWM_MODULE_INIT
= 0;
159 static Atom _XA_KWM_MODULE_INITIALIZED
= 0;
160 static Atom _XA_KWM_MODULE_DESKTOP_CHANGE
= 0;
161 static Atom _XA_KWM_MODULE_DESKTOP_NAME_CHANGE
= 0;
162 static Atom _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE
= 0;
163 static Atom _XA_KWM_MODULE_WIN_ADD
= 0;
164 static Atom _XA_KWM_MODULE_WIN_REMOVE
= 0;
165 static Atom _XA_KWM_MODULE_WIN_CHANGE
= 0;
166 static Atom _XA_KWM_MODULE_WIN_RAISE
= 0;
167 static Atom _XA_KWM_MODULE_WIN_LOWER
= 0;
168 static Atom _XA_KWM_MODULE_WIN_ACTIVATE
= 0;
169 static Atom _XA_KWM_MODULE_WIN_ICON_CHANGE
= 0;
170 static Atom _XA_KWM_MODULE_DOCKWIN_ADD
= 0;
171 static Atom _XA_KWM_MODULE_DOCKWIN_REMOVE
= 0;
173 static Atom _XA_KWM_WIN_UNSAVED_DATA
= 0;
174 static Atom _XA_KWM_WIN_DECORATION
= 0;
175 static Atom _XA_KWM_WIN_DESKTOP
= 0;
176 static Atom _XA_KWM_WIN_GEOMETRY_RESTORE
= 0;
177 static Atom _XA_KWM_WIN_ICONIFIED
= 0;
178 static Atom _XA_KWM_WIN_MAXIMIZED
= 0;
179 static Atom _XA_KWM_WIN_STICKY
= 0;
181 static Atom _XA_KWM_WIN_ICON_GEOMETRY
= 0;
183 static Atom _XA_KWM_CURRENT_DESKTOP
= 0;
184 static Atom _XA_KWM_NUMBER_OF_DESKTOPS
= 0;
185 static Atom _XA_KWM_DESKTOP_NAME_
[MAX_WORKSPACES
];
186 static Atom _XA_KWM_WINDOW_REGION_
[MAX_WORKSPACES
];
190 /* list of window titles that must not be managed */
191 typedef struct KWMDoNotManageList
{
193 struct KWMDoNotManageList
*next
;
194 } KWMDoNotManageList
;
196 static KWMDoNotManageList
*KWMDoNotManageCrap
= NULL
;
199 /* list of KWM modules */
200 typedef struct KWMModuleList
{
202 struct KWMModuleList
*next
;
208 static KWMModuleList
*KWMModules
= NULL
;
210 static KWMModuleList
*KWMDockWindows
= NULL
;
212 /* window decoration types */
215 KWMnormalDecoration
= 1,
216 KWMtinyDecoration
= 2,
223 getSimpleHint(Window win
, Atom atom
, long *retval
)
229 data
= (long*)PropGetCheckProperty(win
, atom
, atom
, 32, 1, NULL
);
244 setSimpleHint(Window win
, Atom atom
, long value
)
247 XChangeProperty(dpy
, win
, atom
, atom
,
248 32, PropModeReplace
, (unsigned char*)&value
, 1);
253 sendClientMessage(WScreen
*scr
, Window window
, Atom atom
, long value
)
260 memset(&event
, 0, sizeof(XEvent
));
261 event
.xclient
.type
= ClientMessage
;
262 event
.xclient
.message_type
= atom
;
263 event
.xclient
.window
= window
;
264 event
.xclient
.format
= 32;
265 event
.xclient
.data
.l
[0] = value
;
266 event
.xclient
.data
.l
[1] = LastTimestamp
;
268 if (scr
&& scr
->root_win
== window
)
269 mask
= SubstructureRedirectMask
;
271 XSendEvent(dpy
, window
, False
, mask
, &event
);
276 sendTextMessage(WScreen
*scr
, Window window
, Atom atom
, char *text
)
284 memset(&event
, 0, sizeof(XEvent
));
285 event
.xclient
.type
= ClientMessage
;
286 event
.xclient
.message_type
= atom
;
287 event
.xclient
.window
= window
;
288 event
.xclient
.format
= 8;
290 for (i
=0; i
<20 && text
[i
]; i
++)
291 event
.xclient
.data
.b
[i
] = text
[i
];
293 if (scr
&& scr
->root_win
== window
)
294 mask
= SubstructureRedirectMask
;
296 XSendEvent(dpy
, window
, False
, mask
, &event
);
301 getAreaHint(Window win
, Atom atom
, WArea
*area
)
305 data
= (long*)PropGetCheckProperty(win
, atom
, atom
, 32, 4, NULL
);
312 area
->x2
= data
[2] + area
->x1
;
313 area
->y2
= data
[3] + area
->y1
;
322 setAreaHint(Window win
, Atom atom
, WArea area
)
329 value
[2] = area
.x2
- area
.x1
;
330 value
[3] = area
.y2
- area
.y1
;
331 XChangeProperty(dpy
, win
, atom
, atom
, 32, PropModeReplace
,
332 (unsigned char*)&value
, 4);
337 addModule(WScreen
*scr
, Window window
)
343 node
= malloc(sizeof(KWMModuleList
));
345 wwarning("out of memory while registering KDE module");
349 node
->next
= KWMModules
;
350 node
->window
= window
;
353 sendClientMessage(scr
, window
, _XA_KWM_MODULE_INIT
, 0);
355 if (getSimpleHint(window
, _XA_KWM_MODULE
, &val
) && val
==2) {
356 if (scr
->kwm_dock
!= None
) {
357 setSimpleHint(window
, _XA_KWM_MODULE
, 1);
361 scr
->kwm_dock
= window
;
363 for (ptr
= KWMDockWindows
; ptr
!=NULL
; ptr
= ptr
->next
) {
364 sendClientMessage(scr
, scr
->kwm_dock
, _XA_KWM_MODULE_DOCKWIN_ADD
,
370 /* send list of windows */
371 for (ptr
= scr
->focused_window
; ptr
!=NULL
; ptr
= ptr
->prev
) {
372 if (!ptr
->flags
.kwm_hidden_for_modules
373 && !WFLAGP(ptr
, skip_window_list
)) {
374 sendClientMessage(scr
, window
, _XA_KWM_MODULE_WIN_ADD
,
379 /* send window stacking order */
380 wKWMSendStacking(scr
, window
);
382 /* send focused window */
383 if (scr
->focused_window
&& scr
->focused_window
->flags
.focused
) {
384 sendClientMessage(scr
, window
, _XA_KWM_MODULE_WIN_ACTIVATE
,
385 scr
->focused_window
->client_win
);
388 /* tell who we are */
389 sendTextMessage(scr
, window
, _XA_KWM_COMMAND
, "wm:wmaker");
392 sendClientMessage(scr
, window
, _XA_KWM_MODULE_INITIALIZED
, 0);
394 KWMModules
->title
= NULL
;
395 XFetchName(dpy
, window
, &KWMModules
->title
);
396 printf("NEW MODULE %s\n", KWMModules
->title
);
402 removeModule(WScreen
*scr
, Window window
)
410 if (KWMModules
->window
== window
) {
411 next
= KWMModules
->next
;
413 printf("REMOVING MODULE %s\n", KWMModules
->title
);
414 if (KWMModules
->title
)
415 XFree(KWMModules
->title
);
424 if (ptr
->next
->window
== window
) {
425 next
= ptr
->next
->next
;
427 printf("REMOVING MODULE %s\n", ptr
->next
->title
);
428 if (ptr
->next
->title
)
429 XFree(ptr
->next
->title
);
432 ptr
->next
->next
= next
;
435 ptr
->next
= ptr
->next
->next
;
439 if (scr
->kwm_dock
== window
)
440 scr
->kwm_dock
= None
;
446 addDockWindow(WScreen
*scr
, Window window
)
450 for (ptr
= KWMDockWindows
; ptr
!= NULL
; ptr
= ptr
->next
) {
451 if (ptr
->window
== window
)
457 node
= malloc(sizeof(KWMModuleList
));
459 wwarning("out of memory while processing KDE dock window");
462 node
->next
= KWMDockWindows
;
463 KWMDockWindows
= node
;
464 node
->window
= window
;
465 XSelectInput(dpy
, window
, StructureNotifyMask
);
467 sendClientMessage(scr
, scr
->kwm_dock
, _XA_KWM_MODULE_DOCKWIN_ADD
,
474 removeDockWindow(WScreen
*scr
, Window window
)
479 if (KWMDockWindows
->window
== window
) {
482 sendClientMessage(scr
, scr
->kwm_dock
, _XA_KWM_MODULE_DOCKWIN_REMOVE
,
485 next
= KWMDockWindows
->next
;
486 free(KWMDockWindows
);
487 KWMDockWindows
= next
;
490 KWMModuleList
*ptr
, *next
;
492 ptr
= KWMDockWindows
;
494 if (ptr
->next
->window
== window
) {
495 sendClientMessage(scr
, scr
->kwm_dock
,
496 _XA_KWM_MODULE_DOCKWIN_REMOVE
, window
);
497 next
= ptr
->next
->next
;
509 sendToModules(WScreen
*scr
, Atom atom
, WWindow
*wwin
, long data
)
516 if (wwin
->flags
.kwm_hidden_for_modules
517 || WFLAGP(wwin
, skip_window_list
))
519 data
= wwin
->client_win
;
522 printf("notifying %s\n",XGetAtomName(dpy
, atom
));
524 memset(&event
, 0, sizeof(XEvent
));
525 event
.xclient
.type
= ClientMessage
;
526 event
.xclient
.message_type
= atom
;
527 event
.xclient
.format
= 32;
528 event
.xclient
.data
.l
[1] = LastTimestamp
;
531 if (scr
&& scr
->root_win
== data
)
532 mask
= SubstructureRedirectMask
;
534 for (ptr
= KWMModules
; ptr
!=NULL
; ptr
= ptr
->next
) {
535 event
.xclient
.window
= ptr
->window
;
536 event
.xclient
.data
.l
[0] = data
;
537 XSendEvent(dpy
, ptr
->window
, False
, mask
, &event
);
543 wKWMInitStuff(WScreen
*scr
)
545 if (!_XA_KWM_WIN_STICKY
) {
546 _XA_KWM_WIN_UNSAVED_DATA
= XInternAtom(dpy
, "KWM_WIN_UNSAVED_DATA",
549 _XA_KWM_WIN_DECORATION
= XInternAtom(dpy
, "KWM_WIN_DECORATION", False
);
551 _XA_KWM_WIN_DESKTOP
= XInternAtom(dpy
, "KWM_WIN_DESKTOP", False
);
553 _XA_KWM_WIN_GEOMETRY_RESTORE
= XInternAtom(dpy
,
554 "KWM_WIN_GEOMETRY_RESTORE",
557 _XA_KWM_WIN_STICKY
= XInternAtom(dpy
, "KWM_WIN_STICKY", False
);
559 _XA_KWM_WIN_ICONIFIED
= XInternAtom(dpy
, "KWM_WIN_ICONIFIED", False
);
561 _XA_KWM_WIN_MAXIMIZED
= XInternAtom(dpy
, "KWM_WIN_MAXIMIZED", False
);
563 _XA_KWM_WIN_ICON_GEOMETRY
= XInternAtom(dpy
, "KWM_WIN_ICON_GEOMETRY",
566 _XA_KWM_COMMAND
= XInternAtom(dpy
, "KWM_COMMAND", False
);
568 _XA_KWM_ACTIVE_WINDOW
= XInternAtom(dpy
, "KWM_ACTIVE_WINDOW", False
);
570 _XA_KWM_ACTIVATE_WINDOW
= XInternAtom(dpy
, "KWM_ACTIVATE_WINDOW",
573 _XA_KWM_DO_NOT_MANAGE
= XInternAtom(dpy
, "KWM_DO_NOT_MANAGE", False
);
575 _XA_KWM_CURRENT_DESKTOP
= XInternAtom(dpy
, "KWM_CURRENT_DESKTOP",
578 _XA_KWM_NUMBER_OF_DESKTOPS
= XInternAtom(dpy
, "KWM_NUMBER_OF_DESKTOPS",
581 _XA_KWM_DOCKWINDOW
= XInternAtom(dpy
, "KWM_DOCKWINDOW", False
);
583 _XA_KWM_RUNNING
= XInternAtom(dpy
, "KWM_RUNNING", False
);
585 _XA_KWM_MODULE
= XInternAtom(dpy
, "KWM_MODULE", False
);
587 _XA_KWM_MODULE_INIT
= XInternAtom(dpy
, "KWM_MODULE_INIT", False
);
588 _XA_KWM_MODULE_INITIALIZED
= XInternAtom(dpy
, "KWM_MODULE_INITIALIZED", False
);
590 /* dunno what these do, but Matthias' patch contains it... */
591 _XA_KWM_MODULE_DESKTOP_CHANGE
= XInternAtom(dpy
, "KWM_MODULE_DESKTOP_CHANGE", False
);
592 _XA_KWM_MODULE_DESKTOP_NAME_CHANGE
= XInternAtom(dpy
, "KWM_MODULE_DESKTOP_NAME_CHANGE", False
);
593 _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE
= XInternAtom(dpy
, "KWM_MODULE_DESKTOP_NUMBER_CHANGE", False
);
595 _XA_KWM_MODULE_WIN_ADD
= XInternAtom(dpy
, "KWM_MODULE_WIN_ADD", False
);
596 _XA_KWM_MODULE_WIN_REMOVE
= XInternAtom(dpy
, "KWM_MODULE_WIN_REMOVE", False
);
597 _XA_KWM_MODULE_WIN_CHANGE
= XInternAtom(dpy
, "KWM_MODULE_WIN_CHANGE", False
);
598 _XA_KWM_MODULE_WIN_RAISE
= XInternAtom(dpy
, "KWM_MODULE_WIN_RAISE", False
);
599 _XA_KWM_MODULE_WIN_LOWER
= XInternAtom(dpy
, "KWM_MODULE_WIN_LOWER", False
);
600 _XA_KWM_MODULE_WIN_ACTIVATE
= XInternAtom(dpy
, "KWM_MODULE_WIN_ACTIVATE", False
);
601 _XA_KWM_MODULE_WIN_ICON_CHANGE
= XInternAtom(dpy
, "KWM_MODULE_WIN_ICON_CHANGE", False
);
602 _XA_KWM_MODULE_DOCKWIN_ADD
= XInternAtom(dpy
, "KWM_MODULE_DOCKWIN_ADD", False
);
603 _XA_KWM_MODULE_DOCKWIN_REMOVE
= XInternAtom(dpy
, "KWM_MODULE_DOCKWIN_REMOVE", False
);
605 memset(_XA_KWM_WINDOW_REGION_
, 0, sizeof(_XA_KWM_WINDOW_REGION_
));
607 memset(_XA_KWM_DESKTOP_NAME_
, 0, sizeof(_XA_KWM_DESKTOP_NAME_
));
610 #define SETSTR(hint, str) {\
611 static Atom a = 0; if (!a) a = XInternAtom(dpy, #hint, False);\
612 XChangeProperty(dpy, scr->root_win, a, XA_STRING, 8, PropModeReplace,\
613 (unsigned char*)str, strlen(str));}
615 SETSTR(KWM_STRING_MAXIMIZE
, _("Maximize"));
616 SETSTR(KWM_STRING_UNMAXIMIZE
, _("Unmaximize"));
617 SETSTR(KWM_STRING_ICONIFY
, _("Miniaturize"));
618 SETSTR(KWM_STRING_UNICONIFY
, _("Deminiaturize"));
619 SETSTR(KWM_STRING_STICKY
, _("Omnipresent"));
620 SETSTR(KWM_STRING_UNSTICKY
, _("Not Omnipresent"));
621 SETSTR(KWM_STRING_STRING_MOVE
, _("Move"));
622 SETSTR(KWM_STRING_STRING_RESIZE
, _("Resize"));
623 SETSTR(KWM_STRING_CLOSE
, _("Close"));
624 SETSTR(KWM_STRING_TODESKTOP
, _("Move To"));
625 SETSTR(KWM_STRING_ONTOCURRENTDESKTOP
, _("Bring Here"));
631 wKWMSendStacking(WScreen
*scr
, Window module
)
636 for (i
= 0; i
< MAX_WINDOW_LEVELS
; i
++) {
637 for (core
= scr
->stacking_list
[i
]; core
!= NULL
;
638 core
= core
->stacking
->under
) {
641 wwin
= wWindowFor(core
->window
);
643 sendClientMessage(scr
, module
, _XA_KWM_MODULE_WIN_RAISE
,
651 wKWMBroadcastStacking(WScreen
*scr
)
653 KWMModuleList
*ptr
= KWMModules
;
656 wKWMSendStacking(scr
, ptr
->window
);
664 wKWMGetWorkspaceName(WScreen
*scr
, int workspace
)
668 unsigned long nitems_ret
;
669 unsigned long bytes_after_ret
;
670 char *data
= NULL
, *tmp
;
673 assert(workspace
>= 0 && workspace
< MAX_WORKSPACES
);
675 if (_XA_KWM_DESKTOP_NAME_
[workspace
]==0) {
676 sprintf(buffer
, "KWM_DESKTOP_NAME_%d", workspace
+ 1);
678 _XA_KWM_DESKTOP_NAME_
[workspace
] = XInternAtom(dpy
, buffer
, False
);
681 /* What do these people have against correctly using property types? */
682 if (XGetWindowProperty(dpy
, scr
->root_win
,
683 _XA_KWM_DESKTOP_NAME_
[workspace
], 0, 128, False
,
685 &type_ret
, &fmt_ret
, &nitems_ret
, &bytes_after_ret
,
686 (unsigned char**)&data
)!=Success
|| !data
)
697 wKWMSetInitializedHint(WScreen
*scr
)
699 setSimpleHint(scr
->root_win
, _XA_KWM_RUNNING
, 1);
704 wKWMShutdown(WScreen
*scr
, Bool closeModules
)
708 XDeleteProperty(dpy
, scr
->root_win
, _XA_KWM_RUNNING
);
711 for (ptr
= KWMModules
; ptr
!= NULL
; ptr
= ptr
->next
) {
712 XKillClient(dpy
, ptr
->window
);
719 wKWMCheckClientHints(WWindow
*wwin
, int *workspace
)
723 if (getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_UNSAVED_DATA
, &val
)
726 wwin
->client_flags
.broken_close
= 1;
728 if (getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_DECORATION
, &val
)) {
729 if (val
& KWMnoFocus
) {
730 wwin
->client_flags
.no_focusable
= 1;
732 switch (val
& ~KWMnoFocus
) {
733 case KWMnoDecoration
:
734 wwin
->client_flags
.no_titlebar
= 1;
735 wwin
->client_flags
.no_resizebar
= 1;
737 case KWMtinyDecoration
:
738 wwin
->client_flags
.no_resizebar
= 1;
740 case KWMnormalDecoration
:
745 if (getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_DESKTOP
, &val
)) {
746 *workspace
= val
- 1;
752 wKWMCheckClientInitialState(WWindow
*wwin
)
756 if (getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_STICKY
, &val
) && val
) {
758 wwin
->client_flags
.omnipresent
= 1;
760 if (getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_ICONIFIED
, &val
)
763 wwin
->flags
.miniaturized
= 1;
765 if (getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_MAXIMIZED
, &val
)
768 wwin
->flags
.maximized
= MAX_VERTICAL
|MAX_HORIZONTAL
;
774 wKWMCheckClientHintChange(WWindow
*wwin
, XPropertyEvent
*event
)
776 Bool processed
= True
;
785 if (event
->atom
== _XA_KWM_WIN_UNSAVED_DATA
) {
787 printf("got KDE unsaved data change\n");
790 flag
= getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_UNSAVED_DATA
,
793 if (flag
!= wwin
->client_flags
.broken_close
) {
794 wwin
->client_flags
.broken_close
= flag
;
796 wWindowUpdateButtonImages(wwin
);
798 } else if (event
->atom
== _XA_KWM_WIN_STICKY
) {
801 printf("got KDE sticky change\n");
803 flag
= !getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_STICKY
,
806 if (flag
!= wwin
->client_flags
.omnipresent
) {
808 wwin
->client_flags
.omnipresent
= flag
;
810 UpdateSwitchMenu(wwin
->screen_ptr
, wwin
, ACTION_CHANGE_WORKSPACE
);
813 } else if (event
->atom
== _XA_KWM_WIN_MAXIMIZED
) {
816 printf("got KDE maximize change\n");
818 flag
= !getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_MAXIMIZED
,
821 if (flag
!= (wwin
->flags
.maximized
!=0)) {
824 wMaximizeWindow(wwin
, flag
*(MAX_VERTICAL
|MAX_HORIZONTAL
));
826 wUnmaximizeWindow(wwin
);
828 } else if (event
->atom
== _XA_KWM_WIN_ICONIFIED
) {
831 printf("got KDE iconify change\n");
833 flag
= !getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_ICONIFIED
,
836 if (flag
!= wwin
->flags
.miniaturized
) {
839 wIconifyWindow(wwin
);
841 wDeiconifyWindow(wwin
);
844 } else if (event
->atom
== _XA_KWM_WIN_DECORATION
) {
845 Bool refresh
= False
;
849 printf("got KDE decoration change\n");
852 oldnofocus
= wwin
->client_flags
.no_focusable
;
854 if (getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_DECORATION
, &value
)) {
855 wwin
->client_flags
.no_focusable
= (value
& KWMnoFocus
)!=0;
857 switch (value
& ~KWMnoFocus
) {
858 case KWMnoDecoration
:
859 if (!WFLAGP(wwin
, no_titlebar
) || !WFLAGP(wwin
, no_resizebar
))
862 wwin
->client_flags
.no_titlebar
= 1;
863 wwin
->client_flags
.no_resizebar
= 1;
866 case KWMtinyDecoration
:
867 if (WFLAGP(wwin
, no_titlebar
) || !WFLAGP(wwin
, no_resizebar
))
870 wwin
->client_flags
.no_titlebar
= 0;
871 wwin
->client_flags
.no_resizebar
= 1;
874 case KWMnormalDecoration
:
876 if (WFLAGP(wwin
, no_titlebar
) || WFLAGP(wwin
, no_resizebar
))
879 wwin
->client_flags
.no_titlebar
= 0;
880 wwin
->client_flags
.no_resizebar
= 0;
884 if (WFLAGP(wwin
, no_titlebar
) || WFLAGP(wwin
, no_resizebar
))
886 wwin
->client_flags
.no_focusable
= (value
& KWMnoFocus
)!=0;
887 wwin
->client_flags
.no_titlebar
= 0;
888 wwin
->client_flags
.no_resizebar
= 0;
892 wWindowConfigureBorders(wwin
);
894 if (wwin
->client_flags
.no_focusable
&& !oldnofocus
) {
896 sendToModules(wwin
->screen_ptr
, _XA_KWM_MODULE_WIN_REMOVE
,
898 wwin
->flags
.kwm_hidden_for_modules
= 1;
900 } else if (!wwin
->client_flags
.no_focusable
&& oldnofocus
) {
902 if (wwin
->flags
.kwm_hidden_for_modules
) {
903 sendToModules(wwin
->screen_ptr
, _XA_KWM_MODULE_WIN_ADD
,
905 wwin
->flags
.kwm_hidden_for_modules
= 0;
908 } else if (event
->atom
== _XA_KWM_WIN_DESKTOP
&& wwin
->frame
) {
910 printf("got KDE workspace change for %s\n", wwin
->frame
->title
);
912 if (getSimpleHint(wwin
->client_win
, _XA_KWM_WIN_DESKTOP
, &value
)
913 && value
-1 != wwin
->frame
->workspace
) {
914 wWindowChangeWorkspace(wwin
, value
-1);
917 } else if (event
->atom
== _XA_KWM_WIN_GEOMETRY_RESTORE
) {
921 printf("got KDE geometry restore change\n");
923 if (getAreaHint(wwin
->client_win
, _XA_KWM_WIN_GEOMETRY_RESTORE
, &area
)
924 && (wwin
->old_geometry
.x
!= area
.x1
925 || wwin
->old_geometry
.y
!= area
.y1
926 || wwin
->old_geometry
.width
!= area
.x2
- area
.x1
927 || wwin
->old_geometry
.height
!= area
.y2
- area
.y1
)) {
929 wwin
->old_geometry
.x
= area
.x1
;
930 wwin
->old_geometry
.y
= area
.y1
;
931 wwin
->old_geometry
.width
= area
.x2
- area
.x1
;
932 wwin
->old_geometry
.height
= area
.y2
- area
.y1
;
943 performWindowCommand(WScreen
*scr
, char *command
)
945 WWindow
*wwin
= NULL
;
948 wwin
= scr
->focused_window
;
949 if (!wwin
|| !wwin
->flags
.focused
|| !wwin
->flags
.mapped
) {
953 CloseWindowMenu(scr
);
956 if (strcmp(command
, "winMove")==0 || strcmp(command
, "winResize")==0) {
959 wKeyboardMoveResizeWindow(wwin
);
961 } else if (strcmp(command
, "winMaximize")==0) {
964 wMaximizeWindow(wwin
, MAX_VERTICAL
|MAX_HORIZONTAL
);
966 } else if (strcmp(command
, "winRestore")==0) {
968 if (wwin
&& wwin
->flags
.maximized
)
969 wUnmaximizeWindow(wwin
);
971 } else if (strcmp(command
, "winIconify")==0) {
974 if (wwin
&& !WFLAGP(wwin
, no_miniaturizable
)) {
975 if (wwin
->protocols
.MINIATURIZE_WINDOW
)
976 wClientSendProtocol(wwin
, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW
,
979 wIconifyWindow(wwin
);
983 } else if (strcmp(command
, "winClose")==0) {
985 if (wwin
&& !WFLAGP(wwin
, no_closable
)) {
986 if (wwin
->protocols
.DELETE_WINDOW
)
987 wClientSendProtocol(wwin
, _XA_WM_DELETE_WINDOW
, LastTimestamp
);
990 } else if (strcmp(command
, "winSticky")==0) {
993 wwin
->client_flags
.omnipresent
^= 1;
994 UpdateSwitchMenu(scr
, wwin
, ACTION_CHANGE_WORKSPACE
);
997 } else if (strcmp(command
, "winShade")==0) {
999 if (wwin
&& !WFLAGP(wwin
, no_shadeable
)) {
1000 if (wwin
->flags
.shaded
)
1001 wUnshadeWindow(wwin
);
1006 } else if (strcmp(command
, "winOperation")==0) {
1009 OpenWindowMenu(wwin
, wwin
->frame_x
,
1010 wwin
->frame_y
+wwin
->frame
->top_width
, True
);
1021 performCommand(WScreen
*scr
, char *command
, XClientMessageEvent
*event
)
1023 assert(scr
!= NULL
);
1025 if (strcmp(command
, "commandLine")==0
1026 || strcmp(command
, "execute")==0) {
1029 cmd
= ExpandOptions(scr
, _("%a(Run Command,Type the command to run:)"));
1031 ExecuteShellCommand(scr
, cmd
);
1034 } else if (strcmp(command
, "logout")==0) {
1036 Shutdown(WSLogoutMode
);
1038 } else if (strcmp(command
, "refreshScreen")==0) {
1040 wRefreshDesktop(scr
);
1042 } else if (strncmp(command
, "go:", 3)==0) {
1044 Shutdown(WSRestartPreparationMode
);
1045 Restart(&command
[3]);
1047 } else if (strcmp(command
, "desktop+1")==0) {
1049 wWorkspaceRelativeChange(scr
, 1);
1051 } else if (strcmp(command
, "desktop-1")==0) {
1053 wWorkspaceRelativeChange(scr
, -1);
1055 } else if (strcmp(command
, "desktop+2")==0) {
1057 wWorkspaceRelativeChange(scr
, 2);
1059 } else if (strcmp(command
, "desktop-2")==0) {
1061 wWorkspaceRelativeChange(scr
, -2);
1063 } else if (strcmp(command
, "desktop%%2")==0) {
1065 if (scr
->current_workspace
% 2 == 1)
1066 wWorkspaceRelativeChange(scr
, 1);
1068 wWorkspaceRelativeChange(scr
, -1);
1069 } else if (strncmp(command
, "desktop", 7)==0) {
1072 ws
= atoi(&command
[7]);
1073 wWorkspaceChange(scr
, ws
);
1075 /* wmaker specific stuff */
1076 } else if (strcmp(command
, "wmaker:info")==0) {
1078 wShowInfoPanel(scr
);
1080 } else if (strcmp(command
, "wmaker:legal")==0) {
1082 wShowLegalPanel(scr
);
1084 } else if (strcmp(command
, "wmaker:arrangeIcons")==0) {
1086 wArrangeIcons(scr
, True
);
1088 } else if (strcmp(command
, "wmaker:showAll")==0) {
1090 wShowAllWindows(scr
);
1092 } else if (strcmp(command
, "wmaker:hideOthers")==0) {
1094 wHideOtherApplications(scr
->focused_window
);
1096 } else if (strcmp(command
, "wmaker:restart")==0) {
1098 Shutdown(WSRestartPreparationMode
);
1101 } else if (strcmp(command
, "wmaker:exit")==0) {
1103 Shutdown(WSExitMode
);
1105 #ifdef UNSUPPORTED_STUFF
1106 } else if (strcmp(command
, "moduleRaised")==0) { /* useless */
1107 } else if (strcmp(command
, "deskUnclutter")==0) {
1108 } else if (strcmp(command
, "deskCascade")==0) {
1109 } else if (strcmp(command
, "configure")==0) {
1110 } else if (strcmp(command
, "taskManager")==0) {
1111 } else if (strcmp(command
, "darkenScreen")==0) { /* breaks consistency */
1113 } else if (!performWindowCommand(scr
, command
)) {
1114 KWMModuleList
*module
;
1117 /* do message relay thing */
1119 ev
.xclient
= *event
;
1120 for (module
= KWMModules
; module
!= NULL
; module
= module
->next
) {
1122 ev
.xclient
.window
= module
->window
;
1123 if (module
->window
== scr
->root_win
)
1124 mask
= SubstructureRedirectMask
;
1128 XSendEvent(dpy
, module
->window
, False
, mask
, &ev
);
1135 wKWMProcessClientMessage(XClientMessageEvent
*event
)
1137 Bool processed
= True
;
1140 printf("CLIENT MESS %s\n", XGetAtomName(dpy
, event
->message_type
));
1142 if (event
->message_type
== _XA_KWM_COMMAND
&& event
->format
==8) {
1146 scr
= wScreenForRootWindow(event
->window
);
1148 for (i
=0; i
<20; i
++) {
1149 buffer
[i
] = event
->data
.b
[i
];
1154 printf("got KDE command %s\n", buffer
);
1156 performCommand(scr
, buffer
, event
);
1158 } else if (event
->message_type
== _XA_KWM_ACTIVATE_WINDOW
) {
1162 printf("got KDE activate internal\n");
1164 wwin
= wWindowFor(event
->data
.l
[0]);
1167 wSetFocusTo(wwin
->screen_ptr
, wwin
);
1169 } else if (event
->message_type
== _XA_KWM_DO_NOT_MANAGE
1170 && event
->format
== 8) {
1171 KWMDoNotManageList
*node
;
1175 printf("got KDE dont manage\n");
1178 node
= malloc(sizeof(KWMDoNotManageList
));
1180 wwarning("out of memory processing KWM_DO_NOT_MANAGE message");
1182 for (i
=0; i
<20 && event
->data
.b
[i
]; i
++)
1183 node
->title
[i
] = event
->data
.b
[i
];
1186 node
->next
= KWMDoNotManageCrap
;
1187 KWMDoNotManageCrap
= node
;
1189 } else if (event
->message_type
== _XA_KWM_MODULE
) {
1191 Window modwin
= event
->data
.l
[0];
1193 scr
= wScreenForRootWindow(event
->window
);
1195 if (getSimpleHint(modwin
, _XA_KWM_MODULE
, &val
) && val
) {
1197 puts("got KDE module startup");
1199 addModule(scr
, modwin
);
1202 puts("got KDE module finish");
1204 removeModule(scr
, modwin
);
1215 wKWMCheckModule(WScreen
*scr
, Window window
)
1219 if (getSimpleHint(window
, _XA_KWM_MODULE
, &val
) && val
) {
1221 puts("got KDE module startup");
1223 addModule(scr
, window
);
1229 wKWMCheckRootHintChange(WScreen
*scr
, XPropertyEvent
*event
)
1231 Bool processed
= True
;
1234 if (event
->atom
== _XA_KWM_CURRENT_DESKTOP
) {
1235 if (getSimpleHint(scr
->root_win
, _XA_KWM_CURRENT_DESKTOP
, &value
)) {
1237 printf("got KDE workspace switch to %li\n", value
);
1239 if (value
-1 != scr
->current_workspace
) {
1240 wWorkspaceChange(scr
, value
-1);
1243 } else if (event
->atom
== _XA_KWM_NUMBER_OF_DESKTOPS
) {
1245 printf("got KDE workspace number change\n");
1248 if (getSimpleHint(scr
->root_win
, _XA_KWM_NUMBER_OF_DESKTOPS
, &value
)) {
1250 /* increasing is easy... */
1251 if (value
> scr
->workspace_count
) {
1252 scr
->flags
.kwm_syncing_count
= 1;
1254 wWorkspaceMake(scr
, value
- scr
->workspace_count
);
1256 scr
->flags
.kwm_syncing_count
= 0;
1258 } else if (value
< scr
->workspace_count
) {
1260 Bool rebuild
= False
;
1262 scr
->flags
.kwm_syncing_count
= 1;
1264 /* decrease all we can do */
1265 for (i
= scr
->workspace_count
; i
>= value
; i
--) {
1266 if (!wWorkspaceDelete(scr
, i
)) {
1272 scr
->flags
.kwm_syncing_count
= 0;
1274 /* someone destroyed a workspace that can't be destroyed.
1275 * Reset the hints to reflect our internal state.
1278 wKWMUpdateWorkspaceCountHint(scr
);
1287 for (i
= 0; i
< MAX_WORKSPACES
; i
++) {
1288 if (event
->atom
== _XA_KWM_DESKTOP_NAME_
[i
]) {
1291 name
= wKWMGetWorkspaceName(scr
, i
);
1294 printf("got KDE workspace name change to %s\n", name
);
1297 if (name
&& strncmp(name
, scr
->workspaces
[i
]->name
,
1298 MAX_WORKSPACENAME_WIDTH
)!=0) {
1299 scr
->flags
.kwm_syncing_name
= 1;
1300 wWorkspaceRename(scr
, i
, name
);
1301 scr
->flags
.kwm_syncing_name
= 0;
1307 } else if (event
->atom
== _XA_KWM_WINDOW_REGION_
[i
]) {
1310 if (getAreaHint(scr
->root_win
, event
->atom
, &area
)) {
1312 if (scr
->totalUsableArea
.x1
!= area
.x1
1313 || scr
->totalUsableArea
.y1
!= area
.y1
1314 || scr
->totalUsableArea
.x2
!= area
.x2
1315 || scr
->totalUsableArea
.y2
!= area
.y2
) {
1316 wScreenUpdateUsableArea(scr
);
1331 wKWMManageableClient(WScreen
*scr
, Window win
, char *title
)
1333 KWMDoNotManageList
*ptr
, *next
;
1336 if (getSimpleHint(win
, _XA_KWM_DOCKWINDOW
, &val
) && val
) {
1337 addDockWindow(scr
, win
);
1341 ptr
= KWMDoNotManageCrap
;
1343 * TODO: support for glob patterns or regexes
1345 if (ptr
&& strncmp(ptr
->title
, title
, strlen(ptr
->title
))==0) {
1348 KWMDoNotManageCrap
= next
;
1350 printf("window %s not managed per KDE request\n", title
);
1353 sendToModules(scr
, _XA_KWM_MODULE_WIN_ADD
, NULL
, win
);
1354 sendToModules(scr
, _XA_KWM_MODULE_WIN_REMOVE
, NULL
, win
);
1359 if (strncmp(ptr
->next
->title
, title
, strlen(ptr
->next
->title
))==0) {
1361 printf("window %s not managed per KDE request\n", title
);
1363 next
= ptr
->next
->next
;
1367 sendToModules(scr
, _XA_KWM_MODULE_WIN_ADD
, NULL
, win
);
1368 sendToModules(scr
, _XA_KWM_MODULE_WIN_REMOVE
, NULL
, win
);
1382 wKWMUpdateCurrentWorkspaceHint(WScreen
*scr
)
1384 setSimpleHint(scr
->root_win
, _XA_KWM_CURRENT_DESKTOP
,
1385 scr
->current_workspace
+1);
1387 sendToModules(scr
, _XA_KWM_MODULE_DESKTOP_CHANGE
, NULL
,
1388 scr
->current_workspace
+1);
1393 wKWMUpdateActiveWindowHint(WScreen
*scr
)
1397 if (!scr
->focused_window
|| !scr
->focused_window
->flags
.focused
)
1400 val
= (long)(scr
->focused_window
->client_win
);
1402 XChangeProperty(dpy
, scr
->root_win
, _XA_KWM_ACTIVE_WINDOW
,
1403 _XA_KWM_ACTIVE_WINDOW
, 32, PropModeReplace
,
1404 (unsigned char*)&val
, 1);
1410 wKWMUpdateWorkspaceCountHint(WScreen
*scr
)
1412 if (scr
->flags
.kwm_syncing_count
)
1415 setSimpleHint(scr
->root_win
, _XA_KWM_NUMBER_OF_DESKTOPS
,
1416 scr
->workspace_count
);
1418 sendToModules(scr
, _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE
, NULL
,
1419 scr
->workspace_count
);
1424 wKWMCheckDestroy(XDestroyWindowEvent
*event
)
1428 if (event
->event
== event
->window
) {
1432 scr
= wScreenSearchForRootWindow(event
->event
);
1437 removeModule(scr
, event
->window
);
1438 removeDockWindow(scr
, event
->window
);
1443 wKWMUpdateWorkspaceNameHint(WScreen
*scr
, int workspace
)
1447 assert(workspace
>= 0 && workspace
< MAX_WORKSPACES
);
1449 if (_XA_KWM_DESKTOP_NAME_
[workspace
]==0) {
1450 sprintf(buffer
, "KWM_DESKTOP_NAME_%d", workspace
+ 1);
1452 _XA_KWM_DESKTOP_NAME_
[workspace
] = XInternAtom(dpy
, buffer
, False
);
1455 XChangeProperty(dpy
, scr
->root_win
, _XA_KWM_DESKTOP_NAME_
[workspace
],
1456 XA_STRING
, 8, PropModeReplace
,
1457 (unsigned char*)scr
->workspaces
[workspace
]->name
,
1458 strlen(scr
->workspaces
[workspace
]->name
)+1);
1460 sendToModules(scr
, _XA_KWM_MODULE_DESKTOP_NAME_CHANGE
, NULL
, workspace
+1);
1466 wKWMUpdateClientWorkspace(WWindow
*wwin
)
1469 printf("updating workspace of %s to %i\n",
1470 wwin
->frame
->title
, wwin
->frame
->workspace
+1);
1472 setSimpleHint(wwin
->client_win
, _XA_KWM_WIN_DESKTOP
,
1473 wwin
->frame
->workspace
+1);
1478 wKWMUpdateClientGeometryRestore(WWindow
*wwin
)
1482 rect
.x1
= wwin
->old_geometry
.x
;
1483 rect
.y1
= wwin
->old_geometry
.y
;
1484 rect
.x2
= wwin
->old_geometry
.x
+ wwin
->old_geometry
.width
;
1485 rect
.y2
= wwin
->old_geometry
.y
+ wwin
->old_geometry
.height
;
1487 setAreaHint(wwin
->client_win
, _XA_KWM_WIN_GEOMETRY_RESTORE
, rect
);
1492 wKWMUpdateClientStateHint(WWindow
*wwin
, WKWMStateFlag flags
)
1494 if (flags
& KWMIconifiedFlag
) {
1495 setSimpleHint(wwin
->client_win
, _XA_KWM_WIN_ICONIFIED
,
1496 wwin
->flags
.miniaturized
/*|| wwin->flags.shaded
1497 || wwin->flags.hidden*/);
1499 if (flags
& KWMStickyFlag
) {
1500 setSimpleHint(wwin
->client_win
, _XA_KWM_WIN_STICKY
,
1501 IS_OMNIPRESENT(wwin
));
1503 if (flags
& KWMMaximizedFlag
) {
1504 setSimpleHint(wwin
->client_win
, _XA_KWM_WIN_MAXIMIZED
,
1505 wwin
->flags
.maximized
!=0);
1511 wKWMGetUsableArea(WScreen
*scr
, WArea
*area
)
1515 if (_XA_KWM_WINDOW_REGION_
[0]==0) {
1516 sprintf(buffer
, "KWM_WINDOW_REGION_%d", 1);
1518 _XA_KWM_WINDOW_REGION_
[0] = XInternAtom(dpy
, buffer
, False
);
1521 return getAreaHint(scr
->root_win
, _XA_KWM_WINDOW_REGION_
[0], area
);
1527 wKWMGetIconGeometry(WWindow
*wwin
, WArea
*area
)
1529 return getAreaHint(wwin
->client_win
, _XA_KWM_WIN_ICON_GEOMETRY
, area
);
1536 wKWMSetUsableAreaHint(WScreen
*scr
, int workspace
)
1538 /* if we set this after making changes of our own to the area,
1539 * the next time the area changes, we won't know what should
1540 * be the new final area. This protocol isn't worth a shit :/
1543 * According to Matthias Ettrich:
1544 * Indeed, there's no protocol to deal with the area yet in case several
1545 * clients want to influence it. It is sufficent, though, if it is clear
1546 * that one process is responsable for the area. For KDE this is kpanel, but
1547 * I see that there might be a conflict with the docking area of windowmaker
1555 assert(workspace
>= 0 && workspace
< MAX_WORKSPACES
);
1557 if (_XA_KWM_WINDOW_REGION_
[workspace
]==0) {
1558 sprintf(buffer
, "KWM_WINDOW_REGION_%d", workspace
+1);
1560 _XA_KWM_WINDOW_REGION_
[workspace
] = XInternAtom(dpy
, buffer
, False
);
1563 setAreaHint(scr
->root_win
, _XA_KWM_WINDOW_REGION_
[workspace
],
1564 scr
->totalUsableArea
);
1567 #endif /* not_used */
1570 wKWMSendEventMessage(WWindow
*wwin
, WKWMEventMessage message
)
1574 if (wwin
&& (wwin
->flags
.internal_window
1575 || wwin
->flags
.kwm_hidden_for_modules
1576 || !wwin
->flags
.kwm_managed
1577 || WFLAGP(wwin
, skip_window_list
)))
1582 msg
= _XA_KWM_MODULE_WIN_ADD
;
1584 case WKWMRemoveWindow
:
1585 msg
= _XA_KWM_MODULE_WIN_REMOVE
;
1587 case WKWMFocusWindow
:
1588 msg
= _XA_KWM_MODULE_WIN_ACTIVATE
;
1590 case WKWMRaiseWindow
:
1591 msg
= _XA_KWM_MODULE_WIN_RAISE
;
1593 case WKWMLowerWindow
:
1594 msg
= _XA_KWM_MODULE_WIN_LOWER
;
1596 case WKWMChangedClient
:
1597 msg
= _XA_KWM_MODULE_WIN_CHANGE
;
1599 case WKWMIconChange
:
1600 msg
= _XA_KWM_MODULE_WIN_ICON_CHANGE
;
1606 sendToModules(wwin
? wwin
->screen_ptr
: NULL
, msg
, wwin
, 0);
1610 #endif /* KWM_HINTS */