changed indentation to use spaces only
[wmaker-crm.git] / src / kwm.c
blob8490349e7ac3bb11ad1e6a27a62a0d7c66b871ed
1 /* kwm.c-- stuff for support for kwm hints
3 * Window Maker window manager
5 * Copyright (c) 1998-2003 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,
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 * XXX
106 * different WORKAREA for each workspace
107 * -- done by rebuilding usableArea at each workspace switch.
111 #include "wconfig.h"
113 #ifdef KWM_HINTS
115 #include <X11/Xlib.h>
116 #include <X11/Xutil.h>
117 #include <X11/Xatom.h>
119 #include <stdlib.h>
120 #include <stdio.h>
121 #include <string.h>
122 #include <unistd.h>
124 #include <sys/types.h>
125 #include <sys/socket.h>
126 #include <sys/un.h>
127 #include <signal.h>
130 #include "WindowMaker.h"
132 #include "screen.h"
133 #include "wcore.h"
134 #include "framewin.h"
135 #include "window.h"
136 #include "properties.h"
137 #include "icon.h"
138 #include "client.h"
139 #include "funcs.h"
140 #include "actions.h"
141 #include "workspace.h"
142 #include "dialog.h"
143 #include "stacking.h"
144 #include "xinerama.h"
146 #include "kwm.h"
148 /*#define DEBUG1
150 /******* Global ******/
152 extern Time LastFocusChange;
153 extern Time LastTimestamp;
156 extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
157 extern Atom _XA_WM_DELETE_WINDOW;
159 /** Local **/
161 static Atom _XA_KWM_COMMAND = 0;
162 static Atom _XA_KWM_ACTIVATE_WINDOW = 0;
163 static Atom _XA_KWM_ACTIVE_WINDOW = 0;
164 static Atom _XA_KWM_DO_NOT_MANAGE = 0;
165 static Atom _XA_KWM_DOCKWINDOW = 0;
166 static Atom _XA_KWM_RUNNING = 0;
168 static Atom _XA_KWM_MODULE = 0;
170 static Atom _XA_KWM_MODULE_INIT = 0;
171 static Atom _XA_KWM_MODULE_INITIALIZED = 0;
172 static Atom _XA_KWM_MODULE_DESKTOP_CHANGE = 0;
173 static Atom _XA_KWM_MODULE_DESKTOP_NAME_CHANGE = 0;
174 static Atom _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE = 0;
175 static Atom _XA_KWM_MODULE_WIN_ADD = 0;
176 static Atom _XA_KWM_MODULE_WIN_REMOVE = 0;
177 static Atom _XA_KWM_MODULE_WIN_CHANGE = 0;
178 static Atom _XA_KWM_MODULE_WIN_RAISE = 0;
179 static Atom _XA_KWM_MODULE_WIN_LOWER = 0;
180 static Atom _XA_KWM_MODULE_WIN_ACTIVATE = 0;
181 static Atom _XA_KWM_MODULE_WIN_ICON_CHANGE = 0;
182 static Atom _XA_KWM_MODULE_DOCKWIN_ADD = 0;
183 static Atom _XA_KWM_MODULE_DOCKWIN_REMOVE = 0;
185 static Atom _XA_KWM_WIN_UNSAVED_DATA = 0;
186 static Atom _XA_KWM_WIN_DECORATION = 0;
187 static Atom _XA_KWM_WIN_DESKTOP = 0;
188 static Atom _XA_KWM_WIN_GEOMETRY_RESTORE = 0;
189 static Atom _XA_KWM_WIN_ICONIFIED = 0;
190 static Atom _XA_KWM_WIN_MAXIMIZED = 0;
191 static Atom _XA_KWM_WIN_STICKY = 0;
193 static Atom _XA_KWM_WIN_ICON_GEOMETRY = 0;
195 static Atom _XA_KWM_CURRENT_DESKTOP = 0;
196 static Atom _XA_KWM_NUMBER_OF_DESKTOPS = 0;
197 static Atom _XA_KWM_DESKTOP_NAME_[MAX_WORKSPACES];
198 static Atom _XA_KWM_WINDOW_REGION_[MAX_WORKSPACES];
202 /* list of window titles that must not be managed */
203 typedef struct KWMDoNotManageList {
204 char title[20];
205 struct KWMDoNotManageList *next;
206 } KWMDoNotManageList;
208 static KWMDoNotManageList *KWMDoNotManageCrap = NULL;
211 /* list of KWM modules */
212 typedef struct KWMModuleList {
213 Window window;
214 struct KWMModuleList *next;
215 #ifdef DEBUG1
216 char *title;
217 #endif
218 } KWMModuleList;
220 static KWMModuleList *KWMModules = NULL;
222 static KWMModuleList *KWMDockWindows = NULL;
224 /* window decoration types */
225 enum {
226 KWMnoDecoration = 0,
227 KWMnormalDecoration = 1,
228 KWMtinyDecoration = 2,
229 KWMnoFocus = 256,
230 KWMstandaloneMenuBar = 512,
231 KWMdesktopIcon = 1024,
232 KWMstaysOnTop = 2048
237 static void observer(void *self, WMNotification *notif);
238 static void wsobserver(void *self, WMNotification *notif);
242 static Bool
243 getSimpleHint(Window win, Atom atom, long *retval)
245 long *data = 0;
247 assert(atom!=0);
249 data = (long*)PropGetCheckProperty(win, atom, atom, 32, 1, NULL);
251 if (!data)
252 return False;
254 *retval = *data;
256 XFree(data);
258 return True;
263 static void
264 setSimpleHint(Window win, Atom atom, long value)
266 assert(atom!=0);
267 XChangeProperty(dpy, win, atom, atom,
268 32, PropModeReplace, (unsigned char*)&value, 1);
272 static void
273 sendClientMessage(WScreen *scr, Window window, Atom atom, long value)
275 XEvent event;
276 long mask = 0;
278 assert(atom!=0);
280 memset(&event, 0, sizeof(XEvent));
281 event.xclient.type = ClientMessage;
282 event.xclient.message_type = atom;
283 event.xclient.window = window;
284 event.xclient.format = 32;
285 event.xclient.data.l[0] = value;
286 event.xclient.data.l[1] = LastTimestamp;
288 if (scr && scr->root_win == window)
289 mask = SubstructureRedirectMask;
291 XSendEvent(dpy, window, False, mask, &event);
295 static void
296 sendTextMessage(WScreen *scr, Window window, Atom atom, char *text)
298 XEvent event;
299 long mask = 0;
300 int i;
302 assert(atom!=0);
304 memset(&event, 0, sizeof(XEvent));
305 event.xclient.type = ClientMessage;
306 event.xclient.message_type = atom;
307 event.xclient.window = window;
308 event.xclient.format = 8;
310 for (i=0; i<20 && text[i]; i++)
311 event.xclient.data.b[i] = text[i];
313 if (scr && scr->root_win == window)
314 mask = SubstructureRedirectMask;
316 XSendEvent(dpy, window, False, mask, &event);
320 static Bool
321 getAreaHint(Window win, Atom atom, WArea *area)
323 long *data = 0;
325 data = (long*)PropGetCheckProperty(win, atom, atom, 32, 4, NULL);
327 if (!data)
328 return False;
330 area->x1 = data[0];
331 area->y1 = data[1];
332 area->x2 = data[2] + area->x1;
333 area->y2 = data[3] + area->y1;
335 XFree(data);
337 return True;
341 static void
342 setAreaHint(Window win, Atom atom, WArea area)
344 long value[4];
346 assert(atom!=0);
347 value[0] = area.x1;
348 value[1] = area.y1;
349 value[2] = area.x2 - area.x1;
350 value[3] = area.y2 - area.y1;
351 XChangeProperty(dpy, win, atom, atom, 32, PropModeReplace,
352 (unsigned char*)&value, 4);
356 static void
357 addModule(WScreen *scr, Window window)
359 KWMModuleList *node;
360 long val;
361 WWindow *ptr;
363 node = malloc(sizeof(KWMModuleList));
364 if (!node) {
365 wwarning("out of memory while registering KDE module");
366 return;
369 node->next = KWMModules;
370 node->window = window;
371 KWMModules = node;
373 sendClientMessage(scr, window, _XA_KWM_MODULE_INIT, 0);
375 if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val==2) {
376 if (scr->kwm_dock != None) {
377 setSimpleHint(window, _XA_KWM_MODULE, 1);
378 } else {
379 KWMModuleList *ptr;
381 scr->kwm_dock = window;
383 for (ptr = KWMDockWindows; ptr!=NULL; ptr = ptr->next) {
384 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
385 ptr->window);
390 /* send list of windows */
391 for (ptr = scr->focused_window; ptr!=NULL; ptr = ptr->prev) {
392 if (!ptr->flags.kwm_hidden_for_modules
393 && !WFLAGP(ptr, skip_window_list)) {
394 sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ADD,
395 ptr->client_win);
399 /* send window stacking order */
400 wKWMSendStacking(scr, window);
402 /* send focused window */
403 if (scr->focused_window && scr->focused_window->flags.focused) {
404 sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ACTIVATE,
405 scr->focused_window->client_win);
408 /* tell who we are */
409 sendTextMessage(scr, window, _XA_KWM_COMMAND, "wm:wmaker");
412 sendClientMessage(scr, window, _XA_KWM_MODULE_INITIALIZED, 0);
413 #ifdef DEBUG1
414 KWMModules->title = NULL;
415 XFetchName(dpy, window, &KWMModules->title);
416 printf("NEW MODULE %s\n", KWMModules->title);
417 #endif
421 static void
422 removeModule(WScreen *scr, Window window)
424 KWMModuleList *next;
426 if (!KWMModules) {
427 return;
430 if (KWMModules->window == window) {
431 next = KWMModules->next;
432 #ifdef DEBUG1
433 printf("REMOVING MODULE %s\n", KWMModules->title);
434 if (KWMModules->title)
435 XFree(KWMModules->title);
436 #endif
437 wfree(KWMModules);
438 KWMModules = next;
439 } else {
440 KWMModuleList *ptr;
442 ptr = KWMModules;
443 while (ptr->next) {
444 if (ptr->next->window == window) {
445 next = ptr->next->next;
446 #ifdef DEBUG1
447 printf("REMOVING MODULE %s\n", ptr->next->title);
448 if (ptr->next->title)
449 XFree(ptr->next->title);
450 #endif
451 wfree(ptr->next);
452 ptr->next->next = next;
453 break;
455 ptr->next = ptr->next->next;
459 if (scr->kwm_dock == window)
460 scr->kwm_dock = None;
465 static void
466 addDockWindow(WScreen *scr, Window window)
468 KWMModuleList *ptr;
470 for (ptr = KWMDockWindows; ptr != NULL; ptr = ptr->next) {
471 if (ptr->window == window)
472 break;
474 if (!ptr) {
475 KWMModuleList *node;
477 node = malloc(sizeof(KWMModuleList));
478 if (!node) {
479 wwarning("out of memory while processing KDE dock window");
480 return;
482 node->next = KWMDockWindows;
483 KWMDockWindows = node;
484 node->window = window;
485 XSelectInput(dpy, window, StructureNotifyMask);
487 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
488 window);
493 static void
494 removeDockWindow(WScreen *scr, Window window)
496 if (!KWMDockWindows)
497 return;
499 if (KWMDockWindows->window == window) {
500 KWMModuleList *next;
502 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_REMOVE,
503 window);
505 next = KWMDockWindows->next;
506 wfree(KWMDockWindows);
507 KWMDockWindows = next;
509 } else {
510 KWMModuleList *ptr, *next;
512 ptr = KWMDockWindows;
513 while (ptr->next) {
514 if (ptr->next->window == window) {
515 sendClientMessage(scr, scr->kwm_dock,
516 _XA_KWM_MODULE_DOCKWIN_REMOVE, window);
517 next = ptr->next->next;
518 wfree(ptr->next);
519 ptr->next = next;
520 return;
522 ptr = ptr->next;
528 static void
529 sendToModules(WScreen *scr, Atom atom, WWindow *wwin, long data)
531 KWMModuleList *ptr;
532 XEvent event;
533 long mask;
535 if (wwin) {
536 if (wwin->flags.kwm_hidden_for_modules
537 || WFLAGP(wwin, skip_window_list))
538 return;
539 data = wwin->client_win;
541 #ifdef DEBUG1
542 printf("notifying %s\n",XGetAtomName(dpy, atom));
543 #endif
544 memset(&event, 0, sizeof(XEvent));
545 event.xclient.type = ClientMessage;
546 event.xclient.message_type = atom;
547 event.xclient.format = 32;
548 event.xclient.data.l[1] = LastTimestamp;
550 mask = 0;
551 if (scr && scr->root_win == data)
552 mask = SubstructureRedirectMask;
554 for (ptr = KWMModules; ptr!=NULL; ptr = ptr->next) {
555 event.xclient.window = ptr->window;
556 event.xclient.data.l[0] = data;
557 XSendEvent(dpy, ptr->window, False, mask, &event);
562 void
563 wKWMInitStuff(WScreen *scr)
565 if (!_XA_KWM_WIN_STICKY) {
566 _XA_KWM_WIN_UNSAVED_DATA = XInternAtom(dpy, "KWM_WIN_UNSAVED_DATA",
567 False);
569 _XA_KWM_WIN_DECORATION = XInternAtom(dpy, "KWM_WIN_DECORATION", False);
571 _XA_KWM_WIN_DESKTOP = XInternAtom(dpy, "KWM_WIN_DESKTOP", False);
573 _XA_KWM_WIN_GEOMETRY_RESTORE = XInternAtom(dpy,
574 "KWM_WIN_GEOMETRY_RESTORE",
575 False);
577 _XA_KWM_WIN_STICKY = XInternAtom(dpy, "KWM_WIN_STICKY", False);
579 _XA_KWM_WIN_ICONIFIED = XInternAtom(dpy, "KWM_WIN_ICONIFIED", False);
581 _XA_KWM_WIN_MAXIMIZED = XInternAtom(dpy, "KWM_WIN_MAXIMIZED", False);
583 _XA_KWM_WIN_ICON_GEOMETRY = XInternAtom(dpy, "KWM_WIN_ICON_GEOMETRY",
584 False);
586 _XA_KWM_COMMAND = XInternAtom(dpy, "KWM_COMMAND", False);
588 _XA_KWM_ACTIVE_WINDOW = XInternAtom(dpy, "KWM_ACTIVE_WINDOW", False);
590 _XA_KWM_ACTIVATE_WINDOW = XInternAtom(dpy, "KWM_ACTIVATE_WINDOW",
591 False);
593 _XA_KWM_DO_NOT_MANAGE = XInternAtom(dpy, "KWM_DO_NOT_MANAGE", False);
595 _XA_KWM_CURRENT_DESKTOP = XInternAtom(dpy, "KWM_CURRENT_DESKTOP",
596 False);
598 _XA_KWM_NUMBER_OF_DESKTOPS = XInternAtom(dpy, "KWM_NUMBER_OF_DESKTOPS",
599 False);
601 _XA_KWM_DOCKWINDOW = XInternAtom(dpy, "KWM_DOCKWINDOW", False);
603 _XA_KWM_RUNNING = XInternAtom(dpy, "KWM_RUNNING", False);
605 _XA_KWM_MODULE = XInternAtom(dpy, "KWM_MODULE", False);
607 _XA_KWM_MODULE_INIT = XInternAtom(dpy, "KWM_MODULE_INIT", False);
608 _XA_KWM_MODULE_INITIALIZED = XInternAtom(dpy, "KWM_MODULE_INITIALIZED", False);
610 /* dunno what these do, but Matthias' patch contains it... */
611 _XA_KWM_MODULE_DESKTOP_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_CHANGE", False);
612 _XA_KWM_MODULE_DESKTOP_NAME_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NAME_CHANGE", False);
613 _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NUMBER_CHANGE", False);
615 _XA_KWM_MODULE_WIN_ADD = XInternAtom(dpy, "KWM_MODULE_WIN_ADD", False);
616 _XA_KWM_MODULE_WIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_WIN_REMOVE", False);
617 _XA_KWM_MODULE_WIN_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_CHANGE", False);
618 _XA_KWM_MODULE_WIN_RAISE = XInternAtom(dpy, "KWM_MODULE_WIN_RAISE", False);
619 _XA_KWM_MODULE_WIN_LOWER = XInternAtom(dpy, "KWM_MODULE_WIN_LOWER", False);
620 _XA_KWM_MODULE_WIN_ACTIVATE = XInternAtom(dpy, "KWM_MODULE_WIN_ACTIVATE", False);
621 _XA_KWM_MODULE_WIN_ICON_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_ICON_CHANGE", False);
622 _XA_KWM_MODULE_DOCKWIN_ADD = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_ADD", False);
623 _XA_KWM_MODULE_DOCKWIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_REMOVE", False);
625 memset(_XA_KWM_WINDOW_REGION_, 0, sizeof(_XA_KWM_WINDOW_REGION_));
627 memset(_XA_KWM_DESKTOP_NAME_, 0, sizeof(_XA_KWM_DESKTOP_NAME_));
630 #define SETSTR(hint, str) {\
631 static Atom a = 0; if (!a) a = XInternAtom(dpy, #hint, False);\
632 XChangeProperty(dpy, scr->root_win, a, XA_STRING, 8, PropModeReplace,\
633 (unsigned char*)str, strlen(str));}
635 SETSTR(KWM_STRING_MAXIMIZE, _("Maximize"));
636 SETSTR(KWM_STRING_UNMAXIMIZE, _("Unmaximize"));
637 SETSTR(KWM_STRING_ICONIFY, _("Miniaturize"));
638 SETSTR(KWM_STRING_UNICONIFY, _("Deminiaturize"));
639 SETSTR(KWM_STRING_STICKY, _("Omnipresent"));
640 SETSTR(KWM_STRING_UNSTICKY, _("Not Omnipresent"));
641 SETSTR(KWM_STRING_STRING_MOVE, _("Move"));
642 SETSTR(KWM_STRING_STRING_RESIZE, _("Resize"));
643 SETSTR(KWM_STRING_CLOSE, _("Close"));
644 SETSTR(KWM_STRING_TODESKTOP, _("Move To"));
645 SETSTR(KWM_STRING_ONTOCURRENTDESKTOP, _("Bring Here"));
646 #undef SETSTR
648 /* catch any notifications from any objects */
650 WMAddNotificationObserver(observer, scr, WMNManaged, NULL);
651 WMAddNotificationObserver(observer, scr, WMNUnmanaged, NULL);
652 WMAddNotificationObserver(observer, scr, WMNChangedWorkspace, NULL);
653 WMAddNotificationObserver(observer, scr, WMNChangedState, NULL);
654 WMAddNotificationObserver(observer, scr, WMNChangedFocus, NULL);
655 WMAddNotificationObserver(observer, scr, WMNChangedStacking, NULL);
656 WMAddNotificationObserver(observer, scr, WMNChangedName, NULL);
658 WMAddNotificationObserver(wsobserver, scr, WMNWorkspaceCreated, NULL);
659 WMAddNotificationObserver(wsobserver, scr, WMNWorkspaceDestroyed, NULL);
660 WMAddNotificationObserver(wsobserver, scr, WMNWorkspaceChanged, NULL);
661 WMAddNotificationObserver(wsobserver, scr, WMNWorkspaceNameChanged, NULL);
663 WMAddNotificationObserver(wsobserver, scr, WMNResetStacking, NULL);
667 void
668 wKWMSendStacking(WScreen *scr, Window module)
670 WMBagIterator i;
671 WCoreWindow *core;
673 WM_ITERATE_BAG(scr->stacking_list, core, i) {
674 for (; core != NULL; core = core->stacking->under) {
675 WWindow *wwin;
677 wwin = wWindowFor(core->window);
678 if (wwin)
679 sendClientMessage(scr, module, _XA_KWM_MODULE_WIN_RAISE,
680 wwin->client_win);
686 void
687 wKWMBroadcastStacking(WScreen *scr)
689 KWMModuleList *ptr = KWMModules;
691 while (ptr) {
692 wKWMSendStacking(scr, ptr->window);
694 ptr = ptr->next;
699 char*
700 wKWMGetWorkspaceName(WScreen *scr, int workspace)
702 Atom type_ret;
703 int fmt_ret;
704 unsigned long nitems_ret;
705 unsigned long bytes_after_ret;
706 char *data = NULL, *tmp;
707 char buffer[64];
709 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
711 if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
712 snprintf(buffer, sizeof(buffer), "KWM_DESKTOP_NAME_%d", workspace + 1);
714 _XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
717 /* What do these people have against correctly using property types? */
718 if (XGetWindowProperty(dpy, scr->root_win,
719 _XA_KWM_DESKTOP_NAME_[workspace], 0, 128, False,
720 XA_STRING,
721 &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
722 (unsigned char**)&data)!=Success || !data)
723 return NULL;
725 tmp = wstrdup(data);
726 XFree(data);
728 return tmp;
732 void
733 wKWMSetInitializedHint(WScreen *scr)
735 setSimpleHint(scr->root_win, _XA_KWM_RUNNING, 1);
739 void
740 wKWMShutdown(WScreen *scr, Bool closeModules)
742 KWMModuleList *ptr;
744 XDeleteProperty(dpy, scr->root_win, _XA_KWM_RUNNING);
746 if (closeModules) {
747 for (ptr = KWMModules; ptr != NULL; ptr = ptr->next) {
748 XKillClient(dpy, ptr->window);
754 Bool
755 wKWMCheckClientHints(WWindow *wwin, int *layer, int *workspace)
757 long val;
758 Bool hasHint = False;
760 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA, &val)
761 && val) {
763 wwin->client_flags.broken_close = 1;
764 hasHint = True;
765 } else
766 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &val)) {
767 if (val & KWMnoFocus) {
768 wwin->client_flags.no_focusable = 1;
770 switch (val & ~KWMnoFocus) {
771 case KWMnoDecoration:
772 wwin->client_flags.no_titlebar = 1;
773 wwin->client_flags.no_resizebar = 1;
774 break;
775 case KWMtinyDecoration:
776 wwin->client_flags.no_resizebar = 1;
777 break;
778 case KWMstandaloneMenuBar:
779 wwin->client_flags.no_titlebar = 1;
780 wwin->client_flags.no_resizebar = 1;
781 wwin->client_flags.no_resizable = 1;
782 wwin->client_flags.skip_window_list = 1;
783 wwin->client_flags.no_hide_others = 1;
784 wwin->flags.kwm_menubar = 1;
785 *layer = WMMainMenuLevel;
786 break;
787 case KWMdesktopIcon:
788 *layer = WMDesktopLevel;
789 break;
790 case KWMstaysOnTop:
791 *layer = WMFloatingLevel;
792 break;
793 case KWMnormalDecoration:
794 default:
795 break;
797 hasHint = True;
798 } else
799 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &val)) {
800 *workspace = val - 1;
801 hasHint = True;
804 return hasHint;
808 Bool
809 wKWMCheckClientInitialState(WWindow *wwin)
811 long val;
812 WArea area;
813 Bool hasHint = False;
815 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY, &val) && val) {
817 wwin->client_flags.omnipresent = 1;
818 hasHint = True;
819 } else
820 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED, &val) && val) {
822 wwin->flags.miniaturized = 1;
823 hasHint = True;
824 } else
825 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, &val)) {
826 if (val == 2)
827 wwin->flags.maximized = MAX_VERTICAL;
828 else if (val == 1)
829 wwin->flags.maximized = MAX_HORIZONTAL;
830 else if (val == 3)
831 wwin->flags.maximized = MAX_VERTICAL|MAX_HORIZONTAL;
832 hasHint = True;
833 } else
834 if (getAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, &area)
835 && (wwin->old_geometry.x != area.x1
836 || wwin->old_geometry.y != area.y1
837 || wwin->old_geometry.width != area.x2 - area.x1
838 || wwin->old_geometry.height != area.y2 - area.y1)) {
840 wwin->old_geometry.x = area.x1;
841 wwin->old_geometry.y = area.y1;
842 wwin->old_geometry.width = area.x2 - area.x1;
843 wwin->old_geometry.height = area.y2 - area.y1;
844 hasHint = True;
847 return hasHint;
851 Bool
852 wKWMCheckClientHintChange(WWindow *wwin, XPropertyEvent *event)
854 Bool processed = True;
855 Bool flag;
856 long value;
859 if (!wwin->frame) {
860 return False;
863 if (event->atom == _XA_KWM_WIN_UNSAVED_DATA) {
864 #ifdef DEBUG1
865 printf("got KDE unsaved data change\n");
866 #endif
868 flag = getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA,
869 &value) && value;
871 if (flag != wwin->client_flags.broken_close) {
872 wwin->client_flags.broken_close = flag;
873 if (wwin->frame)
874 wWindowUpdateButtonImages(wwin);
876 } else if (event->atom == _XA_KWM_WIN_STICKY) {
878 #ifdef DEBUG1
879 printf("got KDE sticky change\n");
880 #endif
881 flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY,
882 &value) || value;
884 if (flag != wwin->client_flags.omnipresent) {
886 wWindowSetOmnipresent(wwin, flag);
888 } else if (event->atom == _XA_KWM_WIN_MAXIMIZED) {
889 int bla = 0;
891 #ifdef DEBUG1
892 printf("got KDE maximize change\n");
893 #endif
894 flag = getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, &value);
896 if (flag) {
897 if (value == 3)
898 bla = MAX_VERTICAL|MAX_HORIZONTAL;
899 else if (value == 2)
900 bla = MAX_VERTICAL;
901 else if (value == 1)
902 bla = MAX_HORIZONTAL;
905 if (bla != wwin->flags.maximized) {
906 if (bla != 0)
907 wMaximizeWindow(wwin, bla);
908 else
909 wUnmaximizeWindow(wwin);
911 } else if (event->atom == _XA_KWM_WIN_ICONIFIED) {
913 #ifdef DEBUG1
914 printf("got KDE iconify change\n");
915 #endif
916 flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED,
917 &value) || value;
919 if (flag != wwin->flags.miniaturized) {
921 if (flag)
922 wIconifyWindow(wwin);
923 else
924 wDeiconifyWindow(wwin);
927 } else if (event->atom == _XA_KWM_WIN_DECORATION) {
928 Bool refresh = False;
929 int oldnofocus;
931 #ifdef DEBUG1
932 printf("got KDE decoration change\n");
933 #endif
935 oldnofocus = wwin->client_flags.no_focusable;
937 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &value)) {
938 wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
940 switch (value & ~KWMnoFocus) {
941 case KWMnoDecoration:
942 if (!WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
943 refresh = True;
945 wwin->client_flags.no_titlebar = 1;
946 wwin->client_flags.no_resizebar = 1;
947 break;
949 case KWMtinyDecoration:
950 if (WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
951 refresh = True;
953 wwin->client_flags.no_titlebar = 0;
954 wwin->client_flags.no_resizebar = 1;
955 break;
957 case KWMnormalDecoration:
958 default:
959 if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
960 refresh = True;
962 wwin->client_flags.no_titlebar = 0;
963 wwin->client_flags.no_resizebar = 0;
964 break;
966 } else {
967 if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
968 refresh = True;
969 wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
970 wwin->client_flags.no_titlebar = 0;
971 wwin->client_flags.no_resizebar = 0;
974 if (refresh)
975 wWindowConfigureBorders(wwin);
977 if (wwin->client_flags.no_focusable && !oldnofocus) {
979 sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_REMOVE,
980 wwin, 0);
981 wwin->flags.kwm_hidden_for_modules = 1;
983 } else if (!wwin->client_flags.no_focusable && oldnofocus) {
985 if (wwin->flags.kwm_hidden_for_modules) {
986 sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_ADD,
987 wwin, 0);
988 wwin->flags.kwm_hidden_for_modules = 0;
991 } else if (event->atom == _XA_KWM_WIN_DESKTOP && wwin->frame) {
992 #ifdef DEBUG1
993 printf("got KDE workspace change for %s\n", wwin->frame->title);
994 #endif
995 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &value)
996 && value-1 != wwin->frame->workspace) {
997 wWindowChangeWorkspace(wwin, value-1);
1000 } else if (event->atom == _XA_KWM_WIN_GEOMETRY_RESTORE) {
1001 WArea area;
1003 #ifdef DEBUG1
1004 printf("got KDE geometry restore change\n");
1005 #endif
1006 if (getAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, &area)
1007 && (wwin->old_geometry.x != area.x1
1008 || wwin->old_geometry.y != area.y1
1009 || wwin->old_geometry.width != area.x2 - area.x1
1010 || wwin->old_geometry.height != area.y2 - area.y1)) {
1012 wwin->old_geometry.x = area.x1;
1013 wwin->old_geometry.y = area.y1;
1014 wwin->old_geometry.width = area.x2 - area.x1;
1015 wwin->old_geometry.height = area.y2 - area.y1;
1017 } else {
1018 processed = False;
1021 return processed;
1025 static Bool
1026 performWindowCommand(WScreen *scr, char *command)
1028 WWindow *wwin = NULL;
1031 wwin = scr->focused_window;
1032 if (!wwin || !wwin->flags.focused || !wwin->flags.mapped) {
1033 wwin = NULL;
1036 CloseWindowMenu(scr);
1039 if (strcmp(command, "winMove")==0 || strcmp(command, "winResize")==0) {
1041 if (wwin)
1042 wKeyboardMoveResizeWindow(wwin);
1044 } else if (strcmp(command, "winMaximize")==0) {
1046 if (wwin)
1047 wMaximizeWindow(wwin, MAX_VERTICAL|MAX_HORIZONTAL);
1049 } else if (strcmp(command, "winRestore")==0) {
1051 if (wwin && wwin->flags.maximized)
1052 wUnmaximizeWindow(wwin);
1054 } else if (strcmp(command, "winIconify")==0) {
1057 if (wwin && !WFLAGP(wwin, no_miniaturizable)) {
1058 if (wwin->protocols.MINIATURIZE_WINDOW)
1059 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
1060 LastTimestamp);
1061 else {
1062 wIconifyWindow(wwin);
1066 } else if (strcmp(command, "winClose")==0) {
1068 if (wwin && !WFLAGP(wwin, no_closable)) {
1069 if (wwin->protocols.DELETE_WINDOW)
1070 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
1073 } else if (strcmp(command, "winSticky")==0) {
1075 if (wwin) {
1076 wWindowSetOmnipresent(wwin, !wwin->client_flags.omnipresent);
1079 } else if (strcmp(command, "winShade")==0) {
1081 if (wwin && !WFLAGP(wwin, no_shadeable)) {
1082 if (wwin->flags.shaded)
1083 wUnshadeWindow(wwin);
1084 else
1085 wShadeWindow(wwin);
1088 } else if (strcmp(command, "winOperation")==0) {
1090 if (wwin)
1091 OpenWindowMenu(wwin, wwin->frame_x,
1092 wwin->frame_y+wwin->frame->top_width, True);
1094 } else {
1095 return False;
1098 return True;
1102 static void
1103 performCommand(WScreen *scr, char *command, XClientMessageEvent *event)
1105 assert(scr != NULL);
1107 if (strcmp(command, "commandLine")==0
1108 || strcmp(command, "execute")==0) {
1109 char *cmd;
1111 cmd = ExpandOptions(scr, _("%a(Run Command,Type the command to run:)"));
1112 if (cmd) {
1113 ExecuteShellCommand(scr, cmd);
1114 wfree(cmd);
1116 } else if (strcmp(command, "logout")==0) {
1118 Shutdown(WSLogoutMode);
1120 } else if (strcmp(command, "refreshScreen")==0) {
1122 wRefreshDesktop(scr);
1124 } else if (strncmp(command, "go:", 3)==0) {
1126 Shutdown(WSRestartPreparationMode);
1127 Restart(&command[3], False);
1128 Restart(NULL, True);
1130 } else if (strcmp(command, "desktop+1")==0) {
1132 wWorkspaceRelativeChange(scr, 1);
1134 } else if (strcmp(command, "desktop-1")==0) {
1136 wWorkspaceRelativeChange(scr, -1);
1138 } else if (strcmp(command, "desktop+2")==0) {
1140 wWorkspaceRelativeChange(scr, 2);
1142 } else if (strcmp(command, "desktop-2")==0) {
1144 wWorkspaceRelativeChange(scr, -2);
1146 } else if (strcmp(command, "desktop%%2")==0) {
1148 if (scr->current_workspace % 2 == 1)
1149 wWorkspaceRelativeChange(scr, 1);
1150 else
1151 wWorkspaceRelativeChange(scr, -1);
1152 } else if (strncmp(command, "desktop", 7)==0) {
1153 int ws;
1155 ws = atoi(&command[7]);
1156 wWorkspaceChange(scr, ws);
1158 /* wmaker specific stuff */
1159 } else if (strcmp(command, "wmaker:info")==0) {
1161 wShowInfoPanel(scr);
1163 } else if (strcmp(command, "wmaker:legal")==0) {
1165 wShowLegalPanel(scr);
1167 } else if (strcmp(command, "wmaker:arrangeIcons")==0) {
1169 wArrangeIcons(scr, True);
1171 } else if (strcmp(command, "wmaker:showAll")==0) {
1173 wShowAllWindows(scr);
1175 } else if (strcmp(command, "wmaker:hideOthers")==0) {
1177 wHideOtherApplications(scr->focused_window);
1179 } else if (strcmp(command, "wmaker:restart")==0) {
1181 Shutdown(WSRestartPreparationMode);
1182 Restart(NULL, True);
1184 } else if (strcmp(command, "wmaker:exit")==0) {
1186 Shutdown(WSExitMode);
1188 #ifdef UNSUPPORTED_STUFF
1189 } else if (strcmp(command, "moduleRaised")==0) { /* useless */
1190 } else if (strcmp(command, "deskUnclutter")==0) {
1191 } else if (strcmp(command, "deskCascade")==0) {
1192 } else if (strcmp(command, "configure")==0) {
1193 } else if (strcmp(command, "taskManager")==0) {
1194 } else if (strcmp(command, "darkenScreen")==0) { /* breaks consistency */
1195 #endif
1196 } else if (!performWindowCommand(scr, command)) {
1197 KWMModuleList *module;
1198 long mask = 0;
1199 XEvent ev;
1200 /* do message relay thing */
1202 ev.xclient = *event;
1203 for (module = KWMModules; module != NULL; module = module->next) {
1205 ev.xclient.window = module->window;
1206 if (module->window == scr->root_win)
1207 mask = SubstructureRedirectMask;
1208 else
1209 mask = 0;
1211 XSendEvent(dpy, module->window, False, mask, &ev);
1217 Bool
1218 wKWMProcessClientMessage(XClientMessageEvent *event)
1220 Bool processed = True;
1221 WScreen *scr;
1222 #ifdef DEBUG1
1223 printf("CLIENT MESS %s\n", XGetAtomName(dpy, event->message_type));
1224 #endif
1225 if (event->message_type == _XA_KWM_COMMAND && event->format==8) {
1226 char buffer[24];
1227 int i;
1229 scr = wScreenForRootWindow(event->window);
1231 for (i=0; i<20; i++) {
1232 buffer[i] = event->data.b[i];
1234 buffer[i] = 0;
1236 #ifdef DEBUG1
1237 printf("got KDE command %s\n", buffer);
1238 #endif
1239 performCommand(scr, buffer, event);
1241 } else if (event->message_type == _XA_KWM_ACTIVATE_WINDOW) {
1242 WWindow *wwin;
1244 #ifdef DEBUG1
1245 printf("got KDE activate internal\n");
1246 #endif
1247 wwin = wWindowFor(event->data.l[0]);
1249 if (wwin)
1250 wSetFocusTo(wwin->screen_ptr, wwin);
1252 } else if (event->message_type == _XA_KWM_DO_NOT_MANAGE
1253 && event->format == 8) {
1254 KWMDoNotManageList *node;
1255 int i;
1257 #ifdef DEBUG1
1258 printf("got KDE dont manage\n");
1259 #endif
1261 node = malloc(sizeof(KWMDoNotManageList));
1262 if (!node) {
1263 wwarning("out of memory processing KWM_DO_NOT_MANAGE message");
1265 for (i=0; i<20 && event->data.b[i]; i++)
1266 node->title[i] = event->data.b[i];
1267 node->title[i] = 0;
1269 node->next = KWMDoNotManageCrap;
1270 KWMDoNotManageCrap = node;
1272 } else if (event->message_type == _XA_KWM_MODULE) {
1273 long val;
1274 Window modwin = event->data.l[0];
1276 scr = wScreenForRootWindow(event->window);
1278 if (getSimpleHint(modwin, _XA_KWM_MODULE, &val) && val) {
1279 #ifdef DEBUG1
1280 puts("got KDE module startup");
1281 #endif
1282 addModule(scr, modwin);
1283 } else {
1284 #ifdef DEBUG1
1285 puts("got KDE module finish");
1286 #endif
1287 removeModule(scr, modwin);
1289 } else {
1290 processed = False;
1293 return processed;
1297 void
1298 wKWMCheckModule(WScreen *scr, Window window)
1300 long val;
1302 if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val) {
1303 #ifdef DEBUG1
1304 puts("got KDE module startup");
1305 #endif
1306 addModule(scr, window);
1311 Bool
1312 wKWMCheckRootHintChange(WScreen *scr, XPropertyEvent *event)
1314 Bool processed = True;
1315 long value;
1317 if (event->atom == _XA_KWM_CURRENT_DESKTOP) {
1318 if (getSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP, &value)) {
1319 #ifdef DEBUG1
1320 printf("got KDE workspace switch to %li\n", value);
1321 #endif
1322 if (value-1 != scr->current_workspace) {
1323 wWorkspaceChange(scr, value-1);
1326 } else if (event->atom == _XA_KWM_NUMBER_OF_DESKTOPS) {
1327 #ifdef DEBUG1
1328 printf("got KDE workspace number change\n");
1329 #endif
1331 if (getSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS, &value)) {
1333 /* increasing is easy... */
1334 if (value > scr->workspace_count) {
1335 scr->flags.kwm_syncing_count = 1;
1337 wWorkspaceMake(scr, value - scr->workspace_count);
1339 scr->flags.kwm_syncing_count = 0;
1341 } else if (value < scr->workspace_count) {
1342 int i;
1343 Bool rebuild = False;
1345 scr->flags.kwm_syncing_count = 1;
1347 /* decrease all we can do */
1348 for (i = scr->workspace_count; i >= value; i--) {
1349 if (!wWorkspaceDelete(scr, i)) {
1350 rebuild = True;
1351 break;
1355 scr->flags.kwm_syncing_count = 0;
1357 /* someone destroyed a workspace that can't be destroyed.
1358 * Reset the hints to reflect our internal state.
1360 if (rebuild) {
1361 wKWMUpdateWorkspaceCountHint(scr);
1365 } else {
1366 int i;
1368 processed = False;
1370 for (i = 0; i < MAX_WORKSPACES && i < scr->workspace_count; i++) {
1371 if (event->atom == _XA_KWM_DESKTOP_NAME_[i]) {
1372 char *name;
1374 name = wKWMGetWorkspaceName(scr, i);
1376 #ifdef DEBUG1
1377 printf("got KDE workspace name change to %s\n", name);
1378 #endif
1380 if (name && strncmp(name, scr->workspaces[i]->name,
1381 MAX_WORKSPACENAME_WIDTH)!=0) {
1382 scr->flags.kwm_syncing_name = 1;
1383 wWorkspaceRename(scr, i, name);
1384 scr->flags.kwm_syncing_name = 0;
1386 if (name)
1387 XFree(name);
1388 processed = True;
1389 break;
1390 } else if (event->atom == _XA_KWM_WINDOW_REGION_[i]) {
1391 #if 0
1392 WArea area;
1394 if (getAreaHint(scr->root_win, event->atom, &area)) {
1396 if (scr->totalUsableArea.x1 != area.x1
1397 || scr->totalUsableArea.y1 != area.y1
1398 || scr->totalUsableArea.x2 != area.x2
1399 || scr->totalUsableArea.y2 != area.y2) {
1400 wScreenUpdateUsableArea(scr);
1403 #else
1404 if (i == scr->current_workspace % MAX_WORKSPACES)
1405 wScreenUpdateUsableArea(scr);
1406 #endif
1408 processed = True;
1409 break;
1414 return processed;
1418 Bool
1419 wKWMManageableClient(WScreen *scr, Window win, char *title)
1421 KWMDoNotManageList *ptr, *next;
1422 long val;
1424 if (getSimpleHint(win, _XA_KWM_DOCKWINDOW, &val) && val) {
1425 addDockWindow(scr, win);
1426 return False;
1429 ptr = KWMDoNotManageCrap;
1431 * TODO: support for glob patterns or regexes
1433 if (ptr && strncmp(ptr->title, title, strlen(ptr->title))==0) {
1434 next = ptr->next;
1435 wfree(ptr);
1436 KWMDoNotManageCrap = next;
1437 #ifdef DEBUG1
1438 printf("window %s not managed per KDE request\n", title);
1439 #endif
1441 sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
1442 sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
1444 return False;
1445 } else if (ptr) {
1446 while (ptr->next) {
1447 if (strncmp(ptr->next->title, title, strlen(ptr->next->title))==0) {
1448 #ifdef DEBUG1
1449 printf("window %s not managed per KDE request\n", title);
1450 #endif
1451 next = ptr->next->next;
1452 wfree(ptr->next);
1453 ptr->next = next;
1455 sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
1456 sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
1458 return False;
1461 ptr = ptr->next;
1465 return True;
1469 void
1470 wKWMUpdateCurrentWorkspaceHint(WScreen *scr)
1472 setSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP,
1473 scr->current_workspace+1);
1475 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_CHANGE, NULL,
1476 scr->current_workspace+1);
1480 void
1481 wKWMUpdateActiveWindowHint(WScreen *scr)
1483 long val;
1484 WWindow *wwin, *tmp;
1486 if (!scr->focused_window || !scr->focused_window->flags.focused)
1487 val = None;
1488 else {
1489 val = (long)(scr->focused_window->client_win);
1491 /* raise the menubar thing */
1492 wwin = scr->focused_window;
1493 tmp = wwin->prev;
1494 while (tmp) {
1495 if (tmp->flags.kwm_menubar
1496 && tmp->transient_for == wwin->client_win) {
1497 wRaiseFrame(tmp->frame->core);
1498 break;
1500 tmp = tmp->prev;
1504 XChangeProperty(dpy, scr->root_win, _XA_KWM_ACTIVE_WINDOW,
1505 _XA_KWM_ACTIVE_WINDOW, 32, PropModeReplace,
1506 (unsigned char*)&val, 1);
1507 XFlush(dpy);
1511 void
1512 wKWMUpdateWorkspaceCountHint(WScreen *scr)
1514 if (scr->flags.kwm_syncing_count)
1515 return;
1517 setSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS,
1518 scr->workspace_count);
1520 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE, NULL,
1521 scr->workspace_count);
1525 void
1526 wKWMCheckDestroy(XDestroyWindowEvent *event)
1528 WScreen *scr;
1530 if (event->event == event->window) {
1531 return;
1534 scr = wScreenSearchForRootWindow(event->event);
1535 if (!scr) {
1536 return;
1539 removeModule(scr, event->window);
1540 removeDockWindow(scr, event->window);
1544 void
1545 wKWMUpdateWorkspaceNameHint(WScreen *scr, int workspace)
1547 char buffer[64];
1549 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
1551 if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
1552 snprintf(buffer, sizeof(buffer), "KWM_DESKTOP_NAME_%d", workspace + 1);
1554 _XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
1557 XChangeProperty(dpy, scr->root_win, _XA_KWM_DESKTOP_NAME_[workspace],
1558 XA_STRING, 8, PropModeReplace,
1559 (unsigned char*)scr->workspaces[workspace]->name,
1560 strlen(scr->workspaces[workspace]->name)+1);
1562 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NAME_CHANGE, NULL, workspace+1);
1567 void
1568 wKWMUpdateClientWorkspace(WWindow *wwin)
1570 #ifdef DEBUG1
1571 printf("updating workspace of %s to %i\n",
1572 wwin->frame->title, wwin->frame->workspace+1);
1573 #endif
1574 setSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP,
1575 wwin->frame->workspace+1);
1579 void
1580 wKWMUpdateClientGeometryRestore(WWindow *wwin)
1582 WArea rect;
1584 rect.x1 = wwin->old_geometry.x;
1585 rect.y1 = wwin->old_geometry.y;
1586 rect.x2 = wwin->old_geometry.x + wwin->old_geometry.width;
1587 rect.y2 = wwin->old_geometry.y + wwin->old_geometry.height;
1589 setAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, rect);
1593 void
1594 wKWMUpdateClientStateHint(WWindow *wwin, WKWMStateFlag flags)
1596 if (flags & KWMIconifiedFlag) {
1597 setSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED,
1598 wwin->flags.miniaturized /*|| wwin->flags.shaded
1599 || wwin->flags.hidden*/);
1601 if (flags & KWMStickyFlag) {
1602 setSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY,
1603 IS_OMNIPRESENT(wwin));
1605 if (flags & KWMMaximizedFlag) {
1606 int value = 0;
1608 if (wwin->flags.maximized & MAX_VERTICAL)
1609 value |= 2;
1610 if (wwin->flags.maximized & MAX_HORIZONTAL)
1611 value |= 1;
1613 setSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, value);
1618 Bool
1619 wKWMGetUsableArea(WScreen *scr, int head, WArea *area)
1621 char buffer[64];
1622 Bool ok;
1623 int region = scr->current_workspace % MAX_WORKSPACES;
1625 if (_XA_KWM_WINDOW_REGION_[region]==0) {
1626 snprintf(buffer, sizeof(buffer), "KWM_WINDOW_REGION_%d", 1+region);
1628 _XA_KWM_WINDOW_REGION_[region] = XInternAtom(dpy, buffer, False);
1631 ok = getAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[region], area);
1633 if (ok) {
1634 WMRect rect = wGetRectForHead(scr, head);
1636 area->x1 = WMAX(area->x1, rect.pos.x);
1637 area->x2 = WMIN(area->x2, rect.pos.x + rect.size.width);
1638 area->y1 = WMAX(area->y1, rect.pos.y);
1639 area->y2 = WMIN(area->y2, rect.pos.y + rect.size.height);
1642 return ok;
1647 Bool
1648 wKWMGetIconGeometry(WWindow *wwin, WArea *area)
1650 return getAreaHint(wwin->client_win, _XA_KWM_WIN_ICON_GEOMETRY, area);
1655 #ifdef not_used
1656 void
1657 wKWMSetUsableAreaHint(WScreen *scr, int workspace)
1659 /* if we set this after making changes of our own to the area,
1660 * the next time the area changes, we won't know what should
1661 * be the new final area. This protocol isn't worth a shit :/
1664 * According to Matthias Ettrich:
1665 * Indeed, there's no protocol to deal with the area yet in case several
1666 * clients want to influence it. It is sufficent, though, if it is clear
1667 * that one process is responsable for the area. For KDE this is kpanel, but
1668 * I see that there might be a conflict with the docking area of windowmaker
1669 * itself.
1673 #ifdef notdef
1674 char buffer[64];
1676 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
1678 if (_XA_KWM_WINDOW_REGION_[workspace]==0) {
1679 snprintf(buffer, sizeof(buffer), "KWM_WINDOW_REGION_%d", workspace+1);
1681 _XA_KWM_WINDOW_REGION_[workspace] = XInternAtom(dpy, buffer, False);
1684 setAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[workspace],
1685 scr->totalUsableArea);
1686 #endif
1688 #endif /* not_used */
1690 void
1691 wKWMSendEventMessage(WWindow *wwin, WKWMEventMessage message)
1693 Atom msg;
1695 if (wwin && (wwin->flags.internal_window
1696 || wwin->flags.kwm_hidden_for_modules
1697 || !wwin->flags.kwm_managed
1698 || WFLAGP(wwin, skip_window_list)))
1699 return;
1701 switch (message) {
1702 case WKWMAddWindow:
1703 msg = _XA_KWM_MODULE_WIN_ADD;
1704 break;
1705 case WKWMRemoveWindow:
1706 msg = _XA_KWM_MODULE_WIN_REMOVE;
1707 break;
1708 case WKWMFocusWindow:
1709 msg = _XA_KWM_MODULE_WIN_ACTIVATE;
1710 break;
1711 case WKWMRaiseWindow:
1712 msg = _XA_KWM_MODULE_WIN_RAISE;
1713 break;
1714 case WKWMLowerWindow:
1715 msg = _XA_KWM_MODULE_WIN_LOWER;
1716 break;
1717 case WKWMChangedClient:
1718 msg = _XA_KWM_MODULE_WIN_CHANGE;
1719 break;
1720 case WKWMIconChange:
1721 msg = _XA_KWM_MODULE_WIN_ICON_CHANGE;
1722 break;
1723 default:
1724 return;
1727 sendToModules(wwin ? wwin->screen_ptr : NULL, msg, wwin, 0);
1730 #if 0
1731 static void
1732 writeSocket(int sock, char *data)
1734 char buffer[128];
1736 snprintf(buffer, sizeof(buffer), "%i ", strlen(data));
1737 write(sock, buffer, strlen(buffer));
1738 write(sock, data, strlen(data));
1742 static int
1743 connectKFM(WScreen *scr)
1745 char *path;
1746 char *buffer;
1747 char *ptr;
1748 FILE *f;
1749 int pid;
1750 int sock = 0;
1751 struct sockaddr_un addr;
1752 char buf[256];
1754 path = wstrconcat(wgethomedir(), "/.kde/share/apps/kfm/pid");
1755 buffer = wstrdup(getenv("DISPLAY"));
1757 ptr = strchr(buffer, ':');
1758 if (ptr)
1759 *ptr = '_';
1761 ptr = strrchr(buffer, '.');
1762 if (ptr)
1763 *ptr = 0;
1765 char b[32];
1767 snprintf(b, sizeof(b), ".%i", scr->screen);
1769 buffer = wstrappend(buffer, b);
1771 path = wstrappend(path, buffer);
1772 wfree(buffer);
1774 /* pid file */
1775 f = fopen(path, "rb");
1776 wfree(path);
1777 if (!f)
1778 return -1;
1780 *buf = 0;
1781 fgets(buf, sizeof(buf), f);
1782 buf[sizeof(buf)] = 0;
1783 pid = atoi(buf);
1784 if (pid <= 0)
1785 return -1;
1787 if (kill(pid, 0) != 0)
1788 return -1;
1790 *buf = 0;
1791 fgets(buf, sizeof(buf), f);
1792 buf[sizeof(buf)] = 0;
1793 fclose(f);
1795 sock = socket(AF_UNIX, SOCK_STREAM, 0);
1796 if (sock < 0)
1797 return -1;
1798 addr.sun_family = AF_UNIX;
1799 strcpy(addr.sun_path, buf);
1801 if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
1802 close(sock);
1803 return -1;
1806 path = wstrconcat(wgethomedir(), "/.kde/share/apps/kfm/magic");
1807 f = fopen(path, "rb");
1808 wfree(path);
1809 if (!f) {
1810 return -1;
1812 ptr = fgets(buf, sizeof(buf), f);
1813 fclose(f);
1814 if (!ptr) {
1815 return -1;
1817 puts(buffer);
1819 ptr = wstrconcat("auth", buf);
1821 writeSocket(sock, ptr);
1822 wfree(ptr);
1824 return sock;
1826 #endif
1828 void
1829 wKWMSelectRootRegion(WScreen *scr, int x, int y, int w, int h, Bool control)
1831 #if 0
1832 char buffer[128];
1833 int sock;
1835 puts("CONNECTING");
1836 sock = connectKFM(scr);
1837 if (sock < 0)
1838 return;
1839 puts("SENDING DATA");
1841 sprintf(buffer, "selectRootIcons %i %i %i %i %c", x, y, w, h, control);
1842 writeSocket(sock, buffer);
1844 close(sock);
1845 #endif
1849 static void
1850 observer(void *self, WMNotification *notif)
1852 WScreen *scr = (WScreen*)self;
1853 WWindow *wwin = (WWindow*)WMGetNotificationObject(notif);
1854 const char *name = WMGetNotificationName(notif);
1855 void *data = WMGetNotificationClientData(notif);
1857 if (strcmp(name, WMNManaged) == 0 && wwin) {
1858 wKWMUpdateClientWorkspace(wwin);
1859 wKWMUpdateClientStateHint(wwin, KWMAllFlags);
1861 wwin->flags.kwm_managed = 1;
1863 wKWMSendEventMessage(wwin, WKWMAddWindow);
1865 } else if (strcmp(name, WMNUnmanaged) == 0 && wwin) {
1866 wwin->frame->workspace = -1;
1868 wKWMUpdateClientWorkspace(wwin);
1870 wKWMSendEventMessage(wwin, WKWMRemoveWindow);
1872 } else if (strcmp(name, WMNChangedWorkspace) == 0 && wwin) {
1873 wKWMUpdateClientWorkspace(wwin);
1874 wKWMSendEventMessage(wwin, WKWMChangedClient);
1876 } else if (strcmp(name, WMNChangedFocus) == 0) {
1877 wKWMUpdateActiveWindowHint(scr);
1878 wKWMSendEventMessage(wwin, WKWMFocusWindow);
1880 } else if (strcmp(name, WMNChangedName) == 0) {
1881 wKWMSendEventMessage(wwin, WKWMChangedClient);
1883 } else if (strcmp(name, WMNChangedState) == 0) {
1884 char *detail = (char*)data;
1886 if (strcmp(detail, "shade") == 0) {
1887 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1888 wKWMSendEventMessage(wwin, WKWMChangedClient);
1889 } else if (strcmp(detail, "omnipresent") == 0) {
1890 wKWMUpdateClientStateHint(wwin, KWMStickyFlag);
1891 wKWMSendEventMessage(wwin, WKWMChangedClient);
1892 } else if (strcmp(detail, "maximize") == 0) {
1893 wKWMUpdateClientStateHint(wwin, KWMMaximizedFlag);
1894 wKWMSendEventMessage(wwin, WKWMChangedClient);
1895 } else if (strcmp(detail, "iconify-transient") == 0) {
1896 if (wwin->flags.miniaturized) {
1897 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1898 wKWMSendEventMessage(wwin, WKWMRemoveWindow);
1899 wwin->flags.kwm_hidden_for_modules = 1;
1900 } else {
1901 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1902 if (wwin->flags.kwm_hidden_for_modules) {
1903 wKWMSendEventMessage(wwin, WKWMAddWindow);
1904 wwin->flags.kwm_hidden_for_modules = 0;
1907 } else if (strcmp(detail, "iconify") == 0) {
1908 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1909 wKWMSendEventMessage(wwin, WKWMChangedClient);
1910 } else if (strcmp(detail, "hide") == 0) {
1911 wKWMUpdateClientStateHint(wwin, KWMIconifiedFlag);
1912 wKWMSendEventMessage(wwin, WKWMChangedClient);
1915 } else if (strcmp(name, WMNChangedStacking) == 0 && wwin) {
1916 if (data == NULL)
1917 wKWMBroadcastStacking(wwin->screen_ptr);
1918 else if (strcmp(data, "lower") == 0)
1919 wKWMSendEventMessage(wwin, WKWMLowerWindow);
1920 else if (strcmp(data, "raise") == 0)
1921 wKWMSendEventMessage(wwin, WKWMRaiseWindow);
1926 static void
1927 wsobserver(void *self, WMNotification *notif)
1929 WScreen *scr = (WScreen*)WMGetNotificationObject(notif);
1930 const char *name = WMGetNotificationName(notif);
1931 void *data = WMGetNotificationClientData(notif);
1933 if (strcmp(name, WMNWorkspaceCreated) == 0) {
1934 if (!scr->flags.kwm_syncing_count) {
1935 wKWMUpdateWorkspaceCountHint(scr);
1936 wKWMUpdateWorkspaceNameHint(scr, (int)data);
1938 #ifdef not_used
1939 wKWMSetUsableAreaHint(scr, scr->workspace_count-1);
1940 #endif
1941 } else if (strcmp(name, WMNWorkspaceDestroyed) == 0) {
1942 wKWMUpdateWorkspaceCountHint(scr);
1943 } else if (strcmp(name, WMNWorkspaceNameChanged) == 0) {
1944 wKWMUpdateWorkspaceNameHint(scr, (int)data);
1945 } else if (strcmp(name, WMNWorkspaceChanged) == 0) {
1946 wKWMUpdateCurrentWorkspaceHint(scr);
1948 } else if (strcmp(name, WMNResetStacking) == 0) {
1949 wKWMBroadcastStacking(scr);
1954 #endif /* KWM_HINTS */