- Fixed crashing bug in menu.c
[wmaker-crm.git] / src / kwm.c
blobcb48b05ae87f10d540ff76d3729699cfdc30894f
1 /* kwm.c-- stuff for support for kwm hints
3 * Window Maker window manager
4 *
5 * Copyright (c) 1998-2003 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 * ================
28 * kfm icon selection from krootbgwm
30 * kwm.h function/method Notes
31 *----------------------------------------------------------------------------
32 * setUnsavedDataHint() currently, only gives visual clue that
33 * there is unsaved data (broken X close button)
34 * setSticky()
35 * setIcon() std X thing...
36 * setDecoration()
37 * logout()
38 * refreshScreen()
39 * setWmCommand() std X thing
40 * currentDesktop()
41 * setKWMModule()
43 * isKWMInitialized() not trustworthy
44 * activeWindow() dunno it's use, but since it's easy to
45 * implement it won't hurt to support
46 * switchToDesktop()
47 * (set/get)WindowRegion()
48 * (set)numberOfDesktops() KDE limits to 32, but wmaker is virtually
49 * unlimited. May raise some incompatibility
50 * in badly written KDE modules?
51 * (set/get)DesktopName()
52 * sendKWMCommand() also does the message relay thing
53 * desktop()
54 * geometryRestore()
55 * isIconified()
56 * isMaximized()
57 * isSticky()
58 * moveToDesktop() WARNING: evil mechanism
59 * setGeometryRestore() WARNING: evil mechanism
60 * setMaximize() woo hoo! wanna race?
61 * setIconify() BAH!: why reinvent the f'ing wheel!?
62 * its even broken!!!
63 * move() std X thing
64 * setGeometry() std X thing
65 * close() std X thing
66 * activate()
67 * activateInternal()
68 * raise() std X thing
69 * lower() std X thing
70 * prepareForSwallowing() std X thing
71 * doNotManage() klugy thing...
72 * getBlablablaString()
73 * setKWMDockModule() maybe we can make the Dock behave as the KDE
74 * dock, but must figure where to show the windows
75 * setDockWindow()
77 * Unsupported stuff (superfluous/not-essential/nonsense):
78 * =======================================================
80 * darkenScreen()
81 * setMiniIcon()
82 * configureWm()
83 * raiseSoundEvent()
84 * registerSoundEvent()
85 * unregisterSoundEvent()
86 * title()
87 * titleWithState()
88 * geometry() kde lib code makes it unnecessary
91 * Extensions to KDE:
92 * ==================
94 * These are clientmessage-type messages specific to Window Maker:
95 * wmaker:info - show info panel
96 * wmaker:legal - show legal panel
97 * wmaker:arrangeIcons - arrange icons
98 * wmaker:showAll - show all windows
99 * wmaker:hideOthers - hide others
100 * wmaker:restart - restart wmaker
101 * wmaker:exit - exit wmaker
105 * TODO
106 * different WORKAREA for each workspace
110 #include "wconfig.h"
112 #ifdef KWM_HINTS
114 #include <X11/Xlib.h>
115 #include <X11/Xutil.h>
116 #include <X11/Xatom.h>
118 #include <stdlib.h>
119 #include <stdio.h>
120 #include <string.h>
121 #include <unistd.h>
123 #include <sys/types.h>
124 #include <sys/socket.h>
125 #include <sys/un.h>
126 #include <signal.h>
129 #include "WindowMaker.h"
131 #include "screen.h"
132 #include "wcore.h"
133 #include "framewin.h"
134 #include "window.h"
135 #include "properties.h"
136 #include "icon.h"
137 #include "client.h"
138 #include "funcs.h"
139 #include "actions.h"
140 #include "workspace.h"
141 #include "dialog.h"
142 #include "stacking.h"
144 #include "kwm.h"
146 /*#define DEBUG1
148 /******* Global ******/
150 extern Time LastFocusChange;
151 extern Time LastTimestamp;
154 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
155 extern Atom _XA_WM_DELETE_WINDOW;
157 /** Local **/
159 static Atom _XA_KWM_COMMAND = 0;
160 static Atom _XA_KWM_ACTIVATE_WINDOW = 0;
161 static Atom _XA_KWM_ACTIVE_WINDOW = 0;
162 static Atom _XA_KWM_DO_NOT_MANAGE = 0;
163 static Atom _XA_KWM_DOCKWINDOW = 0;
164 static Atom _XA_KWM_RUNNING = 0;
166 static Atom _XA_KWM_MODULE = 0;
168 static Atom _XA_KWM_MODULE_INIT = 0;
169 static Atom _XA_KWM_MODULE_INITIALIZED = 0;
170 static Atom _XA_KWM_MODULE_DESKTOP_CHANGE = 0;
171 static Atom _XA_KWM_MODULE_DESKTOP_NAME_CHANGE = 0;
172 static Atom _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE = 0;
173 static Atom _XA_KWM_MODULE_WIN_ADD = 0;
174 static Atom _XA_KWM_MODULE_WIN_REMOVE = 0;
175 static Atom _XA_KWM_MODULE_WIN_CHANGE = 0;
176 static Atom _XA_KWM_MODULE_WIN_RAISE = 0;
177 static Atom _XA_KWM_MODULE_WIN_LOWER = 0;
178 static Atom _XA_KWM_MODULE_WIN_ACTIVATE = 0;
179 static Atom _XA_KWM_MODULE_WIN_ICON_CHANGE = 0;
180 static Atom _XA_KWM_MODULE_DOCKWIN_ADD = 0;
181 static Atom _XA_KWM_MODULE_DOCKWIN_REMOVE = 0;
183 static Atom _XA_KWM_WIN_UNSAVED_DATA = 0;
184 static Atom _XA_KWM_WIN_DECORATION = 0;
185 static Atom _XA_KWM_WIN_DESKTOP = 0;
186 static Atom _XA_KWM_WIN_GEOMETRY_RESTORE = 0;
187 static Atom _XA_KWM_WIN_ICONIFIED = 0;
188 static Atom _XA_KWM_WIN_MAXIMIZED = 0;
189 static Atom _XA_KWM_WIN_STICKY = 0;
191 static Atom _XA_KWM_WIN_ICON_GEOMETRY = 0;
193 static Atom _XA_KWM_CURRENT_DESKTOP = 0;
194 static Atom _XA_KWM_NUMBER_OF_DESKTOPS = 0;
195 static Atom _XA_KWM_DESKTOP_NAME_[MAX_WORKSPACES];
196 static Atom _XA_KWM_WINDOW_REGION_[MAX_WORKSPACES];
200 /* list of window titles that must not be managed */
201 typedef struct KWMDoNotManageList {
202 char title[20];
203 struct KWMDoNotManageList *next;
204 } KWMDoNotManageList;
206 static KWMDoNotManageList *KWMDoNotManageCrap = NULL;
209 /* list of KWM modules */
210 typedef struct KWMModuleList {
211 Window window;
212 struct KWMModuleList *next;
213 #ifdef DEBUG1
214 char *title;
215 #endif
216 } KWMModuleList;
218 static KWMModuleList *KWMModules = NULL;
220 static KWMModuleList *KWMDockWindows = NULL;
222 /* window decoration types */
223 enum {
224 KWMnoDecoration = 0,
225 KWMnormalDecoration = 1,
226 KWMtinyDecoration = 2,
227 KWMnoFocus = 256,
228 KWMstandaloneMenuBar = 512,
229 KWMdesktopIcon = 1024,
230 KWMstaysOnTop = 2048
235 static void observer(void *self, WMNotification *notif);
236 static void wsobserver(void *self, WMNotification *notif);
240 static Bool
241 getSimpleHint(Window win, Atom atom, long *retval)
243 long *data = 0;
245 assert(atom!=0);
247 data = (long*)PropGetCheckProperty(win, atom, atom, 32, 1, NULL);
249 if (!data)
250 return False;
252 *retval = *data;
254 XFree(data);
256 return True;
261 static void
262 setSimpleHint(Window win, Atom atom, long value)
264 assert(atom!=0);
265 XChangeProperty(dpy, win, atom, atom,
266 32, PropModeReplace, (unsigned char*)&value, 1);
270 static void
271 sendClientMessage(WScreen *scr, Window window, Atom atom, long value)
273 XEvent event;
274 long mask = 0;
276 assert(atom!=0);
278 memset(&event, 0, sizeof(XEvent));
279 event.xclient.type = ClientMessage;
280 event.xclient.message_type = atom;
281 event.xclient.window = window;
282 event.xclient.format = 32;
283 event.xclient.data.l[0] = value;
284 event.xclient.data.l[1] = LastTimestamp;
286 if (scr && scr->root_win == window)
287 mask = SubstructureRedirectMask;
289 XSendEvent(dpy, window, False, mask, &event);
293 static void
294 sendTextMessage(WScreen *scr, Window window, Atom atom, char *text)
296 XEvent event;
297 long mask = 0;
298 int i;
300 assert(atom!=0);
302 memset(&event, 0, sizeof(XEvent));
303 event.xclient.type = ClientMessage;
304 event.xclient.message_type = atom;
305 event.xclient.window = window;
306 event.xclient.format = 8;
308 for (i=0; i<20 && text[i]; i++)
309 event.xclient.data.b[i] = text[i];
311 if (scr && scr->root_win == window)
312 mask = SubstructureRedirectMask;
314 XSendEvent(dpy, window, False, mask, &event);
318 static Bool
319 getAreaHint(Window win, Atom atom, WArea *area)
321 long *data = 0;
323 data = (long*)PropGetCheckProperty(win, atom, atom, 32, 4, NULL);
325 if (!data)
326 return False;
328 area->x1 = data[0];
329 area->y1 = data[1];
330 area->x2 = data[2] + area->x1;
331 area->y2 = data[3] + area->y1;
333 XFree(data);
335 return True;
339 static void
340 setAreaHint(Window win, Atom atom, WArea area)
342 long value[4];
344 assert(atom!=0);
345 value[0] = area.x1;
346 value[1] = area.y1;
347 value[2] = area.x2 - area.x1;
348 value[3] = area.y2 - area.y1;
349 XChangeProperty(dpy, win, atom, atom, 32, PropModeReplace,
350 (unsigned char*)&value, 4);
354 static void
355 addModule(WScreen *scr, Window window)
357 KWMModuleList *node;
358 long val;
359 WWindow *ptr;
361 node = malloc(sizeof(KWMModuleList));
362 if (!node) {
363 wwarning("out of memory while registering KDE module");
364 return;
367 node->next = KWMModules;
368 node->window = window;
369 KWMModules = node;
371 sendClientMessage(scr, window, _XA_KWM_MODULE_INIT, 0);
373 if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val==2) {
374 if (scr->kwm_dock != None) {
375 setSimpleHint(window, _XA_KWM_MODULE, 1);
376 } else {
377 KWMModuleList *ptr;
379 scr->kwm_dock = window;
381 for (ptr = KWMDockWindows; ptr!=NULL; ptr = ptr->next) {
382 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
383 ptr->window);
388 /* send list of windows */
389 for (ptr = scr->focused_window; ptr!=NULL; ptr = ptr->prev) {
390 if (!ptr->flags.kwm_hidden_for_modules
391 && !WFLAGP(ptr, skip_window_list)) {
392 sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ADD,
393 ptr->client_win);
397 /* send window stacking order */
398 wKWMSendStacking(scr, window);
400 /* send focused window */
401 if (scr->focused_window && scr->focused_window->flags.focused) {
402 sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ACTIVATE,
403 scr->focused_window->client_win);
406 /* tell who we are */
407 sendTextMessage(scr, window, _XA_KWM_COMMAND, "wm:wmaker");
410 sendClientMessage(scr, window, _XA_KWM_MODULE_INITIALIZED, 0);
411 #ifdef DEBUG1
412 KWMModules->title = NULL;
413 XFetchName(dpy, window, &KWMModules->title);
414 printf("NEW MODULE %s\n", KWMModules->title);
415 #endif
419 static void
420 removeModule(WScreen *scr, Window window)
422 KWMModuleList *next;
424 if (!KWMModules) {
425 return;
428 if (KWMModules->window == window) {
429 next = KWMModules->next;
430 #ifdef DEBUG1
431 printf("REMOVING MODULE %s\n", KWMModules->title);
432 if (KWMModules->title)
433 XFree(KWMModules->title);
434 #endif
435 wfree(KWMModules);
436 KWMModules = next;
437 } else {
438 KWMModuleList *ptr;
440 ptr = KWMModules;
441 while (ptr->next) {
442 if (ptr->next->window == window) {
443 next = ptr->next->next;
444 #ifdef DEBUG1
445 printf("REMOVING MODULE %s\n", ptr->next->title);
446 if (ptr->next->title)
447 XFree(ptr->next->title);
448 #endif
449 wfree(ptr->next);
450 ptr->next->next = next;
451 break;
453 ptr->next = ptr->next->next;
457 if (scr->kwm_dock == window)
458 scr->kwm_dock = None;
463 static void
464 addDockWindow(WScreen *scr, Window window)
466 KWMModuleList *ptr;
468 for (ptr = KWMDockWindows; ptr != NULL; ptr = ptr->next) {
469 if (ptr->window == window)
470 break;
472 if (!ptr) {
473 KWMModuleList *node;
475 node = malloc(sizeof(KWMModuleList));
476 if (!node) {
477 wwarning("out of memory while processing KDE dock window");
478 return;
480 node->next = KWMDockWindows;
481 KWMDockWindows = node;
482 node->window = window;
483 XSelectInput(dpy, window, StructureNotifyMask);
485 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
486 window);
491 static void
492 removeDockWindow(WScreen *scr, Window window)
494 if (!KWMDockWindows)
495 return;
497 if (KWMDockWindows->window == window) {
498 KWMModuleList *next;
500 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_REMOVE,
501 window);
503 next = KWMDockWindows->next;
504 wfree(KWMDockWindows);
505 KWMDockWindows = next;
507 } else {
508 KWMModuleList *ptr, *next;
510 ptr = KWMDockWindows;
511 while (ptr->next) {
512 if (ptr->next->window == window) {
513 sendClientMessage(scr, scr->kwm_dock,
514 _XA_KWM_MODULE_DOCKWIN_REMOVE, window);
515 next = ptr->next->next;
516 wfree(ptr->next);
517 ptr->next = next;
518 return;
520 ptr = ptr->next;
526 static void
527 sendToModules(WScreen *scr, Atom atom, WWindow *wwin, long data)
529 KWMModuleList *ptr;
530 XEvent event;
531 long mask;
533 if (wwin) {
534 if (wwin->flags.kwm_hidden_for_modules
535 || WFLAGP(wwin, skip_window_list))
536 return;
537 data = wwin->client_win;
539 #ifdef DEBUG1
540 printf("notifying %s\n",XGetAtomName(dpy, atom));
541 #endif
542 memset(&event, 0, sizeof(XEvent));
543 event.xclient.type = ClientMessage;
544 event.xclient.message_type = atom;
545 event.xclient.format = 32;
546 event.xclient.data.l[1] = LastTimestamp;
548 mask = 0;
549 if (scr && scr->root_win == data)
550 mask = SubstructureRedirectMask;
552 for (ptr = KWMModules; ptr!=NULL; ptr = ptr->next) {
553 event.xclient.window = ptr->window;
554 event.xclient.data.l[0] = data;
555 XSendEvent(dpy, ptr->window, False, mask, &event);
560 void
561 wKWMInitStuff(WScreen *scr)
563 if (!_XA_KWM_WIN_STICKY) {
564 _XA_KWM_WIN_UNSAVED_DATA = XInternAtom(dpy, "KWM_WIN_UNSAVED_DATA",
565 False);
567 _XA_KWM_WIN_DECORATION = XInternAtom(dpy, "KWM_WIN_DECORATION", False);
569 _XA_KWM_WIN_DESKTOP = XInternAtom(dpy, "KWM_WIN_DESKTOP", False);
571 _XA_KWM_WIN_GEOMETRY_RESTORE = XInternAtom(dpy,
572 "KWM_WIN_GEOMETRY_RESTORE",
573 False);
575 _XA_KWM_WIN_STICKY = XInternAtom(dpy, "KWM_WIN_STICKY", False);
577 _XA_KWM_WIN_ICONIFIED = XInternAtom(dpy, "KWM_WIN_ICONIFIED", False);
579 _XA_KWM_WIN_MAXIMIZED = XInternAtom(dpy, "KWM_WIN_MAXIMIZED", False);
581 _XA_KWM_WIN_ICON_GEOMETRY = XInternAtom(dpy, "KWM_WIN_ICON_GEOMETRY",
582 False);
584 _XA_KWM_COMMAND = XInternAtom(dpy, "KWM_COMMAND", False);
586 _XA_KWM_ACTIVE_WINDOW = XInternAtom(dpy, "KWM_ACTIVE_WINDOW", False);
588 _XA_KWM_ACTIVATE_WINDOW = XInternAtom(dpy, "KWM_ACTIVATE_WINDOW",
589 False);
591 _XA_KWM_DO_NOT_MANAGE = XInternAtom(dpy, "KWM_DO_NOT_MANAGE", False);
593 _XA_KWM_CURRENT_DESKTOP = XInternAtom(dpy, "KWM_CURRENT_DESKTOP",
594 False);
596 _XA_KWM_NUMBER_OF_DESKTOPS = XInternAtom(dpy, "KWM_NUMBER_OF_DESKTOPS",
597 False);
599 _XA_KWM_DOCKWINDOW = XInternAtom(dpy, "KWM_DOCKWINDOW", False);
601 _XA_KWM_RUNNING = XInternAtom(dpy, "KWM_RUNNING", False);
603 _XA_KWM_MODULE = XInternAtom(dpy, "KWM_MODULE", False);
605 _XA_KWM_MODULE_INIT = XInternAtom(dpy, "KWM_MODULE_INIT", False);
606 _XA_KWM_MODULE_INITIALIZED = XInternAtom(dpy, "KWM_MODULE_INITIALIZED", False);
608 /* dunno what these do, but Matthias' patch contains it... */
609 _XA_KWM_MODULE_DESKTOP_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_CHANGE", False);
610 _XA_KWM_MODULE_DESKTOP_NAME_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NAME_CHANGE", False);
611 _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NUMBER_CHANGE", False);
613 _XA_KWM_MODULE_WIN_ADD = XInternAtom(dpy, "KWM_MODULE_WIN_ADD", False);
614 _XA_KWM_MODULE_WIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_WIN_REMOVE", False);
615 _XA_KWM_MODULE_WIN_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_CHANGE", False);
616 _XA_KWM_MODULE_WIN_RAISE = XInternAtom(dpy, "KWM_MODULE_WIN_RAISE", False);
617 _XA_KWM_MODULE_WIN_LOWER = XInternAtom(dpy, "KWM_MODULE_WIN_LOWER", False);
618 _XA_KWM_MODULE_WIN_ACTIVATE = XInternAtom(dpy, "KWM_MODULE_WIN_ACTIVATE", False);
619 _XA_KWM_MODULE_WIN_ICON_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_ICON_CHANGE", False);
620 _XA_KWM_MODULE_DOCKWIN_ADD = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_ADD", False);
621 _XA_KWM_MODULE_DOCKWIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_REMOVE", False);
623 memset(_XA_KWM_WINDOW_REGION_, 0, sizeof(_XA_KWM_WINDOW_REGION_));
625 memset(_XA_KWM_DESKTOP_NAME_, 0, sizeof(_XA_KWM_DESKTOP_NAME_));
628 #define SETSTR(hint, str) {\
629 static Atom a = 0; if (!a) a = XInternAtom(dpy, #hint, False);\
630 XChangeProperty(dpy, scr->root_win, a, XA_STRING, 8, PropModeReplace,\
631 (unsigned char*)str, strlen(str));}
633 SETSTR(KWM_STRING_MAXIMIZE, _("Maximize"));
634 SETSTR(KWM_STRING_UNMAXIMIZE, _("Unmaximize"));
635 SETSTR(KWM_STRING_ICONIFY, _("Miniaturize"));
636 SETSTR(KWM_STRING_UNICONIFY, _("Deminiaturize"));
637 SETSTR(KWM_STRING_STICKY, _("Omnipresent"));
638 SETSTR(KWM_STRING_UNSTICKY, _("Not Omnipresent"));
639 SETSTR(KWM_STRING_STRING_MOVE, _("Move"));
640 SETSTR(KWM_STRING_STRING_RESIZE, _("Resize"));
641 SETSTR(KWM_STRING_CLOSE, _("Close"));
642 SETSTR(KWM_STRING_TODESKTOP, _("Move To"));
643 SETSTR(KWM_STRING_ONTOCURRENTDESKTOP, _("Bring Here"));
644 #undef SETSTR
646 /* catch any notifications from any objects */
648 WMAddNotificationObserver(observer, scr, WMNManaged, NULL);
649 WMAddNotificationObserver(observer, scr, WMNUnmanaged, NULL);
650 WMAddNotificationObserver(observer, scr, WMNChangedWorkspace, NULL);
651 WMAddNotificationObserver(observer, scr, WMNChangedState, NULL);
652 WMAddNotificationObserver(observer, scr, WMNChangedFocus, NULL);
653 WMAddNotificationObserver(observer, scr, WMNChangedStacking, NULL);
654 WMAddNotificationObserver(observer, scr, WMNChangedName, NULL);
656 WMAddNotificationObserver(wsobserver, scr, WMNWorkspaceCreated, NULL);
657 WMAddNotificationObserver(wsobserver, scr, WMNWorkspaceDestroyed, NULL);
658 WMAddNotificationObserver(wsobserver, scr, WMNWorkspaceChanged, NULL);
659 WMAddNotificationObserver(wsobserver, scr, WMNWorkspaceNameChanged, NULL);
661 WMAddNotificationObserver(wsobserver, scr, WMNResetStacking, NULL);
665 void
666 wKWMSendStacking(WScreen *scr, Window module)
668 WMBagIterator i;
669 WCoreWindow *core;
671 WM_ITERATE_BAG(scr->stacking_list, core, i) {
672 for (; core != NULL; core = core->stacking->under) {
673 WWindow *wwin;
675 wwin = wWindowFor(core->window);
676 if (wwin)
677 sendClientMessage(scr, module, _XA_KWM_MODULE_WIN_RAISE,
678 wwin->client_win);
684 void
685 wKWMBroadcastStacking(WScreen *scr)
687 KWMModuleList *ptr = KWMModules;
689 while (ptr) {
690 wKWMSendStacking(scr, ptr->window);
692 ptr = ptr->next;
697 char*
698 wKWMGetWorkspaceName(WScreen *scr, int workspace)
700 Atom type_ret;
701 int fmt_ret;
702 unsigned long nitems_ret;
703 unsigned long bytes_after_ret;
704 char *data = NULL, *tmp;
705 char buffer[64];
707 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
709 if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
710 snprintf(buffer, sizeof(buffer), "KWM_DESKTOP_NAME_%d", workspace + 1);
712 _XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
715 /* What do these people have against correctly using property types? */
716 if (XGetWindowProperty(dpy, scr->root_win,
717 _XA_KWM_DESKTOP_NAME_[workspace], 0, 128, False,
718 XA_STRING,
719 &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
720 (unsigned char**)&data)!=Success || !data)
721 return NULL;
723 tmp = wstrdup(data);
724 XFree(data);
726 return tmp;
730 void
731 wKWMSetInitializedHint(WScreen *scr)
733 setSimpleHint(scr->root_win, _XA_KWM_RUNNING, 1);
737 void
738 wKWMShutdown(WScreen *scr, Bool closeModules)
740 KWMModuleList *ptr;
742 XDeleteProperty(dpy, scr->root_win, _XA_KWM_RUNNING);
744 if (closeModules) {
745 for (ptr = KWMModules; ptr != NULL; ptr = ptr->next) {
746 XKillClient(dpy, ptr->window);
752 void
753 wKWMCheckClientHints(WWindow *wwin, int *layer, int *workspace)
755 long val;
757 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA, &val)
758 && val) {
760 wwin->client_flags.broken_close = 1;
762 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &val)) {
763 if (val & KWMnoFocus) {
764 wwin->client_flags.no_focusable = 1;
766 switch (val & ~KWMnoFocus) {
767 case KWMnoDecoration:
768 wwin->client_flags.no_titlebar = 1;
769 wwin->client_flags.no_resizebar = 1;
770 break;
771 case KWMtinyDecoration:
772 wwin->client_flags.no_resizebar = 1;
773 break;
774 case KWMstandaloneMenuBar:
775 wwin->client_flags.no_titlebar = 1;
776 wwin->client_flags.no_resizebar = 1;
777 wwin->client_flags.no_resizable = 1;
778 wwin->client_flags.skip_window_list = 1;
779 wwin->client_flags.no_hide_others = 1;
780 wwin->flags.kwm_menubar = 1;
781 *layer = WMMainMenuLevel;
782 break;
783 case KWMdesktopIcon:
784 *layer = WMDesktopLevel;
785 break;
786 case KWMstaysOnTop:
787 *layer = WMFloatingLevel;
788 break;
789 case KWMnormalDecoration:
790 default:
791 break;
794 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &val)) {
795 *workspace = val - 1;
800 void
801 wKWMCheckClientInitialState(WWindow *wwin)
803 long val;
804 WArea area;
806 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY, &val) && val) {
808 wwin->client_flags.omnipresent = 1;
810 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED, &val) && val) {
812 wwin->flags.miniaturized = 1;
814 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, &val)) {
815 if (val == 2)
816 wwin->flags.maximized = MAX_VERTICAL;
817 else if (val == 1)
818 wwin->flags.maximized = MAX_HORIZONTAL;
819 else if (val == 3)
820 wwin->flags.maximized = MAX_VERTICAL|MAX_HORIZONTAL;
822 if (getAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, &area)
823 && (wwin->old_geometry.x != area.x1
824 || wwin->old_geometry.y != area.y1
825 || wwin->old_geometry.width != area.x2 - area.x1
826 || wwin->old_geometry.height != area.y2 - area.y1)) {
828 wwin->old_geometry.x = area.x1;
829 wwin->old_geometry.y = area.y1;
830 wwin->old_geometry.width = area.x2 - area.x1;
831 wwin->old_geometry.height = area.y2 - area.y1;
836 Bool
837 wKWMCheckClientHintChange(WWindow *wwin, XPropertyEvent *event)
839 Bool processed = True;
840 Bool flag;
841 long value;
844 if (!wwin->frame) {
845 return False;
848 if (event->atom == _XA_KWM_WIN_UNSAVED_DATA) {
849 #ifdef DEBUG1
850 printf("got KDE unsaved data change\n");
851 #endif
853 flag = getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA,
854 &value) && value;
856 if (flag != wwin->client_flags.broken_close) {
857 wwin->client_flags.broken_close = flag;
858 if (wwin->frame)
859 wWindowUpdateButtonImages(wwin);
861 } else if (event->atom == _XA_KWM_WIN_STICKY) {
863 #ifdef DEBUG1
864 printf("got KDE sticky change\n");
865 #endif
866 flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY,
867 &value) || value;
869 if (flag != wwin->client_flags.omnipresent) {
871 wWindowSetOmnipresent(wwin, flag);
873 } else if (event->atom == _XA_KWM_WIN_MAXIMIZED) {
874 int bla = 0;
876 #ifdef DEBUG1
877 printf("got KDE maximize change\n");
878 #endif
879 flag = getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, &value);
881 if (flag) {
882 if (value == 3)
883 bla = MAX_VERTICAL|MAX_HORIZONTAL;
884 else if (value == 2)
885 bla = MAX_VERTICAL;
886 else if (value == 1)
887 bla = MAX_HORIZONTAL;
890 if (bla != wwin->flags.maximized) {
891 if (bla != 0)
892 wMaximizeWindow(wwin, bla);
893 else
894 wUnmaximizeWindow(wwin);
896 } else if (event->atom == _XA_KWM_WIN_ICONIFIED) {
898 #ifdef DEBUG1
899 printf("got KDE iconify change\n");
900 #endif
901 flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED,
902 &value) || value;
904 if (flag != wwin->flags.miniaturized) {
906 if (flag)
907 wIconifyWindow(wwin);
908 else
909 wDeiconifyWindow(wwin);
912 } else if (event->atom == _XA_KWM_WIN_DECORATION) {
913 Bool refresh = False;
914 int oldnofocus;
916 #ifdef DEBUG1
917 printf("got KDE decoration change\n");
918 #endif
920 oldnofocus = wwin->client_flags.no_focusable;
922 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &value)) {
923 wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
925 switch (value & ~KWMnoFocus) {
926 case KWMnoDecoration:
927 if (!WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
928 refresh = True;
930 wwin->client_flags.no_titlebar = 1;
931 wwin->client_flags.no_resizebar = 1;
932 break;
934 case KWMtinyDecoration:
935 if (WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
936 refresh = True;
938 wwin->client_flags.no_titlebar = 0;
939 wwin->client_flags.no_resizebar = 1;
940 break;
942 case KWMnormalDecoration:
943 default:
944 if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
945 refresh = True;
947 wwin->client_flags.no_titlebar = 0;
948 wwin->client_flags.no_resizebar = 0;
949 break;
951 } else {
952 if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
953 refresh = True;
954 wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
955 wwin->client_flags.no_titlebar = 0;
956 wwin->client_flags.no_resizebar = 0;
959 if (refresh)
960 wWindowConfigureBorders(wwin);
962 if (wwin->client_flags.no_focusable && !oldnofocus) {
964 sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_REMOVE,
965 wwin, 0);
966 wwin->flags.kwm_hidden_for_modules = 1;
968 } else if (!wwin->client_flags.no_focusable && oldnofocus) {
970 if (wwin->flags.kwm_hidden_for_modules) {
971 sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_ADD,
972 wwin, 0);
973 wwin->flags.kwm_hidden_for_modules = 0;
976 } else if (event->atom == _XA_KWM_WIN_DESKTOP && wwin->frame) {
977 #ifdef DEBUG1
978 printf("got KDE workspace change for %s\n", wwin->frame->title);
979 #endif
980 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &value)
981 && value-1 != wwin->frame->workspace) {
982 wWindowChangeWorkspace(wwin, value-1);
985 } else if (event->atom == _XA_KWM_WIN_GEOMETRY_RESTORE) {
986 WArea area;
988 #ifdef DEBUG1
989 printf("got KDE geometry restore change\n");
990 #endif
991 if (getAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, &area)
992 && (wwin->old_geometry.x != area.x1
993 || wwin->old_geometry.y != area.y1
994 || wwin->old_geometry.width != area.x2 - area.x1
995 || wwin->old_geometry.height != area.y2 - area.y1)) {
997 wwin->old_geometry.x = area.x1;
998 wwin->old_geometry.y = area.y1;
999 wwin->old_geometry.width = area.x2 - area.x1;
1000 wwin->old_geometry.height = area.y2 - area.y1;
1002 } else {
1003 processed = False;
1006 return processed;
1010 static Bool
1011 performWindowCommand(WScreen *scr, char *command)
1013 WWindow *wwin = NULL;
1016 wwin = scr->focused_window;
1017 if (!wwin || !wwin->flags.focused || !wwin->flags.mapped) {
1018 wwin = NULL;
1021 CloseWindowMenu(scr);
1024 if (strcmp(command, "winMove")==0 || strcmp(command, "winResize")==0) {
1026 if (wwin)
1027 wKeyboardMoveResizeWindow(wwin);
1029 } else if (strcmp(command, "winMaximize")==0) {
1031 if (wwin)
1032 wMaximizeWindow(wwin, MAX_VERTICAL|MAX_HORIZONTAL);
1034 } else if (strcmp(command, "winRestore")==0) {
1036 if (wwin && wwin->flags.maximized)
1037 wUnmaximizeWindow(wwin);
1039 } else if (strcmp(command, "winIconify")==0) {
1042 if (wwin && !WFLAGP(wwin, no_miniaturizable)) {
1043 if (wwin->protocols.MINIATURIZE_WINDOW)
1044 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
1045 LastTimestamp);
1046 else {
1047 wIconifyWindow(wwin);
1051 } else if (strcmp(command, "winClose")==0) {
1053 if (wwin && !WFLAGP(wwin, no_closable)) {
1054 if (wwin->protocols.DELETE_WINDOW)
1055 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
1058 } else if (strcmp(command, "winSticky")==0) {
1060 if (wwin) {
1061 wWindowSetOmnipresent(wwin, !wwin->client_flags.omnipresent);
1064 } else if (strcmp(command, "winShade")==0) {
1066 if (wwin && !WFLAGP(wwin, no_shadeable)) {
1067 if (wwin->flags.shaded)
1068 wUnshadeWindow(wwin);
1069 else
1070 wShadeWindow(wwin);
1073 } else if (strcmp(command, "winOperation")==0) {
1075 if (wwin)
1076 OpenWindowMenu(wwin, wwin->frame_x,
1077 wwin->frame_y+wwin->frame->top_width, True);
1079 } else {
1080 return False;
1083 return True;
1087 static void
1088 performCommand(WScreen *scr, char *command, XClientMessageEvent *event)
1090 assert(scr != NULL);
1092 if (strcmp(command, "commandLine")==0
1093 || strcmp(command, "execute")==0) {
1094 char *cmd;
1096 cmd = ExpandOptions(scr, _("%a(Run Command,Type the command to run:)"));
1097 if (cmd) {
1098 ExecuteShellCommand(scr, cmd);
1099 wfree(cmd);
1101 } else if (strcmp(command, "logout")==0) {
1103 Shutdown(WSLogoutMode);
1105 } else if (strcmp(command, "refreshScreen")==0) {
1107 wRefreshDesktop(scr);
1109 } else if (strncmp(command, "go:", 3)==0) {
1111 Shutdown(WSRestartPreparationMode);
1112 Restart(&command[3], False);
1113 Restart(NULL, True);
1115 } else if (strcmp(command, "desktop+1")==0) {
1117 wWorkspaceRelativeChange(scr, 1);
1119 } else if (strcmp(command, "desktop-1")==0) {
1121 wWorkspaceRelativeChange(scr, -1);
1123 } else if (strcmp(command, "desktop+2")==0) {
1125 wWorkspaceRelativeChange(scr, 2);
1127 } else if (strcmp(command, "desktop-2")==0) {
1129 wWorkspaceRelativeChange(scr, -2);
1131 } else if (strcmp(command, "desktop%%2")==0) {
1133 if (scr->current_workspace % 2 == 1)
1134 wWorkspaceRelativeChange(scr, 1);
1135 else
1136 wWorkspaceRelativeChange(scr, -1);
1137 } else if (strncmp(command, "desktop", 7)==0) {
1138 int ws;
1140 ws = atoi(&command[7]);
1141 wWorkspaceChange(scr, ws);
1143 /* wmaker specific stuff */
1144 } else if (strcmp(command, "wmaker:info")==0) {
1146 wShowInfoPanel(scr);
1148 } else if (strcmp(command, "wmaker:legal")==0) {
1150 wShowLegalPanel(scr);
1152 } else if (strcmp(command, "wmaker:arrangeIcons")==0) {
1154 wArrangeIcons(scr, True);
1156 } else if (strcmp(command, "wmaker:showAll")==0) {
1158 wShowAllWindows(scr);
1160 } else if (strcmp(command, "wmaker:hideOthers")==0) {
1162 wHideOtherApplications(scr->focused_window);
1164 } else if (strcmp(command, "wmaker:restart")==0) {
1166 Shutdown(WSRestartPreparationMode);
1167 Restart(NULL, True);
1169 } else if (strcmp(command, "wmaker:exit")==0) {
1171 Shutdown(WSExitMode);
1173 #ifdef UNSUPPORTED_STUFF
1174 } else if (strcmp(command, "moduleRaised")==0) { /* useless */
1175 } else if (strcmp(command, "deskUnclutter")==0) {
1176 } else if (strcmp(command, "deskCascade")==0) {
1177 } else if (strcmp(command, "configure")==0) {
1178 } else if (strcmp(command, "taskManager")==0) {
1179 } else if (strcmp(command, "darkenScreen")==0) { /* breaks consistency */
1180 #endif
1181 } else if (!performWindowCommand(scr, command)) {
1182 KWMModuleList *module;
1183 long mask = 0;
1184 XEvent ev;
1185 /* do message relay thing */
1187 ev.xclient = *event;
1188 for (module = KWMModules; module != NULL; module = module->next) {
1190 ev.xclient.window = module->window;
1191 if (module->window == scr->root_win)
1192 mask = SubstructureRedirectMask;
1193 else
1194 mask = 0;
1196 XSendEvent(dpy, module->window, False, mask, &ev);
1202 Bool
1203 wKWMProcessClientMessage(XClientMessageEvent *event)
1205 Bool processed = True;
1206 WScreen *scr;
1207 #ifdef DEBUG1
1208 printf("CLIENT MESS %s\n", XGetAtomName(dpy, event->message_type));
1209 #endif
1210 if (event->message_type == _XA_KWM_COMMAND && event->format==8) {
1211 char buffer[24];
1212 int i;
1214 scr = wScreenForRootWindow(event->window);
1216 for (i=0; i<20; i++) {
1217 buffer[i] = event->data.b[i];
1219 buffer[i] = 0;
1221 #ifdef DEBUG1
1222 printf("got KDE command %s\n", buffer);
1223 #endif
1224 performCommand(scr, buffer, event);
1226 } else if (event->message_type == _XA_KWM_ACTIVATE_WINDOW) {
1227 WWindow *wwin;
1229 #ifdef DEBUG1
1230 printf("got KDE activate internal\n");
1231 #endif
1232 wwin = wWindowFor(event->data.l[0]);
1234 if (wwin)
1235 wSetFocusTo(wwin->screen_ptr, wwin);
1237 } else if (event->message_type == _XA_KWM_DO_NOT_MANAGE
1238 && event->format == 8) {
1239 KWMDoNotManageList *node;
1240 int i;
1242 #ifdef DEBUG1
1243 printf("got KDE dont manage\n");
1244 #endif
1246 node = malloc(sizeof(KWMDoNotManageList));
1247 if (!node) {
1248 wwarning("out of memory processing KWM_DO_NOT_MANAGE message");
1250 for (i=0; i<20 && event->data.b[i]; i++)
1251 node->title[i] = event->data.b[i];
1252 node->title[i] = 0;
1254 node->next = KWMDoNotManageCrap;
1255 KWMDoNotManageCrap = node;
1257 } else if (event->message_type == _XA_KWM_MODULE) {
1258 long val;
1259 Window modwin = event->data.l[0];
1261 scr = wScreenForRootWindow(event->window);
1263 if (getSimpleHint(modwin, _XA_KWM_MODULE, &val) && val) {
1264 #ifdef DEBUG1
1265 puts("got KDE module startup");
1266 #endif
1267 addModule(scr, modwin);
1268 } else {
1269 #ifdef DEBUG1
1270 puts("got KDE module finish");
1271 #endif
1272 removeModule(scr, modwin);
1274 } else {
1275 processed = False;
1278 return processed;
1282 void
1283 wKWMCheckModule(WScreen *scr, Window window)
1285 long val;
1287 if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val) {
1288 #ifdef DEBUG1
1289 puts("got KDE module startup");
1290 #endif
1291 addModule(scr, window);
1296 Bool
1297 wKWMCheckRootHintChange(WScreen *scr, XPropertyEvent *event)
1299 Bool processed = True;
1300 long value;
1302 if (event->atom == _XA_KWM_CURRENT_DESKTOP) {
1303 if (getSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP, &value)) {
1304 #ifdef DEBUG1
1305 printf("got KDE workspace switch to %li\n", value);
1306 #endif
1307 if (value-1 != scr->current_workspace) {
1308 wWorkspaceChange(scr, value-1);
1311 } else if (event->atom == _XA_KWM_NUMBER_OF_DESKTOPS) {
1312 #ifdef DEBUG1
1313 printf("got KDE workspace number change\n");
1314 #endif
1316 if (getSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS, &value)) {
1318 /* increasing is easy... */
1319 if (value > scr->workspace_count) {
1320 scr->flags.kwm_syncing_count = 1;
1322 wWorkspaceMake(scr, value - scr->workspace_count);
1324 scr->flags.kwm_syncing_count = 0;
1326 } else if (value < scr->workspace_count) {
1327 int i;
1328 Bool rebuild = False;
1330 scr->flags.kwm_syncing_count = 1;
1332 /* decrease all we can do */
1333 for (i = scr->workspace_count; i >= value; i--) {
1334 if (!wWorkspaceDelete(scr, i)) {
1335 rebuild = True;
1336 break;
1340 scr->flags.kwm_syncing_count = 0;
1342 /* someone destroyed a workspace that can't be destroyed.
1343 * Reset the hints to reflect our internal state.
1345 if (rebuild) {
1346 wKWMUpdateWorkspaceCountHint(scr);
1350 } else {
1351 int i;
1353 processed = False;
1355 for (i = 0; i < MAX_WORKSPACES && i < scr->workspace_count; i++) {
1356 if (event->atom == _XA_KWM_DESKTOP_NAME_[i]) {
1357 char *name;
1359 name = wKWMGetWorkspaceName(scr, i);
1361 #ifdef DEBUG1
1362 printf("got KDE workspace name change to %s\n", name);
1363 #endif
1365 if (name && strncmp(name, scr->workspaces[i]->name,
1366 MAX_WORKSPACENAME_WIDTH)!=0) {
1367 scr->flags.kwm_syncing_name = 1;
1368 wWorkspaceRename(scr, i, name);
1369 scr->flags.kwm_syncing_name = 0;
1371 if (name)
1372 XFree(name);
1373 processed = True;
1374 break;
1375 } else if (event->atom == _XA_KWM_WINDOW_REGION_[i]) {
1376 WArea area;
1378 if (getAreaHint(scr->root_win, event->atom, &area)) {
1380 if (scr->totalUsableArea.x1 != area.x1
1381 || scr->totalUsableArea.y1 != area.y1
1382 || scr->totalUsableArea.x2 != area.x2
1383 || scr->totalUsableArea.y2 != area.y2) {
1384 wScreenUpdateUsableArea(scr);
1388 processed = True;
1389 break;
1394 return processed;
1398 Bool
1399 wKWMManageableClient(WScreen *scr, Window win, char *title)
1401 KWMDoNotManageList *ptr, *next;
1402 long val;
1404 if (getSimpleHint(win, _XA_KWM_DOCKWINDOW, &val) && val) {
1405 addDockWindow(scr, win);
1406 return False;
1409 ptr = KWMDoNotManageCrap;
1411 * TODO: support for glob patterns or regexes
1413 if (ptr && strncmp(ptr->title, title, strlen(ptr->title))==0) {
1414 next = ptr->next;
1415 wfree(ptr);
1416 KWMDoNotManageCrap = next;
1417 #ifdef DEBUG1
1418 printf("window %s not managed per KDE request\n", title);
1419 #endif
1421 sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
1422 sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
1424 return False;
1425 } else if (ptr) {
1426 while (ptr->next) {
1427 if (strncmp(ptr->next->title, title, strlen(ptr->next->title))==0) {
1428 #ifdef DEBUG1
1429 printf("window %s not managed per KDE request\n", title);
1430 #endif
1431 next = ptr->next->next;
1432 wfree(ptr->next);
1433 ptr->next = next;
1435 sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
1436 sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
1438 return False;
1441 ptr = ptr->next;
1445 return True;
1449 void
1450 wKWMUpdateCurrentWorkspaceHint(WScreen *scr)
1452 setSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP,
1453 scr->current_workspace+1);
1455 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_CHANGE, NULL,
1456 scr->current_workspace+1);
1460 void
1461 wKWMUpdateActiveWindowHint(WScreen *scr)
1463 long val;
1464 WWindow *wwin, *tmp;
1466 if (!scr->focused_window || !scr->focused_window->flags.focused)
1467 val = None;
1468 else {
1469 val = (long)(scr->focused_window->client_win);
1471 /* raise the menubar thing */
1472 wwin = scr->focused_window;
1473 tmp = wwin->prev;
1474 while (tmp) {
1475 if (tmp->flags.kwm_menubar
1476 && tmp->transient_for == wwin->client_win) {
1477 wRaiseFrame(tmp->frame->core);
1478 break;
1480 tmp = tmp->prev;
1484 XChangeProperty(dpy, scr->root_win, _XA_KWM_ACTIVE_WINDOW,
1485 _XA_KWM_ACTIVE_WINDOW, 32, PropModeReplace,
1486 (unsigned char*)&val, 1);
1487 XFlush(dpy);
1491 void
1492 wKWMUpdateWorkspaceCountHint(WScreen *scr)
1494 if (scr->flags.kwm_syncing_count)
1495 return;
1497 setSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS,
1498 scr->workspace_count);
1500 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE, NULL,
1501 scr->workspace_count);
1505 void
1506 wKWMCheckDestroy(XDestroyWindowEvent *event)
1508 WScreen *scr;
1510 if (event->event == event->window) {
1511 return;
1514 scr = wScreenSearchForRootWindow(event->event);
1515 if (!scr) {
1516 return;
1519 removeModule(scr, event->window);
1520 removeDockWindow(scr, event->window);
1524 void
1525 wKWMUpdateWorkspaceNameHint(WScreen *scr, int workspace)
1527 char buffer[64];
1529 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
1531 if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
1532 snprintf(buffer, sizeof(buffer), "KWM_DESKTOP_NAME_%d", workspace + 1);
1534 _XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
1537 XChangeProperty(dpy, scr->root_win, _XA_KWM_DESKTOP_NAME_[workspace],
1538 XA_STRING, 8, PropModeReplace,
1539 (unsigned char*)scr->workspaces[workspace]->name,
1540 strlen(scr->workspaces[workspace]->name)+1);
1542 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NAME_CHANGE, NULL, workspace+1);
1547 void
1548 wKWMUpdateClientWorkspace(WWindow *wwin)
1550 #ifdef DEBUG1
1551 printf("updating workspace of %s to %i\n",
1552 wwin->frame->title, wwin->frame->workspace+1);
1553 #endif
1554 setSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP,
1555 wwin->frame->workspace+1);
1559 void
1560 wKWMUpdateClientGeometryRestore(WWindow *wwin)
1562 WArea rect;
1564 rect.x1 = wwin->old_geometry.x;
1565 rect.y1 = wwin->old_geometry.y;
1566 rect.x2 = wwin->old_geometry.x + wwin->old_geometry.width;
1567 rect.y2 = wwin->old_geometry.y + wwin->old_geometry.height;
1569 setAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, rect);
1573 void
1574 wKWMUpdateClientStateHint(WWindow *wwin, WKWMStateFlag flags)
1576 if (flags & KWMIconifiedFlag) {
1577 setSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED,
1578 wwin->flags.miniaturized /*|| wwin->flags.shaded
1579 || wwin->flags.hidden*/);
1581 if (flags & KWMStickyFlag) {
1582 setSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY,
1583 IS_OMNIPRESENT(wwin));
1585 if (flags & KWMMaximizedFlag) {
1586 int value = 0;
1588 if (wwin->flags.maximized & MAX_VERTICAL)
1589 value |= 2;
1590 if (wwin->flags.maximized & MAX_HORIZONTAL)
1591 value |= 1;
1593 setSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, value);
1598 Bool
1599 wKWMGetUsableArea(WScreen *scr, WArea *area)
1601 char buffer[64];
1603 if (_XA_KWM_WINDOW_REGION_[0]==0) {
1604 snprintf(buffer, sizeof(buffer), "KWM_WINDOW_REGION_%d", 1);
1606 _XA_KWM_WINDOW_REGION_[0] = XInternAtom(dpy, buffer, False);
1609 return getAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[0], area);
1614 Bool
1615 wKWMGetIconGeometry(WWindow *wwin, WArea *area)
1617 return getAreaHint(wwin->client_win, _XA_KWM_WIN_ICON_GEOMETRY, area);
1622 #ifdef not_used
1623 void
1624 wKWMSetUsableAreaHint(WScreen *scr, int workspace)
1626 /* if we set this after making changes of our own to the area,
1627 * the next time the area changes, we won't know what should
1628 * be the new final area. This protocol isn't worth a shit :/
1631 * According to Matthias Ettrich:
1632 * Indeed, there's no protocol to deal with the area yet in case several
1633 * clients want to influence it. It is sufficent, though, if it is clear
1634 * that one process is responsable for the area. For KDE this is kpanel, but
1635 * I see that there might be a conflict with the docking area of windowmaker
1636 * itself.
1640 #ifdef notdef
1641 char buffer[64];
1643 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
1645 if (_XA_KWM_WINDOW_REGION_[workspace]==0) {
1646 snprintf(buffer, sizeof(buffer), "KWM_WINDOW_REGION_%d", workspace+1);
1648 _XA_KWM_WINDOW_REGION_[workspace] = XInternAtom(dpy, buffer, False);
1651 setAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[workspace],
1652 scr->totalUsableArea);
1653 #endif
1655 #endif /* not_used */
1657 void
1658 wKWMSendEventMessage(WWindow *wwin, WKWMEventMessage message)
1660 Atom msg;
1662 if (wwin && (wwin->flags.internal_window
1663 || wwin->flags.kwm_hidden_for_modules
1664 || !wwin->flags.kwm_managed
1665 || WFLAGP(wwin, skip_window_list)))
1666 return;
1668 switch (message) {
1669 case WKWMAddWindow:
1670 msg = _XA_KWM_MODULE_WIN_ADD;
1671 break;
1672 case WKWMRemoveWindow:
1673 msg = _XA_KWM_MODULE_WIN_REMOVE;
1674 break;
1675 case WKWMFocusWindow:
1676 msg = _XA_KWM_MODULE_WIN_ACTIVATE;
1677 break;
1678 case WKWMRaiseWindow:
1679 msg = _XA_KWM_MODULE_WIN_RAISE;
1680 break;
1681 case WKWMLowerWindow:
1682 msg = _XA_KWM_MODULE_WIN_LOWER;
1683 break;
1684 case WKWMChangedClient:
1685 msg = _XA_KWM_MODULE_WIN_CHANGE;
1686 break;
1687 case WKWMIconChange:
1688 msg = _XA_KWM_MODULE_WIN_ICON_CHANGE;
1689 break;
1690 default:
1691 return;
1694 sendToModules(wwin ? wwin->screen_ptr : NULL, msg, wwin, 0);
1697 #if 0
1698 static void
1699 writeSocket(int sock, char *data)
1701 char buffer[128];
1703 snprintf(buffer, sizeof(buffer), "%i ", strlen(data));
1704 write(sock, buffer, strlen(buffer));
1705 write(sock, data, strlen(data));
1709 static int
1710 connectKFM(WScreen *scr)
1712 char *path;
1713 char *buffer;
1714 char *ptr;
1715 FILE *f;
1716 int pid;
1717 int sock = 0;
1718 struct sockaddr_un addr;
1719 char buf[256];
1721 path = wstrconcat(wgethomedir(), "/.kde/share/apps/kfm/pid");
1722 buffer = wstrdup(getenv("DISPLAY"));
1724 ptr = strchr(buffer, ':');
1725 if (ptr)
1726 *ptr = '_';
1728 ptr = strrchr(buffer, '.');
1729 if (ptr)
1730 *ptr = 0;
1732 char b[32];
1734 snprintf(b, sizeof(b), ".%i", scr->screen);
1736 buffer = wstrappend(buffer, b);
1738 path = wstrappend(path, buffer);
1739 wfree(buffer);
1741 /* pid file */
1742 f = fopen(path, "rb");
1743 wfree(path);
1744 if (!f)
1745 return -1;
1747 *buf = 0;
1748 fgets(buf, sizeof(buf), f);
1749 buf[sizeof(buf)] = 0;
1750 pid = atoi(buf);
1751 if (pid <= 0)
1752 return -1;
1754 if (kill(pid, 0) != 0)
1755 return -1;
1757 *buf = 0;
1758 fgets(buf, sizeof(buf), f);
1759 buf[sizeof(buf)] = 0;
1760 fclose(f);
1762 sock = socket(AF_UNIX, SOCK_STREAM, 0);
1763 if (sock < 0)
1764 return -1;
1765 addr.sun_family = AF_UNIX;
1766 strcpy(addr.sun_path, buf);
1768 if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
1769 close(sock);
1770 return -1;
1773 path = wstrconcat(wgethomedir(), "/.kde/share/apps/kfm/magic");
1774 f = fopen(path, "rb");
1775 wfree(path);
1776 if (!f) {
1777 return -1;
1779 ptr = fgets(buf, sizeof(buf), f);
1780 fclose(f);
1781 if (!ptr) {
1782 return -1;
1784 puts(buffer);
1786 ptr = wstrconcat("auth", buf);
1788 writeSocket(sock, ptr);
1789 wfree(ptr);
1791 return sock;
1793 #endif
1795 void
1796 wKWMSelectRootRegion(WScreen *scr, int x, int y, int w, int h, Bool control)
1798 #if 0
1799 char buffer[128];
1800 int sock;
1802 puts("CONNECTING");
1803 sock = connectKFM(scr);
1804 if (sock < 0)
1805 return;
1806 puts("SENDING DATA");
1808 sprintf(buffer, "selectRootIcons %i %i %i %i %c", x, y, w, h, control);
1809 writeSocket(sock, buffer);
1811 close(sock);
1812 #endif
1818 static void observer(void *self, WMNotification *notif)
1820 WScreen *scr = (WScreen*)self;
1821 WWindow *wwin = (WWindow*)WMGetNotificationObject(notif);
1822 const char *name = WMGetNotificationName(notif);
1823 void *data = WMGetNotificationClientData(notif);
1825 if (strcmp(name, WMNManaged) == 0 && wwin) {
1826 wKWMUpdateClientWorkspace(wwin);
1827 wKWMUpdateClientStateHint(wwin, KWMAllFlags);
1829 wwin->flags.kwm_managed = 1;
1831 wKWMSendEventMessage(wwin, WKWMAddWindow);
1833 } else if (strcmp(name, WMNUnmanaged) == 0 && wwin) {
1834 wwin->frame->workspace = -1;
1836 wKWMUpdateClientWorkspace(wwin);
1838 wKWMSendEventMessage(wwin, WKWMRemoveWindow);
1840 } else if (strcmp(name, WMNChangedWorkspace) == 0 && wwin) {
1841 wKWMUpdateClientWorkspace(wwin);
1842 wKWMSendEventMessage(wwin, WKWMChangedClient);
1844 } else if (strcmp(name, WMNChangedFocus) == 0) {
1845 wKWMUpdateActiveWindowHint(scr);
1846 wKWMSendEventMessage(wwin, WKWMFocusWindow);
1848 } else if (strcmp(name, WMNChangedName) == 0) {
1849 wKWMSendEventMessage(wwin, WKWMChangedClient);
1851 } else if (strcmp(name, WMNChangedState) == 0) {
1852 char *detail = (char*)data;
1854 if (strcmp(detail, "shade") == 0) {
1855 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1856 wKWMSendEventMessage(wwin, WKWMChangedClient);
1857 } else if (strcmp(detail, "omnipresent") == 0) {
1858 wKWMUpdateClientStateHint(wwin, KWMStickyFlag);
1859 wKWMSendEventMessage(wwin, WKWMChangedClient);
1860 } else if (strcmp(detail, "maximize") == 0) {
1861 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
1862 wKWMSendEventMessage(wwin, WKWMChangedClient);
1863 } else if (strcmp(detail, "iconify-transient") == 0) {
1864 if (wwin->flags.miniaturized) {
1865 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1866 wKWMSendEventMessage(wwin, WKWMRemoveWindow);
1867 wwin->flags.kwm_hidden_for_modules = 1;
1868 } else {
1869 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1870 if (wwin->flags.kwm_hidden_for_modules) {
1871 wKWMSendEventMessage(wwin, WKWMAddWindow);
1872 wwin->flags.kwm_hidden_for_modules = 0;
1875 } else if (strcmp(detail, "iconify") == 0) {
1876 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1877 wKWMSendEventMessage(wwin, WKWMChangedClient);
1878 } else if (strcmp(detail, "hide") == 0) {
1879 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1880 wKWMSendEventMessage(wwin, WKWMChangedClient);
1883 } else if (strcmp(name, WMNChangedStacking) == 0 && wwin) {
1884 if (data == NULL)
1885 wKWMBroadcastStacking(wwin->screen_ptr);
1886 else if (strcmp(data, "lower") == 0)
1887 wKWMSendEventMessage(wwin, WKWMLowerWindow);
1888 else if (strcmp(data, "raise") == 0)
1889 wKWMSendEventMessage(wwin, WKWMRaiseWindow);
1894 static void wsobserver(void *self, WMNotification *notif)
1896 WScreen *scr = (WScreen*)WMGetNotificationObject(notif);
1897 const char *name = WMGetNotificationName(notif);
1898 void *data = WMGetNotificationClientData(notif);
1900 if (strcmp(name, WMNWorkspaceCreated) == 0) {
1901 if (!scr->flags.kwm_syncing_count) {
1902 wKWMUpdateWorkspaceCountHint(scr);
1903 wKWMUpdateWorkspaceNameHint(scr, (int)data);
1905 #ifdef not_used
1906 wKWMSetUsableAreaHint(scr, scr->workspace_count-1);
1907 #endif
1908 } else if (strcmp(name, WMNWorkspaceDestroyed) == 0) {
1909 wKWMUpdateWorkspaceCountHint(scr);
1910 } else if (strcmp(name, WMNWorkspaceNameChanged) == 0) {
1911 wKWMUpdateWorkspaceNameHint(scr, (int)data);
1912 } else if (strcmp(name, WMNWorkspaceChanged) == 0) {
1913 wKWMUpdateCurrentWorkspaceHint(scr);
1915 } else if (strcmp(name, WMNResetStacking) == 0) {
1916 wKWMBroadcastStacking(scr);
1921 #endif /* KWM_HINTS */