Code update for Window Maker version 0.50.0
[wmaker-crm.git] / src / kwm.c
blobf253754daa1ea391a82c319e53a3457256c18f3a
1 /* kwm.c-- stuff for support for kwm hints
3 * Window Maker window manager
4 *
5 * Copyright (c) 1998, 1999 Alfredo K. Kojima
6 *
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,
20 * USA.
25 * Supported stuff:
26 * ================
27 * kwm.h function/method Notes
28 *----------------------------------------------------------------------------
29 * setUnsavedDataHint() currently, only gives visual clue that
30 * there is saved data (broken X close button)
31 * setSticky()
32 * setIcon() std X thing...
33 * setDecoration()
34 * logout()
35 * refreshScreen()
36 * setWmCommand() std X thing
37 * currentDesktop()
38 * setKWMModule()
40 * isKWMInitialized() not trustworthy
41 * activeWindow() dunno it's use, but since it's easy to
42 * implement it won't hurt to support
43 * switchToDesktop()
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
50 * desktop()
51 * geometryRestore()
52 * isIconified()
53 * isMaximized()
54 * isSticky()
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!?
59 * its even broken!!!
60 * move() std X thing
61 * setGeometry() std X thing
62 * close() std X thing
63 * activate()
64 * activateInternal()
65 * raise() std X thing
66 * lower() 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
72 * setDockWindow()
74 * Unsupported stuff (superfluous/not-essential/nonsense):
75 * =======================================================
77 * darkenScreen()
78 * setMiniIcon()
79 * configureWm()
80 * raiseSoundEvent()
81 * registerSoundEvent()
82 * unregisterSoundEvent()
83 * title()
84 * titleWithState()
85 * geometry() kde lib code makes it unnecessary
88 * Extensions to KDE:
89 * ==================
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
102 #include "wconfig.h"
104 #ifdef KWM_HINTS
106 #include <X11/Xlib.h>
107 #include <X11/Xutil.h>
108 #include <X11/Xatom.h>
110 #include <stdlib.h>
111 #include <stdio.h>
112 #include <string.h>
115 #include "WindowMaker.h"
117 #include "screen.h"
118 #include "wcore.h"
119 #include "framewin.h"
120 #include "window.h"
121 #include "properties.h"
122 #include "icon.h"
123 #include "client.h"
124 #include "funcs.h"
125 #include "actions.h"
126 #include "workspace.h"
127 #include "dialog.h"
129 #include "kwm.h"
131 /*#define DEBUG1
133 /******* Global ******/
135 extern Time LastFocusChange;
136 extern Time LastTimestamp;
139 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
140 extern Atom _XA_WM_DELETE_WINDOW;
142 /** Local **/
144 static Atom _XA_KWM_COMMAND = 0;
145 static Atom _XA_KWM_ACTIVATE_WINDOW = 0;
146 static Atom _XA_KWM_ACTIVE_WINDOW = 0;
147 static Atom _XA_KWM_DO_NOT_MANAGE = 0;
148 static Atom _XA_KWM_DOCKWINDOW = 0;
149 static Atom _XA_KWM_RUNNING = 0;
151 static Atom _XA_KWM_MODULE = 0;
153 static Atom _XA_KWM_MODULE_INIT = 0;
154 static Atom _XA_KWM_MODULE_DESKTOP_CHANGE = 0;
155 static Atom _XA_KWM_MODULE_DESKTOP_NAME_CHANGE = 0;
156 static Atom _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE = 0;
157 static Atom _XA_KWM_MODULE_WIN_ADD = 0;
158 static Atom _XA_KWM_MODULE_WIN_REMOVE = 0;
159 static Atom _XA_KWM_MODULE_WIN_CHANGE = 0;
160 static Atom _XA_KWM_MODULE_WIN_RAISE = 0;
161 static Atom _XA_KWM_MODULE_WIN_LOWER = 0;
162 static Atom _XA_KWM_MODULE_WIN_ACTIVATE = 0;
163 static Atom _XA_KWM_MODULE_WIN_ICON_CHANGE = 0;
164 static Atom _XA_KWM_MODULE_DOCKWIN_ADD = 0;
165 static Atom _XA_KWM_MODULE_DOCKWIN_REMOVE = 0;
167 static Atom _XA_KWM_WIN_UNSAVED_DATA = 0;
168 static Atom _XA_KWM_WIN_DECORATION = 0;
169 static Atom _XA_KWM_WIN_DESKTOP = 0;
170 static Atom _XA_KWM_WIN_GEOMETRY_RESTORE = 0;
171 static Atom _XA_KWM_WIN_ICONIFIED = 0;
172 static Atom _XA_KWM_WIN_MAXIMIZED = 0;
173 static Atom _XA_KWM_WIN_STICKY = 0;
175 static Atom _XA_KWM_CURRENT_DESKTOP = 0;
176 static Atom _XA_KWM_NUMBER_OF_DESKTOPS = 0;
177 static Atom _XA_KWM_DESKTOP_NAME_[MAX_WORKSPACES];
178 static Atom _XA_KWM_WINDOW_REGION_[MAX_WORKSPACES];
182 /* list of window titles that must not be managed */
183 typedef struct KWMDoNotManageList {
184 char title[20];
185 struct KWMDoNotManageList *next;
186 } KWMDoNotManageList;
188 static KWMDoNotManageList *KWMDoNotManageCrap = NULL;
191 /* list of KWM modules */
192 typedef struct KWMModuleList {
193 Window window;
194 struct KWMModuleList *next;
195 #ifdef DEBUG1
196 char *title;
197 #endif
198 } KWMModuleList;
200 static KWMModuleList *KWMModules = NULL;
202 static KWMModuleList *KWMDockWindows = NULL;
204 /* window decoration types */
205 enum {
206 KWMnoDecoration = 0,
207 KWMnormalDecoration = 1,
208 KWMtinyDecoration = 2,
209 KWMnoFocus = 256
214 static Bool
215 getSimpleHint(Window win, Atom atom, long *retval)
217 long *data = 0;
219 assert(atom!=0);
221 data = (long*)PropGetCheckProperty(window, atom, atom, 32, 1, NULL);
223 if (!data)
224 return False;
226 *retval = *data;
228 XFree(data);
230 return True;
235 static void
236 setSimpleHint(Window win, Atom atom, long value)
238 assert(atom!=0);
239 XChangeProperty(dpy, win, atom, atom,
240 32, PropModeReplace, (unsigned char*)&value, 1);
244 static void
245 sendClientMessage(WScreen *scr, Window window, Atom atom, long value)
247 XEvent event;
248 long mask = 0;
250 assert(atom!=0);
252 memset(&event, 0, sizeof(XEvent));
253 event.xclient.type = ClientMessage;
254 event.xclient.message_type = atom;
255 event.xclient.window = window;
256 event.xclient.format = 32;
257 event.xclient.data.l[0] = value;
258 event.xclient.data.l[1] = LastTimestamp;
260 if (scr && scr->root_win == window)
261 mask = SubstructureRedirectMask;
263 XSendEvent(dpy, window, False, mask, &event);
267 static Bool
268 getAreaHint(Window win, Atom atom, WArea *area)
270 long *data = 0;
272 data = (long*)PropGetCheckProperty(win, atom, atom, 32, 4, NULL);
274 if (!data)
275 return False;
277 area->x1 = data[0];
278 area->y1 = data[1];
279 area->x2 = data[2] + area->x1;
280 area->y2 = data[3] + area->y1;
282 XFree(data);
284 return True;
288 static void
289 setAreaHint(Window win, Atom atom, WArea area)
291 long value[4];
293 assert(atom!=0);
294 value[0] = area.x1;
295 value[1] = area.y1;
296 value[2] = area.x2 - area.x1;
297 value[3] = area.y2 - area.y1;
298 XChangeProperty(dpy, win, atom, atom, 32, PropModeReplace,
299 (unsigned char*)&value, 4);
303 static void
304 addModule(WScreen *scr, Window window)
306 KWMModuleList *node;
307 long val;
308 WWindow *ptr;
310 node = malloc(sizeof(KWMModuleList));
311 if (!node) {
312 wwarning("out of memory while registering KDE module");
313 return;
316 node->next = KWMModules;
317 node->window = window;
318 KWMModules = node;
320 sendClientMessage(scr, window, _XA_KWM_MODULE_INIT, 0);
322 if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val==2) {
323 if (scr->kwm_dock != None) {
324 setSimpleHint(window, _XA_KWM_MODULE, 1);
325 } else {
326 KWMModuleList *ptr;
328 scr->kwm_dock = window;
330 for (ptr = KWMDockWindows; ptr!=NULL; ptr = ptr->next) {
331 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
332 ptr->window);
337 for (ptr = scr->focused_window; ptr!=NULL; ptr = ptr->prev) {
338 if (!ptr->flags.kwm_hidden_for_modules
339 && !WFLAGP(ptr, skip_window_list)) {
340 sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ADD,
341 ptr->client_win);
344 wKWMSendStacking(scr, window);
346 if (scr->focused_window && scr->focused_window->flags.focused) {
347 sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ACTIVATE,
348 scr->focused_window->client_win);
350 #ifdef DEBUG1
351 KWMModules->title = NULL;
352 XFetchName(dpy, window, &KWMModules->title);
353 printf("NEW MODULE %s\n", KWMModules->title);
354 #endif
358 static void
359 removeModule(WScreen *scr, Window window)
361 KWMModuleList *next;
363 if (!KWMModules) {
364 return;
367 if (KWMModules->window == window) {
368 next = KWMModules->next;
369 #ifdef DEBUG1
370 printf("REMOVING MODULE %s\n", KWMModules->title);
371 if (KWMModules->title)
372 XFree(KWMModules->title);
373 #endif
374 free(KWMModules);
375 KWMModules = next;
376 } else {
377 KWMModuleList *ptr;
379 ptr = KWMModules;
380 while (ptr->next) {
381 if (ptr->next->window == window) {
382 next = ptr->next->next;
383 #ifdef DEBUG1
384 printf("REMOVING MODULE %s\n", ptr->next->title);
385 if (ptr->next->title)
386 XFree(ptr->next->title);
387 #endif
388 free(ptr->next);
389 ptr->next->next = next;
390 break;
392 ptr->next = ptr->next->next;
396 if (scr->kwm_dock == window)
397 scr->kwm_dock = None;
402 static void
403 addDockWindow(WScreen *scr, Window window)
405 KWMModuleList *ptr;
407 for (ptr = KWMDockWindows; ptr != NULL; ptr = ptr->next) {
408 if (ptr->window == window)
409 break;
411 if (!ptr) {
412 KWMModuleList *node;
414 node = malloc(sizeof(KWMModuleList));
415 if (!node) {
416 wwarning("out of memory while processing KDE dock window");
417 return;
419 node->next = KWMDockWindows;
420 KWMDockWindows = node;
421 node->window = window;
422 XSelectInput(dpy, window, StructureNotifyMask);
424 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
425 window);
430 static void
431 removeDockWindow(WScreen *scr, Window window)
433 if (!KWMDockWindows)
434 return;
436 if (KWMDockWindows->window == window) {
437 KWMModuleList *next;
439 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_REMOVE,
440 window);
442 next = KWMDockWindows->next;
443 free(KWMDockWindows);
444 KWMDockWindows = next;
446 } else {
447 KWMModuleList *ptr, *next;
449 ptr = KWMDockWindows;
450 while (ptr->next) {
451 if (ptr->next->window == window) {
452 sendClientMessage(scr, scr->kwm_dock,
453 _XA_KWM_MODULE_DOCKWIN_REMOVE, window);
454 next = ptr->next->next;
455 free(ptr->next);
456 ptr->next = next;
457 return;
459 ptr = ptr->next;
465 static void
466 sendToModules(WScreen *scr, Atom atom, WWindow *wwin, long data)
468 KWMModuleList *ptr;
469 XEvent event;
470 long mask;
472 if (wwin) {
473 if (wwin->flags.kwm_hidden_for_modules
474 || WFLAGP(wwin, skip_window_list))
475 return;
476 data = wwin->client_win;
478 #ifdef DEBUG1
479 printf("notifying %s\n",XGetAtomName(dpy, atom));
480 #endif
481 memset(&event, 0, sizeof(XEvent));
482 event.xclient.type = ClientMessage;
483 event.xclient.message_type = atom;
484 event.xclient.format = 32;
485 event.xclient.data.l[1] = LastTimestamp;
487 mask = 0;
488 if (scr && scr->root_win == data)
489 mask = SubstructureRedirectMask;
491 for (ptr = KWMModules; ptr!=NULL; ptr = ptr->next) {
492 event.xclient.window = ptr->window;
493 event.xclient.data.l[0] = data;
494 XSendEvent(dpy, ptr->window, False, mask, &event);
499 void
500 wKWMInitStuff(WScreen *scr)
502 if (!_XA_KWM_WIN_STICKY) {
503 _XA_KWM_WIN_UNSAVED_DATA = XInternAtom(dpy, "KWM_WIN_UNSAVED_DATA",
504 False);
506 _XA_KWM_WIN_DECORATION = XInternAtom(dpy, "KWM_WIN_DECORATION", False);
508 _XA_KWM_WIN_DESKTOP = XInternAtom(dpy, "KWM_WIN_DESKTOP", False);
510 _XA_KWM_WIN_GEOMETRY_RESTORE = XInternAtom(dpy,
511 "KWM_WIN_GEOMETRY_RESTORE",
512 False);
514 _XA_KWM_WIN_STICKY = XInternAtom(dpy, "KWM_WIN_STICKY", False);
516 _XA_KWM_WIN_ICONIFIED = XInternAtom(dpy, "KWM_WIN_ICONIFIED", False);
518 _XA_KWM_WIN_MAXIMIZED = XInternAtom(dpy, "KWM_WIN_MAXIMIZED", False);
520 _XA_KWM_COMMAND = XInternAtom(dpy, "KWM_COMMAND", False);
522 _XA_KWM_ACTIVE_WINDOW = XInternAtom(dpy, "KWM_ACTIVE_WINDOW", False);
524 _XA_KWM_ACTIVATE_WINDOW = XInternAtom(dpy, "KWM_ACTIVATE_WINDOW",
525 False);
527 _XA_KWM_DO_NOT_MANAGE = XInternAtom(dpy, "KWM_DO_NOT_MANAGE", False);
529 _XA_KWM_CURRENT_DESKTOP = XInternAtom(dpy, "KWM_CURRENT_DESKTOP",
530 False);
532 _XA_KWM_NUMBER_OF_DESKTOPS = XInternAtom(dpy, "KWM_NUMBER_OF_DESKTOPS",
533 False);
535 _XA_KWM_DOCKWINDOW = XInternAtom(dpy, "KWM_DOCKWINDOW", False);
537 _XA_KWM_RUNNING = XInternAtom(dpy, "KWM_RUNNING", False);
539 _XA_KWM_MODULE = XInternAtom(dpy, "KWM_MODULE", False);
541 _XA_KWM_MODULE_INIT = XInternAtom(dpy, "KWM_MODULE_INIT", False);
542 _XA_KWM_MODULE_DESKTOP_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_CHANGE", False);
543 _XA_KWM_MODULE_DESKTOP_NAME_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NAME_CHANGE", False);
544 _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NUMBER_CHANGE", False);
545 _XA_KWM_MODULE_WIN_ADD = XInternAtom(dpy, "KWM_MODULE_WIN_ADD", False);
546 _XA_KWM_MODULE_WIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_WIN_REMOVE", False);
547 _XA_KWM_MODULE_WIN_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_CHANGE", False);
548 _XA_KWM_MODULE_WIN_RAISE = XInternAtom(dpy, "KWM_MODULE_WIN_RAISE", False);
549 _XA_KWM_MODULE_WIN_LOWER = XInternAtom(dpy, "KWM_MODULE_WIN_LOWER", False);
550 _XA_KWM_MODULE_WIN_ACTIVATE = XInternAtom(dpy, "KWM_MODULE_WIN_ACTIVATE", False);
551 _XA_KWM_MODULE_WIN_ICON_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_ICON_CHANGE", False);
552 _XA_KWM_MODULE_DOCKWIN_ADD = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_ADD", False);
553 _XA_KWM_MODULE_DOCKWIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_REMOVE", False);
555 memset(_XA_KWM_WINDOW_REGION_, 0, sizeof(_XA_KWM_WINDOW_REGION_));
557 memset(_XA_KWM_DESKTOP_NAME_, 0, sizeof(_XA_KWM_DESKTOP_NAME_));
560 #define SETSTR(hint, str) {\
561 static Atom a = 0; if (!a) a = XInternAtom(dpy, #hint, False);\
562 XChangeProperty(dpy, scr->root_win, a, XA_STRING, 8, PropModeReplace,\
563 (unsigned char*)str, strlen(str));}
565 SETSTR(KWM_STRING_MAXIMIZE, _("Maximize"));
566 SETSTR(KWM_STRING_UNMAXIMIZE, _("Unmaximize"));
567 SETSTR(KWM_STRING_ICONIFY, _("Miniaturize"));
568 SETSTR(KWM_STRING_UNICONIFY, _("Deminiaturize"));
569 SETSTR(KWM_STRING_STICKY, _("Omnipresent"));
570 SETSTR(KWM_STRING_UNSTICKY, _("Not Omnipresent"));
571 SETSTR(KWM_STRING_STRING_MOVE, _("Move"));
572 SETSTR(KWM_STRING_STRING_RESIZE, _("Resize"));
573 SETSTR(KWM_STRING_CLOSE, _("Close"));
574 SETSTR(KWM_STRING_TODESKTOP, _("Move To"));
575 SETSTR(KWM_STRING_ONTOCURRENTDESKTOP, _("Bring Here"));
576 #undef SETSTR
580 void
581 wKWMSendStacking(WScreen *scr, Window module)
583 int i;
584 WCoreWindow *core;
586 for (i = 0; i < MAX_WINDOW_LEVELS; i++) {
587 for (core = scr->stacking_list[i]; core != NULL;
588 core = core->stacking->under) {
589 WWindow *wwin;
591 wwin = wWindowFor(core->window);
592 if (wwin)
593 sendClientMessage(scr, module, _XA_KWM_MODULE_WIN_RAISE,
594 wwin->client_win);
600 char*
601 wKWMGetWorkspaceName(WScreen *scr, int workspace)
603 Atom type_ret;
604 int fmt_ret;
605 unsigned long nitems_ret;
606 unsigned long bytes_after_ret;
607 char *data = NULL, *tmp;
608 char buffer[64];
610 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
612 if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
613 sprintf(buffer, "KWM_DESKTOP_NAME_%d", workspace + 1);
615 _XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
618 /* What do these people have against correctly using property types? */
619 if (XGetWindowProperty(dpy, scr->root_win,
620 _XA_KWM_DESKTOP_NAME_[workspace], 0, 128, False,
621 XA_STRING,
622 &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
623 (unsigned char**)&data)!=Success || !data)
624 return NULL;
626 tmp = wstrdup(data);
627 XFree(data);
629 return tmp;
633 void
634 wKWMSetInitializedHint(WScreen *scr)
636 setSimpleHint(scr->root_win, _XA_KWM_RUNNING, 1);
640 void
641 wKWMShutdown(WScreen *scr)
643 KWMModuleList *ptr;
645 XDeleteProperty(dpy, scr->root_win, _XA_KWM_RUNNING);
647 for (ptr = KWMModules; ptr != NULL; ptr = ptr->next) {
648 XKillClient(dpy, ptr->window);
653 void
654 wKWMCheckClientHints(WWindow *wwin, int *workspace)
656 long val;
658 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA, &val)
659 && val) {
661 wwin->client_flags.broken_close = 1;
663 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &val)) {
664 if (val & KWMnoFocus) {
665 wwin->client_flags.no_focusable = 1;
667 switch (val & ~KWMnoFocus) {
668 case KWMnoDecoration:
669 wwin->client_flags.no_titlebar = 1;
670 wwin->client_flags.no_resizebar = 1;
671 break;
672 case KWMtinyDecoration:
673 wwin->client_flags.no_resizebar = 1;
674 break;
675 case KWMnormalDecoration:
676 default:
677 break;
680 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &val)) {
681 *workspace = val;
686 void
687 wKWMCheckClientInitialState(WWindow *wwin)
689 long val;
691 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY, &val) && val) {
693 wwin->client_flags.omnipresent = 1;
695 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED, &val)
696 && val) {
698 wwin->flags.miniaturized = 1;
700 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, &val)
701 && val) {
703 wwin->flags.maximized = MAX_VERTICAL|MAX_HORIZONTAL;
708 Bool
709 wKWMCheckClientHintChange(WWindow *wwin, XPropertyEvent *event)
711 Bool processed = True;
712 Bool flag;
713 long value;
716 if (!wwin->frame) {
717 return False;
720 if (event->atom == _XA_KWM_WIN_UNSAVED_DATA) {
721 #ifdef DEBUG1
722 printf("got KDE unsaved data change\n");
723 #endif
725 flag = getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA,
726 &value) && value;
728 if (flag != wwin->client_flags.broken_close) {
729 wwin->client_flags.broken_close = flag;
730 if (wwin->frame)
731 wWindowUpdateButtonImages(wwin);
733 } else if (event->atom == _XA_KWM_WIN_STICKY) {
735 #ifdef DEBUG1
736 printf("got KDE sticky change\n");
737 #endif
738 flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY,
739 &value) || value;
741 if (flag != wwin->client_flags.omnipresent) {
743 wwin->client_flags.omnipresent = flag;
745 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
748 } else if (event->atom == _XA_KWM_WIN_MAXIMIZED) {
750 #ifdef DEBUG1
751 printf("got KDE maximize change\n");
752 #endif
753 flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED,
754 &value) || value;
756 if (flag != (wwin->flags.maximized!=0)) {
758 if (flag)
759 wMaximizeWindow(wwin, flag*(MAX_VERTICAL|MAX_HORIZONTAL));
760 else
761 wUnmaximizeWindow(wwin);
763 } else if (event->atom == _XA_KWM_WIN_ICONIFIED) {
765 #ifdef DEBUG1
766 printf("got KDE iconify change\n");
767 #endif
768 flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED,
769 &value) || value;
771 if (flag != wwin->flags.miniaturized) {
773 if (flag)
774 wIconifyWindow(wwin);
775 else
776 wDeiconifyWindow(wwin);
779 } else if (event->atom == _XA_KWM_WIN_DECORATION) {
780 Bool refresh = False;
781 int oldnofocus;
783 #ifdef DEBUG1
784 printf("got KDE decoration change\n");
785 #endif
787 oldnofocus = wwin->client_flags.no_focusable;
789 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &value)) {
790 wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
792 switch (value & ~KWMnoFocus) {
793 case KWMnoDecoration:
794 if (!WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
795 refresh = True;
797 wwin->client_flags.no_titlebar = 1;
798 wwin->client_flags.no_resizebar = 1;
799 break;
801 case KWMtinyDecoration:
802 if (WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
803 refresh = True;
805 wwin->client_flags.no_titlebar = 0;
806 wwin->client_flags.no_resizebar = 1;
807 break;
809 case KWMnormalDecoration:
810 default:
811 if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
812 refresh = True;
814 wwin->client_flags.no_titlebar = 0;
815 wwin->client_flags.no_resizebar = 0;
816 break;
818 } else {
819 if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
820 refresh = True;
821 wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
822 wwin->client_flags.no_titlebar = 0;
823 wwin->client_flags.no_resizebar = 0;
826 if (refresh)
827 wWindowConfigureBorders(wwin);
829 if (wwin->client_flags.no_focusable && !oldnofocus) {
831 sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_REMOVE,
832 wwin, 0);
833 wwin->flags.kwm_hidden_for_modules = 1;
835 } else if (!wwin->client_flags.no_focusable && oldnofocus) {
837 if (wwin->flags.kwm_hidden_for_modules) {
838 sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_ADD,
839 wwin, 0);
840 wwin->flags.kwm_hidden_for_modules = 0;
843 } else if (event->atom == _XA_KWM_WIN_DESKTOP && wwin->frame) {
844 #ifdef DEBUG1
845 printf("got KDE workspace change for %s\n", wwin->frame->title);
846 #endif
847 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &value)
848 && value-1 != wwin->frame->workspace) {
849 wWindowChangeWorkspace(wwin, value-1);
852 } else if (event->atom == _XA_KWM_WIN_GEOMETRY_RESTORE) {
853 WArea area;
855 #ifdef DEBUG1
856 printf("got KDE geometry restore change\n");
857 #endif
858 if (getAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, &area)
859 && (wwin->old_geometry.x != area.x1
860 || wwin->old_geometry.y != area.y1
861 || wwin->old_geometry.width != area.x2 - area.x1
862 || wwin->old_geometry.height != area.y2 - area.y1)) {
864 wwin->old_geometry.x = area.x1;
865 wwin->old_geometry.y = area.y1;
866 wwin->old_geometry.width = area.x2 - area.x1;
867 wwin->old_geometry.height = area.y2 - area.y1;
869 } else {
870 processed = False;
873 return processed;
877 static Bool
878 performWindowCommand(WScreen *scr, char *command)
880 WWindow *wwin = NULL;
883 wwin = scr->focused_window;
884 if (!wwin || !wwin->flags.focused || !wwin->flags.mapped) {
885 wwin = NULL;
888 CloseWindowMenu(scr);
891 if (strcmp(command, "winMove")==0 || strcmp(command, "winResize")==0) {
893 if (wwin)
894 wKeyboardMoveResizeWindow(wwin);
896 } else if (strcmp(command, "winMaximize")==0) {
898 if (wwin)
899 wMaximizeWindow(wwin, MAX_VERTICAL|MAX_HORIZONTAL);
901 } else if (strcmp(command, "winRestore")==0) {
903 if (wwin && wwin->flags.maximized)
904 wUnmaximizeWindow(wwin);
906 } else if (strcmp(command, "winIconify")==0) {
909 if (wwin && !WFLAGP(wwin, no_miniaturizable)) {
910 if (wwin->protocols.MINIATURIZE_WINDOW)
911 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
912 LastTimestamp);
913 else {
914 wIconifyWindow(wwin);
918 } else if (strcmp(command, "winClose")==0) {
920 if (wwin && !WFLAGP(wwin, no_closable)) {
921 if (wwin->protocols.DELETE_WINDOW)
922 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
925 } else if (strcmp(command, "winSticky")==0) {
927 if (wwin) {
928 wwin->client_flags.omnipresent ^= 1;
929 UpdateSwitchMenu(scr, wwin, ACTION_CHANGE_WORKSPACE);
932 } else if (strcmp(command, "winShade")==0) {
934 if (wwin && !WFLAGP(wwin, no_shadeable)) {
935 if (wwin->flags.shaded)
936 wUnshadeWindow(wwin);
937 else
938 wShadeWindow(wwin);
941 } else if (strcmp(command, "winOperation")==0) {
943 if (wwin)
944 OpenWindowMenu(wwin, wwin->frame_x,
945 wwin->frame_y+wwin->frame->top_width, True);
947 } else {
948 return False;
951 return True;
955 static void
956 performCommand(WScreen *scr, char *command, XClientMessageEvent *event)
958 assert(scr != NULL);
960 if (strcmp(command, "commandLine")==0
961 || strcmp(command, "execute")==0) {
962 char *cmd;
964 cmd = ExpandOptions(scr, _("%a(Run Command,Type the command to run"));
965 if (cmd) {
966 ExecuteShellCommand(scr, cmd);
967 free(cmd);
969 } else if (strcmp(command, "logout")==0) {
971 Shutdown(WSLogoutMode);
973 } else if (strcmp(command, "refreshScreen")==0) {
975 wRefreshDesktop(scr);
977 } else if (strncmp(command, "go:", 3)==0) {
979 Shutdown(WSRestartPreparationMode);
980 Restart(&command[3]);
982 } else if (strcmp(command, "desktop+1")==0) {
984 wWorkspaceRelativeChange(scr, 1);
986 } else if (strcmp(command, "desktop-1")==0) {
988 wWorkspaceRelativeChange(scr, -1);
990 } else if (strcmp(command, "desktop+2")==0) {
992 wWorkspaceRelativeChange(scr, 2);
994 } else if (strcmp(command, "desktop-2")==0) {
996 wWorkspaceRelativeChange(scr, -2);
998 } else if (strcmp(command, "desktop%%2")==0) {
1000 if (scr->current_workspace % 2 == 1)
1001 wWorkspaceRelativeChange(scr, 1);
1002 else
1003 wWorkspaceRelativeChange(scr, -1);
1004 } else if (strncmp(command, "desktop", 7)==0) {
1005 int ws;
1007 ws = atoi(&command[7]);
1008 wWorkspaceChange(scr, ws);
1010 /* wmaker specific stuff */
1011 } else if (strcmp(command, "wmaker:info")==0) {
1013 wShowInfoPanel(scr);
1015 } else if (strcmp(command, "wmaker:legal")==0) {
1017 wShowLegalPanel(scr);
1019 } else if (strcmp(command, "wmaker:arrangeIcons")==0) {
1021 wArrangeIcons(scr, True);
1023 } else if (strcmp(command, "wmaker:showAll")==0) {
1025 wShowAllWindows(scr);
1027 } else if (strcmp(command, "wmaker:hideOthers")==0) {
1029 wHideOtherApplications(scr->focused_window);
1031 } else if (strcmp(command, "wmaker:restart")==0) {
1033 Shutdown(WSRestartPreparationMode);
1034 Restart(NULL);
1036 } else if (strcmp(command, "wmaker:exit")==0) {
1038 Shutdown(WSExitMode);
1040 #ifdef UNSUPPORTED_STUFF
1041 } else if (strcmp(command, "moduleRaised")==0) { /* useless */
1042 } else if (strcmp(command, "deskUnclutter")==0) {
1043 } else if (strcmp(command, "deskCascade")==0) {
1044 } else if (strcmp(command, "configure")==0) { /* useless */
1045 } else if (strcmp(command, "taskManager")==0) {
1046 } else if (strcmp(command, "darkenScreen")==0) { /* breaks consistency */
1047 #endif
1048 } else if (!performWindowCommand(scr, command)) {
1049 KWMModuleList *module;
1050 long mask = 0;
1051 XEvent ev;
1052 /* do message relay thing */
1054 ev.xclient = *event;
1055 for (module = KWMModules; module != NULL; module = module->next) {
1057 ev.xclient.window = module->window;
1058 if (module->window == scr->root_win)
1059 mask = SubstructureRedirectMask;
1060 else
1061 mask = 0;
1063 XSendEvent(dpy, module->window, False, mask, &ev);
1069 Bool
1070 wKWMProcessClientMessage(XClientMessageEvent *event)
1072 Bool processed = True;
1073 WScreen *scr;
1074 #ifdef DEBUG1
1075 printf("CLIENT MESS %s\n", XGetAtomName(dpy, event->message_type));
1076 #endif
1077 if (event->message_type == _XA_KWM_COMMAND && event->format==8) {
1078 char buffer[24];
1079 int i;
1081 scr = wScreenForRootWindow(event->window);
1083 for (i=0; i<20; i++) {
1084 buffer[i] = event->data.b[i];
1086 buffer[i] = 0;
1088 #ifdef DEBUG1
1089 printf("got KDE command %s\n", buffer);
1090 #endif
1091 performCommand(scr, buffer, event);
1093 } else if (event->message_type == _XA_KWM_ACTIVATE_WINDOW) {
1094 WWindow *wwin;
1096 #ifdef DEBUG1
1097 printf("got KDE activate internal\n");
1098 #endif
1099 wwin = wWindowFor(event->data.l[0]);
1101 if (wwin)
1102 wSetFocusTo(wwin->screen_ptr, wwin);
1104 } else if (event->message_type == _XA_KWM_DO_NOT_MANAGE
1105 && event->format == 8) {
1106 KWMDoNotManageList *node;
1107 int i;
1109 #ifdef DEBUG1
1110 printf("got KDE dont manage\n");
1111 #endif
1113 node = malloc(sizeof(KWMDoNotManageList));
1114 if (!node) {
1115 wwarning("out of memory processing KWM_DO_NOT_MANAGE message");
1117 for (i=0; i<20 && event->data.b[i]; i++)
1118 node->title[i] = event->data.b[i];
1119 node->title[i] = 0;
1121 node->next = KWMDoNotManageCrap;
1122 KWMDoNotManageCrap = node;
1124 } else if (event->message_type == _XA_KWM_MODULE) {
1125 long val;
1126 Window modwin = event->data.l[0];
1128 scr = wScreenForRootWindow(event->window);
1130 if (getSimpleHint(modwin, _XA_KWM_MODULE, &val) && val) {
1131 #ifdef DEBUG1
1132 puts("got KDE module startup");
1133 #endif
1134 addModule(scr, modwin);
1135 } else {
1136 #ifdef DEBUG1
1137 puts("got KDE module finish");
1138 #endif
1139 removeModule(scr, modwin);
1141 } else {
1142 processed = False;
1145 return processed;
1149 void
1150 wKWMCheckModule(WScreen *scr, Window window)
1152 long val;
1154 if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val) {
1155 #ifdef DEBUG1
1156 puts("got KDE module startup");
1157 #endif
1158 addModule(scr, window);
1163 Bool
1164 wKWMCheckRootHintChange(WScreen *scr, XPropertyEvent *event)
1166 Bool processed = True;
1167 long value;
1169 if (event->atom == _XA_KWM_CURRENT_DESKTOP) {
1170 if (getSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP, &value)) {
1171 #ifdef DEBUG1
1172 printf("got KDE workspace switch to %li\n", value);
1173 #endif
1174 if (value-1 != scr->current_workspace) {
1175 wWorkspaceChange(scr, value-1);
1178 } else if (event->atom == _XA_KWM_NUMBER_OF_DESKTOPS) {
1179 #ifdef DEBUG1
1180 printf("got KDE workspace number change\n");
1181 #endif
1183 if (getSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS, &value)) {
1185 /* increasing is easy... */
1186 if (value > scr->workspace_count) {
1187 scr->flags.kwm_syncing_count = 1;
1189 wWorkspaceMake(scr, value - scr->workspace_count);
1191 scr->flags.kwm_syncing_count = 0;
1193 } else if (value < scr->workspace_count) {
1194 int i;
1195 Bool rebuild = False;
1197 scr->flags.kwm_syncing_count = 1;
1199 /* decrease all we can do */
1200 for (i = scr->workspace_count; i >= value; i--) {
1201 if (!wWorkspaceDelete(scr, i)) {
1202 rebuild = True;
1203 break;
1207 scr->flags.kwm_syncing_count = 0;
1209 /* someone destroyed a workspace that can't be destroyed.
1210 * Reset the hints to reflect our internal state.
1212 if (rebuild) {
1213 wKWMUpdateWorkspaceCountHint(scr);
1217 } else {
1218 int i;
1220 processed = False;
1222 for (i = 0; i < MAX_WORKSPACES; i++) {
1223 if (event->atom == _XA_KWM_DESKTOP_NAME_[i]) {
1224 char *name;
1226 name = wKWMGetWorkspaceName(scr, i);
1228 #ifdef DEBUG1
1229 printf("got KDE workspace name change to %s\n", name);
1230 #endif
1232 if (name && strncmp(name, scr->workspaces[i]->name,
1233 MAX_WORKSPACENAME_WIDTH)!=0) {
1234 scr->flags.kwm_syncing_name = 1;
1235 wWorkspaceRename(scr, i, name);
1236 scr->flags.kwm_syncing_name = 0;
1238 if (name)
1239 XFree(name);
1240 processed = True;
1241 break;
1242 } else if (event->atom == _XA_KWM_WINDOW_REGION_[i]) {
1243 WArea area;
1245 if (getAreaHint(scr->root_win, event->atom, &area)) {
1247 if (scr->totalUsableArea.x1 != area.x1
1248 || scr->totalUsableArea.y1 != area.y1
1249 || scr->totalUsableArea.x2 != area.x2
1250 || scr->totalUsableArea.y2 != area.y2) {
1251 wScreenUpdateUsableArea(scr);
1255 processed = True;
1256 break;
1261 return processed;
1265 Bool
1266 wKWMManageableClient(WScreen *scr, Window win, char *title)
1268 KWMDoNotManageList *ptr, *next;
1269 long val;
1271 if (getSimpleHint(win, _XA_KWM_DOCKWINDOW, &val) && val) {
1272 addDockWindow(scr, win);
1273 return False;
1276 ptr = KWMDoNotManageCrap;
1277 if (ptr && strncmp(ptr->title, title, strlen(ptr->title))==0) {
1278 next = ptr->next;
1279 free(ptr);
1280 KWMDoNotManageCrap = next;
1281 #ifdef DEBUG1
1282 printf("window %s not managed per KDE request\n", title);
1283 #endif
1285 sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
1286 sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
1288 return False;
1289 } else if (ptr) {
1290 while (ptr->next) {
1291 if (strncmp(ptr->next->title, title, strlen(ptr->next->title))==0) {
1292 #ifdef DEBUG1
1293 printf("window %s not managed per KDE request\n", title);
1294 #endif
1295 next = ptr->next->next;
1296 free(ptr->next);
1297 ptr->next = next;
1299 sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
1300 sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
1302 return False;
1305 ptr = ptr->next;
1309 return True;
1313 void
1314 wKWMUpdateCurrentWorkspaceHint(WScreen *scr)
1316 setSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP,
1317 scr->current_workspace+1);
1319 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_CHANGE, NULL,
1320 scr->current_workspace+1);
1324 void
1325 wKWMUpdateActiveWindowHint(WScreen *scr)
1327 long val;
1329 if (!scr->focused_window || !scr->focused_window->flags.focused)
1330 val = None;
1331 else
1332 val = (long)(scr->focused_window->client_win);
1334 XChangeProperty(dpy, scr->root_win, _XA_KWM_ACTIVE_WINDOW,
1335 _XA_KWM_ACTIVE_WINDOW, 32, PropModeReplace,
1336 (unsigned char*)&val, 1);
1337 XFlush(dpy);
1341 void
1342 wKWMUpdateWorkspaceCountHint(WScreen *scr)
1344 if (scr->flags.kwm_syncing_count)
1345 return;
1347 setSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS,
1348 scr->workspace_count);
1350 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE, NULL,
1351 scr->workspace_count);
1355 void
1356 wKWMCheckDestroy(XDestroyWindowEvent *event)
1358 WScreen *scr;
1360 if (event->event == event->window) {
1361 return;
1364 scr = wScreenForRootWindow(event->event);
1365 if (!scr) {
1366 return;
1369 removeModule(scr, event->window);
1370 removeDockWindow(scr, event->window);
1374 void
1375 wKWMUpdateWorkspaceNameHint(WScreen *scr, int workspace)
1377 char buffer[64];
1379 if (scr->flags.kwm_syncing_name)
1380 return;
1382 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
1384 if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
1385 sprintf(buffer, "KWM_DESKTOP_NAME_%d", workspace + 1);
1387 _XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
1390 XChangeProperty(dpy, scr->root_win, _XA_KWM_DESKTOP_NAME_[workspace],
1391 XA_STRING, 8, PropModeReplace,
1392 (unsigned char*)scr->workspaces[workspace]->name,
1393 strlen(scr->workspaces[workspace]->name)+1);
1395 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NAME_CHANGE, NULL, workspace+1);
1400 void
1401 wKWMUpdateClientWorkspace(WWindow *wwin)
1403 #ifdef DEBUG1
1404 printf("updating workspace of %s to %i\n",
1405 wwin->frame->title, wwin->frame->workspace+1);
1406 #endif
1407 setSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP,
1408 wwin->frame->workspace+1);
1412 void
1413 wKWMUpdateClientGeometryRestore(WWindow *wwin)
1415 WArea rect;
1417 rect.x1 = wwin->old_geometry.x;
1418 rect.y1 = wwin->old_geometry.y;
1419 rect.x2 = wwin->old_geometry.x + wwin->old_geometry.width;
1420 rect.y2 = wwin->old_geometry.y + wwin->old_geometry.height;
1422 setAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, rect);
1426 void
1427 wKWMUpdateClientState(WWindow *wwin, WKWMStateFlag flags)
1429 if (flags & KWMIconifiedFlag) {
1430 setSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED,
1431 wwin->flags.miniaturized /*|| wwin->flags.shaded
1432 || wwin->flags.hidden*/);
1434 if (flags & KWMStickyFlag) {
1435 setSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY,
1436 IS_OMNIPRESENT(wwin));
1438 if (flags & KWMMaximizedFlag) {
1439 setSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED,
1440 wwin->flags.maximized!=0);
1445 Bool
1446 wKWMGetUsableArea(WScreen *scr, WArea *area)
1448 char buffer[64];
1450 if (_XA_KWM_WINDOW_REGION_[0]==0) {
1451 sprintf(buffer, "KWM_WINDOW_REGION_%d", 1);
1453 _XA_KWM_WINDOW_REGION_[0] = XInternAtom(dpy, buffer, False);
1456 return getAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[0], area);
1460 void
1461 wKWMSetUsableAreaHint(WScreen *scr, int workspace)
1463 /* if we set this after making changes of our own to the area,
1464 * the next time the area changes, we won't know what should
1465 * be the new final area. This protocol isn't worth a shit :/
1467 #ifdef notdef
1468 char buffer[64];
1470 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
1472 if (_XA_KWM_WINDOW_REGION_[workspace]==0) {
1473 sprintf(buffer, "KWM_WINDOW_REGION_%d", workspace+1);
1475 _XA_KWM_WINDOW_REGION_[workspace] = XInternAtom(dpy, buffer, False);
1478 setAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[workspace],
1479 scr->totalUsableArea);
1480 #endif
1484 void
1485 wKWMSendEventMessage(WWindow *wwin, WKWMEventMessage message)
1487 Atom msg;
1489 switch (message) {
1490 case WKWMAddWindow:
1491 msg = _XA_KWM_MODULE_WIN_ADD;
1492 break;
1493 case WKWMRemoveWindow:
1494 msg = _XA_KWM_MODULE_WIN_REMOVE;
1495 break;
1496 case WKWMFocusWindow:
1497 msg = _XA_KWM_MODULE_WIN_ACTIVATE;
1498 break;
1499 case WKWMRaiseWindow:
1500 msg = _XA_KWM_MODULE_WIN_RAISE;
1501 break;
1502 case WKWMLowerWindow:
1503 msg = _XA_KWM_MODULE_WIN_LOWER;
1504 break;
1505 case WKWMChangedClient:
1506 msg = _XA_KWM_MODULE_WIN_CHANGE;
1507 break;
1508 case WKWMIconChange:
1509 msg = _XA_KWM_MODULE_WIN_ICON_CHANGE;
1510 break;
1511 default:
1512 return;
1515 sendToModules(wwin ? wwin->screen_ptr : NULL, msg, wwin, 0);
1519 #endif /* KWM_HINTS */