- s/sprintf/snprintf
[wmaker-crm.git] / src / kwm.c
blob223a8142e89eb738161784c9555cf18410e7ec50
1 /* kwm.c-- stuff for support for kwm hints
3 * Window Maker window manager
4 *
5 * Copyright (c) 1998, 1999 Alfredo K. Kojima
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
20 * USA.
25 * Supported stuff:
26 * ================
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 Bool
236 getSimpleHint(Window win, Atom atom, long *retval)
238 long *data = 0;
240 assert(atom!=0);
242 data = (long*)PropGetCheckProperty(win, atom, atom, 32, 1, NULL);
244 if (!data)
245 return False;
247 *retval = *data;
249 XFree(data);
251 return True;
256 static void
257 setSimpleHint(Window win, Atom atom, long value)
259 assert(atom!=0);
260 XChangeProperty(dpy, win, atom, atom,
261 32, PropModeReplace, (unsigned char*)&value, 1);
265 static void
266 sendClientMessage(WScreen *scr, Window window, Atom atom, long value)
268 XEvent event;
269 long mask = 0;
271 assert(atom!=0);
273 memset(&event, 0, sizeof(XEvent));
274 event.xclient.type = ClientMessage;
275 event.xclient.message_type = atom;
276 event.xclient.window = window;
277 event.xclient.format = 32;
278 event.xclient.data.l[0] = value;
279 event.xclient.data.l[1] = LastTimestamp;
281 if (scr && scr->root_win == window)
282 mask = SubstructureRedirectMask;
284 XSendEvent(dpy, window, False, mask, &event);
288 static void
289 sendTextMessage(WScreen *scr, Window window, Atom atom, char *text)
291 XEvent event;
292 long mask = 0;
293 int i;
295 assert(atom!=0);
297 memset(&event, 0, sizeof(XEvent));
298 event.xclient.type = ClientMessage;
299 event.xclient.message_type = atom;
300 event.xclient.window = window;
301 event.xclient.format = 8;
303 for (i=0; i<20 && text[i]; i++)
304 event.xclient.data.b[i] = text[i];
306 if (scr && scr->root_win == window)
307 mask = SubstructureRedirectMask;
309 XSendEvent(dpy, window, False, mask, &event);
313 static Bool
314 getAreaHint(Window win, Atom atom, WArea *area)
316 long *data = 0;
318 data = (long*)PropGetCheckProperty(win, atom, atom, 32, 4, NULL);
320 if (!data)
321 return False;
323 area->x1 = data[0];
324 area->y1 = data[1];
325 area->x2 = data[2] + area->x1;
326 area->y2 = data[3] + area->y1;
328 XFree(data);
330 return True;
334 static void
335 setAreaHint(Window win, Atom atom, WArea area)
337 long value[4];
339 assert(atom!=0);
340 value[0] = area.x1;
341 value[1] = area.y1;
342 value[2] = area.x2 - area.x1;
343 value[3] = area.y2 - area.y1;
344 XChangeProperty(dpy, win, atom, atom, 32, PropModeReplace,
345 (unsigned char*)&value, 4);
349 static void
350 addModule(WScreen *scr, Window window)
352 KWMModuleList *node;
353 long val;
354 WWindow *ptr;
356 node = malloc(sizeof(KWMModuleList));
357 if (!node) {
358 wwarning("out of memory while registering KDE module");
359 return;
362 node->next = KWMModules;
363 node->window = window;
364 KWMModules = node;
366 sendClientMessage(scr, window, _XA_KWM_MODULE_INIT, 0);
368 if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val==2) {
369 if (scr->kwm_dock != None) {
370 setSimpleHint(window, _XA_KWM_MODULE, 1);
371 } else {
372 KWMModuleList *ptr;
374 scr->kwm_dock = window;
376 for (ptr = KWMDockWindows; ptr!=NULL; ptr = ptr->next) {
377 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
378 ptr->window);
383 /* send list of windows */
384 for (ptr = scr->focused_window; ptr!=NULL; ptr = ptr->prev) {
385 if (!ptr->flags.kwm_hidden_for_modules
386 && !WFLAGP(ptr, skip_window_list)) {
387 sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ADD,
388 ptr->client_win);
392 /* send window stacking order */
393 wKWMSendStacking(scr, window);
395 /* send focused window */
396 if (scr->focused_window && scr->focused_window->flags.focused) {
397 sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ACTIVATE,
398 scr->focused_window->client_win);
401 /* tell who we are */
402 sendTextMessage(scr, window, _XA_KWM_COMMAND, "wm:wmaker");
405 sendClientMessage(scr, window, _XA_KWM_MODULE_INITIALIZED, 0);
406 #ifdef DEBUG1
407 KWMModules->title = NULL;
408 XFetchName(dpy, window, &KWMModules->title);
409 printf("NEW MODULE %s\n", KWMModules->title);
410 #endif
414 static void
415 removeModule(WScreen *scr, Window window)
417 KWMModuleList *next;
419 if (!KWMModules) {
420 return;
423 if (KWMModules->window == window) {
424 next = KWMModules->next;
425 #ifdef DEBUG1
426 printf("REMOVING MODULE %s\n", KWMModules->title);
427 if (KWMModules->title)
428 XFree(KWMModules->title);
429 #endif
430 wfree(KWMModules);
431 KWMModules = next;
432 } else {
433 KWMModuleList *ptr;
435 ptr = KWMModules;
436 while (ptr->next) {
437 if (ptr->next->window == window) {
438 next = ptr->next->next;
439 #ifdef DEBUG1
440 printf("REMOVING MODULE %s\n", ptr->next->title);
441 if (ptr->next->title)
442 XFree(ptr->next->title);
443 #endif
444 wfree(ptr->next);
445 ptr->next->next = next;
446 break;
448 ptr->next = ptr->next->next;
452 if (scr->kwm_dock == window)
453 scr->kwm_dock = None;
458 static void
459 addDockWindow(WScreen *scr, Window window)
461 KWMModuleList *ptr;
463 for (ptr = KWMDockWindows; ptr != NULL; ptr = ptr->next) {
464 if (ptr->window == window)
465 break;
467 if (!ptr) {
468 KWMModuleList *node;
470 node = malloc(sizeof(KWMModuleList));
471 if (!node) {
472 wwarning("out of memory while processing KDE dock window");
473 return;
475 node->next = KWMDockWindows;
476 KWMDockWindows = node;
477 node->window = window;
478 XSelectInput(dpy, window, StructureNotifyMask);
480 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
481 window);
486 static void
487 removeDockWindow(WScreen *scr, Window window)
489 if (!KWMDockWindows)
490 return;
492 if (KWMDockWindows->window == window) {
493 KWMModuleList *next;
495 sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_REMOVE,
496 window);
498 next = KWMDockWindows->next;
499 wfree(KWMDockWindows);
500 KWMDockWindows = next;
502 } else {
503 KWMModuleList *ptr, *next;
505 ptr = KWMDockWindows;
506 while (ptr->next) {
507 if (ptr->next->window == window) {
508 sendClientMessage(scr, scr->kwm_dock,
509 _XA_KWM_MODULE_DOCKWIN_REMOVE, window);
510 next = ptr->next->next;
511 wfree(ptr->next);
512 ptr->next = next;
513 return;
515 ptr = ptr->next;
521 static void
522 sendToModules(WScreen *scr, Atom atom, WWindow *wwin, long data)
524 KWMModuleList *ptr;
525 XEvent event;
526 long mask;
528 if (wwin) {
529 if (wwin->flags.kwm_hidden_for_modules
530 || WFLAGP(wwin, skip_window_list))
531 return;
532 data = wwin->client_win;
534 #ifdef DEBUG1
535 printf("notifying %s\n",XGetAtomName(dpy, atom));
536 #endif
537 memset(&event, 0, sizeof(XEvent));
538 event.xclient.type = ClientMessage;
539 event.xclient.message_type = atom;
540 event.xclient.format = 32;
541 event.xclient.data.l[1] = LastTimestamp;
543 mask = 0;
544 if (scr && scr->root_win == data)
545 mask = SubstructureRedirectMask;
547 for (ptr = KWMModules; ptr!=NULL; ptr = ptr->next) {
548 event.xclient.window = ptr->window;
549 event.xclient.data.l[0] = data;
550 XSendEvent(dpy, ptr->window, False, mask, &event);
555 void
556 wKWMInitStuff(WScreen *scr)
558 if (!_XA_KWM_WIN_STICKY) {
559 _XA_KWM_WIN_UNSAVED_DATA = XInternAtom(dpy, "KWM_WIN_UNSAVED_DATA",
560 False);
562 _XA_KWM_WIN_DECORATION = XInternAtom(dpy, "KWM_WIN_DECORATION", False);
564 _XA_KWM_WIN_DESKTOP = XInternAtom(dpy, "KWM_WIN_DESKTOP", False);
566 _XA_KWM_WIN_GEOMETRY_RESTORE = XInternAtom(dpy,
567 "KWM_WIN_GEOMETRY_RESTORE",
568 False);
570 _XA_KWM_WIN_STICKY = XInternAtom(dpy, "KWM_WIN_STICKY", False);
572 _XA_KWM_WIN_ICONIFIED = XInternAtom(dpy, "KWM_WIN_ICONIFIED", False);
574 _XA_KWM_WIN_MAXIMIZED = XInternAtom(dpy, "KWM_WIN_MAXIMIZED", False);
576 _XA_KWM_WIN_ICON_GEOMETRY = XInternAtom(dpy, "KWM_WIN_ICON_GEOMETRY",
577 False);
579 _XA_KWM_COMMAND = XInternAtom(dpy, "KWM_COMMAND", False);
581 _XA_KWM_ACTIVE_WINDOW = XInternAtom(dpy, "KWM_ACTIVE_WINDOW", False);
583 _XA_KWM_ACTIVATE_WINDOW = XInternAtom(dpy, "KWM_ACTIVATE_WINDOW",
584 False);
586 _XA_KWM_DO_NOT_MANAGE = XInternAtom(dpy, "KWM_DO_NOT_MANAGE", False);
588 _XA_KWM_CURRENT_DESKTOP = XInternAtom(dpy, "KWM_CURRENT_DESKTOP",
589 False);
591 _XA_KWM_NUMBER_OF_DESKTOPS = XInternAtom(dpy, "KWM_NUMBER_OF_DESKTOPS",
592 False);
594 _XA_KWM_DOCKWINDOW = XInternAtom(dpy, "KWM_DOCKWINDOW", False);
596 _XA_KWM_RUNNING = XInternAtom(dpy, "KWM_RUNNING", False);
598 _XA_KWM_MODULE = XInternAtom(dpy, "KWM_MODULE", False);
600 _XA_KWM_MODULE_INIT = XInternAtom(dpy, "KWM_MODULE_INIT", False);
601 _XA_KWM_MODULE_INITIALIZED = XInternAtom(dpy, "KWM_MODULE_INITIALIZED", False);
603 /* dunno what these do, but Matthias' patch contains it... */
604 _XA_KWM_MODULE_DESKTOP_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_CHANGE", False);
605 _XA_KWM_MODULE_DESKTOP_NAME_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NAME_CHANGE", False);
606 _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NUMBER_CHANGE", False);
608 _XA_KWM_MODULE_WIN_ADD = XInternAtom(dpy, "KWM_MODULE_WIN_ADD", False);
609 _XA_KWM_MODULE_WIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_WIN_REMOVE", False);
610 _XA_KWM_MODULE_WIN_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_CHANGE", False);
611 _XA_KWM_MODULE_WIN_RAISE = XInternAtom(dpy, "KWM_MODULE_WIN_RAISE", False);
612 _XA_KWM_MODULE_WIN_LOWER = XInternAtom(dpy, "KWM_MODULE_WIN_LOWER", False);
613 _XA_KWM_MODULE_WIN_ACTIVATE = XInternAtom(dpy, "KWM_MODULE_WIN_ACTIVATE", False);
614 _XA_KWM_MODULE_WIN_ICON_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_ICON_CHANGE", False);
615 _XA_KWM_MODULE_DOCKWIN_ADD = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_ADD", False);
616 _XA_KWM_MODULE_DOCKWIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_REMOVE", False);
618 memset(_XA_KWM_WINDOW_REGION_, 0, sizeof(_XA_KWM_WINDOW_REGION_));
620 memset(_XA_KWM_DESKTOP_NAME_, 0, sizeof(_XA_KWM_DESKTOP_NAME_));
623 #define SETSTR(hint, str) {\
624 static Atom a = 0; if (!a) a = XInternAtom(dpy, #hint, False);\
625 XChangeProperty(dpy, scr->root_win, a, XA_STRING, 8, PropModeReplace,\
626 (unsigned char*)str, strlen(str));}
628 SETSTR(KWM_STRING_MAXIMIZE, _("Maximize"));
629 SETSTR(KWM_STRING_UNMAXIMIZE, _("Unmaximize"));
630 SETSTR(KWM_STRING_ICONIFY, _("Miniaturize"));
631 SETSTR(KWM_STRING_UNICONIFY, _("Deminiaturize"));
632 SETSTR(KWM_STRING_STICKY, _("Omnipresent"));
633 SETSTR(KWM_STRING_UNSTICKY, _("Not Omnipresent"));
634 SETSTR(KWM_STRING_STRING_MOVE, _("Move"));
635 SETSTR(KWM_STRING_STRING_RESIZE, _("Resize"));
636 SETSTR(KWM_STRING_CLOSE, _("Close"));
637 SETSTR(KWM_STRING_TODESKTOP, _("Move To"));
638 SETSTR(KWM_STRING_ONTOCURRENTDESKTOP, _("Bring Here"));
639 #undef SETSTR
643 void
644 wKWMSendStacking(WScreen *scr, Window module)
646 WMBagIterator i;
647 WCoreWindow *core;
649 WM_ITERATE_BAG(scr->stacking_list, core, i) {
650 for (; core != NULL; core = core->stacking->under) {
651 WWindow *wwin;
653 wwin = wWindowFor(core->window);
654 if (wwin)
655 sendClientMessage(scr, module, _XA_KWM_MODULE_WIN_RAISE,
656 wwin->client_win);
662 void
663 wKWMBroadcastStacking(WScreen *scr)
665 KWMModuleList *ptr = KWMModules;
667 while (ptr) {
668 wKWMSendStacking(scr, ptr->window);
670 ptr = ptr->next;
675 char*
676 wKWMGetWorkspaceName(WScreen *scr, int workspace)
678 Atom type_ret;
679 int fmt_ret;
680 unsigned long nitems_ret;
681 unsigned long bytes_after_ret;
682 char *data = NULL, *tmp;
683 char buffer[64];
685 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
687 if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
688 snprintf(buffer, sizeof(buffer), "KWM_DESKTOP_NAME_%d", workspace + 1);
690 _XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
693 /* What do these people have against correctly using property types? */
694 if (XGetWindowProperty(dpy, scr->root_win,
695 _XA_KWM_DESKTOP_NAME_[workspace], 0, 128, False,
696 XA_STRING,
697 &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
698 (unsigned char**)&data)!=Success || !data)
699 return NULL;
701 tmp = wstrdup(data);
702 XFree(data);
704 return tmp;
708 void
709 wKWMSetInitializedHint(WScreen *scr)
711 setSimpleHint(scr->root_win, _XA_KWM_RUNNING, 1);
715 void
716 wKWMShutdown(WScreen *scr, Bool closeModules)
718 KWMModuleList *ptr;
720 XDeleteProperty(dpy, scr->root_win, _XA_KWM_RUNNING);
722 if (closeModules) {
723 for (ptr = KWMModules; ptr != NULL; ptr = ptr->next) {
724 XKillClient(dpy, ptr->window);
730 void
731 wKWMCheckClientHints(WWindow *wwin, int *layer, int *workspace)
733 long val;
735 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA, &val)
736 && val) {
738 wwin->client_flags.broken_close = 1;
740 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &val)) {
741 if (val & KWMnoFocus) {
742 wwin->client_flags.no_focusable = 1;
744 switch (val & ~KWMnoFocus) {
745 case KWMnoDecoration:
746 wwin->client_flags.no_titlebar = 1;
747 wwin->client_flags.no_resizebar = 1;
748 break;
749 case KWMtinyDecoration:
750 wwin->client_flags.no_resizebar = 1;
751 break;
752 case KWMstandaloneMenuBar:
753 wwin->client_flags.no_titlebar = 1;
754 wwin->client_flags.no_resizebar = 1;
755 wwin->client_flags.no_resizable = 1;
756 wwin->client_flags.skip_window_list = 1;
757 wwin->client_flags.no_hide_others = 1;
758 wwin->flags.kwm_menubar = 1;
759 *layer = WMMainMenuLevel;
760 break;
761 case KWMdesktopIcon:
762 *layer = WMDesktopLevel;
763 break;
764 case KWMstaysOnTop:
765 *layer = WMFloatingLevel;
766 break;
767 case KWMnormalDecoration:
768 default:
769 break;
772 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &val)) {
773 *workspace = val - 1;
778 void
779 wKWMCheckClientInitialState(WWindow *wwin)
781 long val;
782 WArea area;
784 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY, &val) && val) {
786 wwin->client_flags.omnipresent = 1;
788 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED, &val) && val) {
790 wwin->flags.miniaturized = 1;
792 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, &val)) {
793 if (val == 2)
794 wwin->flags.maximized = MAX_VERTICAL;
795 else if (val == 1)
796 wwin->flags.maximized = MAX_HORIZONTAL;
797 else if (val == 3)
798 wwin->flags.maximized = MAX_VERTICAL|MAX_HORIZONTAL;
800 if (getAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, &area)
801 && (wwin->old_geometry.x != area.x1
802 || wwin->old_geometry.y != area.y1
803 || wwin->old_geometry.width != area.x2 - area.x1
804 || wwin->old_geometry.height != area.y2 - area.y1)) {
806 wwin->old_geometry.x = area.x1;
807 wwin->old_geometry.y = area.y1;
808 wwin->old_geometry.width = area.x2 - area.x1;
809 wwin->old_geometry.height = area.y2 - area.y1;
814 Bool
815 wKWMCheckClientHintChange(WWindow *wwin, XPropertyEvent *event)
817 Bool processed = True;
818 Bool flag;
819 long value;
822 if (!wwin->frame) {
823 return False;
826 if (event->atom == _XA_KWM_WIN_UNSAVED_DATA) {
827 #ifdef DEBUG1
828 printf("got KDE unsaved data change\n");
829 #endif
831 flag = getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA,
832 &value) && value;
834 if (flag != wwin->client_flags.broken_close) {
835 wwin->client_flags.broken_close = flag;
836 if (wwin->frame)
837 wWindowUpdateButtonImages(wwin);
839 } else if (event->atom == _XA_KWM_WIN_STICKY) {
841 #ifdef DEBUG1
842 printf("got KDE sticky change\n");
843 #endif
844 flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY,
845 &value) || value;
847 if (flag != wwin->client_flags.omnipresent) {
849 wwin->client_flags.omnipresent = flag;
851 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
854 } else if (event->atom == _XA_KWM_WIN_MAXIMIZED) {
855 int bla = 0;
857 #ifdef DEBUG1
858 printf("got KDE maximize change\n");
859 #endif
860 flag = getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, &value);
862 if (flag) {
863 if (value == 3)
864 bla = MAX_VERTICAL|MAX_HORIZONTAL;
865 else if (value == 2)
866 bla = MAX_VERTICAL;
867 else if (value == 1)
868 bla = MAX_HORIZONTAL;
871 if (bla != wwin->flags.maximized) {
872 if (bla != 0)
873 wMaximizeWindow(wwin, bla);
874 else
875 wUnmaximizeWindow(wwin);
877 } else if (event->atom == _XA_KWM_WIN_ICONIFIED) {
879 #ifdef DEBUG1
880 printf("got KDE iconify change\n");
881 #endif
882 flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED,
883 &value) || value;
885 if (flag != wwin->flags.miniaturized) {
887 if (flag)
888 wIconifyWindow(wwin);
889 else
890 wDeiconifyWindow(wwin);
893 } else if (event->atom == _XA_KWM_WIN_DECORATION) {
894 Bool refresh = False;
895 int oldnofocus;
897 #ifdef DEBUG1
898 printf("got KDE decoration change\n");
899 #endif
901 oldnofocus = wwin->client_flags.no_focusable;
903 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &value)) {
904 wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
906 switch (value & ~KWMnoFocus) {
907 case KWMnoDecoration:
908 if (!WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
909 refresh = True;
911 wwin->client_flags.no_titlebar = 1;
912 wwin->client_flags.no_resizebar = 1;
913 break;
915 case KWMtinyDecoration:
916 if (WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
917 refresh = True;
919 wwin->client_flags.no_titlebar = 0;
920 wwin->client_flags.no_resizebar = 1;
921 break;
923 case KWMnormalDecoration:
924 default:
925 if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
926 refresh = True;
928 wwin->client_flags.no_titlebar = 0;
929 wwin->client_flags.no_resizebar = 0;
930 break;
932 } else {
933 if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
934 refresh = True;
935 wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
936 wwin->client_flags.no_titlebar = 0;
937 wwin->client_flags.no_resizebar = 0;
940 if (refresh)
941 wWindowConfigureBorders(wwin);
943 if (wwin->client_flags.no_focusable && !oldnofocus) {
945 sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_REMOVE,
946 wwin, 0);
947 wwin->flags.kwm_hidden_for_modules = 1;
949 } else if (!wwin->client_flags.no_focusable && oldnofocus) {
951 if (wwin->flags.kwm_hidden_for_modules) {
952 sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_ADD,
953 wwin, 0);
954 wwin->flags.kwm_hidden_for_modules = 0;
957 } else if (event->atom == _XA_KWM_WIN_DESKTOP && wwin->frame) {
958 #ifdef DEBUG1
959 printf("got KDE workspace change for %s\n", wwin->frame->title);
960 #endif
961 if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &value)
962 && value-1 != wwin->frame->workspace) {
963 wWindowChangeWorkspace(wwin, value-1);
966 } else if (event->atom == _XA_KWM_WIN_GEOMETRY_RESTORE) {
967 WArea area;
969 #ifdef DEBUG1
970 printf("got KDE geometry restore change\n");
971 #endif
972 if (getAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, &area)
973 && (wwin->old_geometry.x != area.x1
974 || wwin->old_geometry.y != area.y1
975 || wwin->old_geometry.width != area.x2 - area.x1
976 || wwin->old_geometry.height != area.y2 - area.y1)) {
978 wwin->old_geometry.x = area.x1;
979 wwin->old_geometry.y = area.y1;
980 wwin->old_geometry.width = area.x2 - area.x1;
981 wwin->old_geometry.height = area.y2 - area.y1;
983 } else {
984 processed = False;
987 return processed;
991 static Bool
992 performWindowCommand(WScreen *scr, char *command)
994 WWindow *wwin = NULL;
997 wwin = scr->focused_window;
998 if (!wwin || !wwin->flags.focused || !wwin->flags.mapped) {
999 wwin = NULL;
1002 CloseWindowMenu(scr);
1005 if (strcmp(command, "winMove")==0 || strcmp(command, "winResize")==0) {
1007 if (wwin)
1008 wKeyboardMoveResizeWindow(wwin);
1010 } else if (strcmp(command, "winMaximize")==0) {
1012 if (wwin)
1013 wMaximizeWindow(wwin, MAX_VERTICAL|MAX_HORIZONTAL);
1015 } else if (strcmp(command, "winRestore")==0) {
1017 if (wwin && wwin->flags.maximized)
1018 wUnmaximizeWindow(wwin);
1020 } else if (strcmp(command, "winIconify")==0) {
1023 if (wwin && !WFLAGP(wwin, no_miniaturizable)) {
1024 if (wwin->protocols.MINIATURIZE_WINDOW)
1025 wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
1026 LastTimestamp);
1027 else {
1028 wIconifyWindow(wwin);
1032 } else if (strcmp(command, "winClose")==0) {
1034 if (wwin && !WFLAGP(wwin, no_closable)) {
1035 if (wwin->protocols.DELETE_WINDOW)
1036 wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
1039 } else if (strcmp(command, "winSticky")==0) {
1041 if (wwin) {
1042 wwin->client_flags.omnipresent ^= 1;
1043 UpdateSwitchMenu(scr, wwin, ACTION_CHANGE_WORKSPACE);
1046 } else if (strcmp(command, "winShade")==0) {
1048 if (wwin && !WFLAGP(wwin, no_shadeable)) {
1049 if (wwin->flags.shaded)
1050 wUnshadeWindow(wwin);
1051 else
1052 wShadeWindow(wwin);
1055 } else if (strcmp(command, "winOperation")==0) {
1057 if (wwin)
1058 OpenWindowMenu(wwin, wwin->frame_x,
1059 wwin->frame_y+wwin->frame->top_width, True);
1061 } else {
1062 return False;
1065 return True;
1069 static void
1070 performCommand(WScreen *scr, char *command, XClientMessageEvent *event)
1072 assert(scr != NULL);
1074 if (strcmp(command, "commandLine")==0
1075 || strcmp(command, "execute")==0) {
1076 char *cmd;
1078 cmd = ExpandOptions(scr, _("%a(Run Command,Type the command to run:)"));
1079 if (cmd) {
1080 ExecuteShellCommand(scr, cmd);
1081 wfree(cmd);
1083 } else if (strcmp(command, "logout")==0) {
1085 Shutdown(WSLogoutMode);
1087 } else if (strcmp(command, "refreshScreen")==0) {
1089 wRefreshDesktop(scr);
1091 } else if (strncmp(command, "go:", 3)==0) {
1093 Shutdown(WSRestartPreparationMode);
1094 Restart(&command[3], False);
1095 Restart(NULL, True);
1097 } else if (strcmp(command, "desktop+1")==0) {
1099 wWorkspaceRelativeChange(scr, 1);
1101 } else if (strcmp(command, "desktop-1")==0) {
1103 wWorkspaceRelativeChange(scr, -1);
1105 } else if (strcmp(command, "desktop+2")==0) {
1107 wWorkspaceRelativeChange(scr, 2);
1109 } else if (strcmp(command, "desktop-2")==0) {
1111 wWorkspaceRelativeChange(scr, -2);
1113 } else if (strcmp(command, "desktop%%2")==0) {
1115 if (scr->current_workspace % 2 == 1)
1116 wWorkspaceRelativeChange(scr, 1);
1117 else
1118 wWorkspaceRelativeChange(scr, -1);
1119 } else if (strncmp(command, "desktop", 7)==0) {
1120 int ws;
1122 ws = atoi(&command[7]);
1123 wWorkspaceChange(scr, ws);
1125 /* wmaker specific stuff */
1126 } else if (strcmp(command, "wmaker:info")==0) {
1128 wShowInfoPanel(scr);
1130 } else if (strcmp(command, "wmaker:legal")==0) {
1132 wShowLegalPanel(scr);
1134 } else if (strcmp(command, "wmaker:arrangeIcons")==0) {
1136 wArrangeIcons(scr, True);
1138 } else if (strcmp(command, "wmaker:showAll")==0) {
1140 wShowAllWindows(scr);
1142 } else if (strcmp(command, "wmaker:hideOthers")==0) {
1144 wHideOtherApplications(scr->focused_window);
1146 } else if (strcmp(command, "wmaker:restart")==0) {
1148 Shutdown(WSRestartPreparationMode);
1149 Restart(NULL, True);
1151 } else if (strcmp(command, "wmaker:exit")==0) {
1153 Shutdown(WSExitMode);
1155 #ifdef UNSUPPORTED_STUFF
1156 } else if (strcmp(command, "moduleRaised")==0) { /* useless */
1157 } else if (strcmp(command, "deskUnclutter")==0) {
1158 } else if (strcmp(command, "deskCascade")==0) {
1159 } else if (strcmp(command, "configure")==0) {
1160 } else if (strcmp(command, "taskManager")==0) {
1161 } else if (strcmp(command, "darkenScreen")==0) { /* breaks consistency */
1162 #endif
1163 } else if (!performWindowCommand(scr, command)) {
1164 KWMModuleList *module;
1165 long mask = 0;
1166 XEvent ev;
1167 /* do message relay thing */
1169 ev.xclient = *event;
1170 for (module = KWMModules; module != NULL; module = module->next) {
1172 ev.xclient.window = module->window;
1173 if (module->window == scr->root_win)
1174 mask = SubstructureRedirectMask;
1175 else
1176 mask = 0;
1178 XSendEvent(dpy, module->window, False, mask, &ev);
1184 Bool
1185 wKWMProcessClientMessage(XClientMessageEvent *event)
1187 Bool processed = True;
1188 WScreen *scr;
1189 #ifdef DEBUG1
1190 printf("CLIENT MESS %s\n", XGetAtomName(dpy, event->message_type));
1191 #endif
1192 if (event->message_type == _XA_KWM_COMMAND && event->format==8) {
1193 char buffer[24];
1194 int i;
1196 scr = wScreenForRootWindow(event->window);
1198 for (i=0; i<20; i++) {
1199 buffer[i] = event->data.b[i];
1201 buffer[i] = 0;
1203 #ifdef DEBUG1
1204 printf("got KDE command %s\n", buffer);
1205 #endif
1206 performCommand(scr, buffer, event);
1208 } else if (event->message_type == _XA_KWM_ACTIVATE_WINDOW) {
1209 WWindow *wwin;
1211 #ifdef DEBUG1
1212 printf("got KDE activate internal\n");
1213 #endif
1214 wwin = wWindowFor(event->data.l[0]);
1216 if (wwin)
1217 wSetFocusTo(wwin->screen_ptr, wwin);
1219 } else if (event->message_type == _XA_KWM_DO_NOT_MANAGE
1220 && event->format == 8) {
1221 KWMDoNotManageList *node;
1222 int i;
1224 #ifdef DEBUG1
1225 printf("got KDE dont manage\n");
1226 #endif
1228 node = malloc(sizeof(KWMDoNotManageList));
1229 if (!node) {
1230 wwarning("out of memory processing KWM_DO_NOT_MANAGE message");
1232 for (i=0; i<20 && event->data.b[i]; i++)
1233 node->title[i] = event->data.b[i];
1234 node->title[i] = 0;
1236 node->next = KWMDoNotManageCrap;
1237 KWMDoNotManageCrap = node;
1239 } else if (event->message_type == _XA_KWM_MODULE) {
1240 long val;
1241 Window modwin = event->data.l[0];
1243 scr = wScreenForRootWindow(event->window);
1245 if (getSimpleHint(modwin, _XA_KWM_MODULE, &val) && val) {
1246 #ifdef DEBUG1
1247 puts("got KDE module startup");
1248 #endif
1249 addModule(scr, modwin);
1250 } else {
1251 #ifdef DEBUG1
1252 puts("got KDE module finish");
1253 #endif
1254 removeModule(scr, modwin);
1256 } else {
1257 processed = False;
1260 return processed;
1264 void
1265 wKWMCheckModule(WScreen *scr, Window window)
1267 long val;
1269 if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val) {
1270 #ifdef DEBUG1
1271 puts("got KDE module startup");
1272 #endif
1273 addModule(scr, window);
1278 Bool
1279 wKWMCheckRootHintChange(WScreen *scr, XPropertyEvent *event)
1281 Bool processed = True;
1282 long value;
1284 if (event->atom == _XA_KWM_CURRENT_DESKTOP) {
1285 if (getSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP, &value)) {
1286 #ifdef DEBUG1
1287 printf("got KDE workspace switch to %li\n", value);
1288 #endif
1289 if (value-1 != scr->current_workspace) {
1290 wWorkspaceChange(scr, value-1);
1293 } else if (event->atom == _XA_KWM_NUMBER_OF_DESKTOPS) {
1294 #ifdef DEBUG1
1295 printf("got KDE workspace number change\n");
1296 #endif
1298 if (getSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS, &value)) {
1300 /* increasing is easy... */
1301 if (value > scr->workspace_count) {
1302 scr->flags.kwm_syncing_count = 1;
1304 wWorkspaceMake(scr, value - scr->workspace_count);
1306 scr->flags.kwm_syncing_count = 0;
1308 } else if (value < scr->workspace_count) {
1309 int i;
1310 Bool rebuild = False;
1312 scr->flags.kwm_syncing_count = 1;
1314 /* decrease all we can do */
1315 for (i = scr->workspace_count; i >= value; i--) {
1316 if (!wWorkspaceDelete(scr, i)) {
1317 rebuild = True;
1318 break;
1322 scr->flags.kwm_syncing_count = 0;
1324 /* someone destroyed a workspace that can't be destroyed.
1325 * Reset the hints to reflect our internal state.
1327 if (rebuild) {
1328 wKWMUpdateWorkspaceCountHint(scr);
1332 } else {
1333 int i;
1335 processed = False;
1337 for (i = 0; i < MAX_WORKSPACES && i < scr->workspace_count; i++) {
1338 if (event->atom == _XA_KWM_DESKTOP_NAME_[i]) {
1339 char *name;
1341 name = wKWMGetWorkspaceName(scr, i);
1343 #ifdef DEBUG1
1344 printf("got KDE workspace name change to %s\n", name);
1345 #endif
1347 if (name && strncmp(name, scr->workspaces[i]->name,
1348 MAX_WORKSPACENAME_WIDTH)!=0) {
1349 scr->flags.kwm_syncing_name = 1;
1350 wWorkspaceRename(scr, i, name);
1351 scr->flags.kwm_syncing_name = 0;
1353 if (name)
1354 XFree(name);
1355 processed = True;
1356 break;
1357 } else if (event->atom == _XA_KWM_WINDOW_REGION_[i]) {
1358 WArea area;
1360 if (getAreaHint(scr->root_win, event->atom, &area)) {
1362 if (scr->totalUsableArea.x1 != area.x1
1363 || scr->totalUsableArea.y1 != area.y1
1364 || scr->totalUsableArea.x2 != area.x2
1365 || scr->totalUsableArea.y2 != area.y2) {
1366 wScreenUpdateUsableArea(scr);
1370 processed = True;
1371 break;
1376 return processed;
1380 Bool
1381 wKWMManageableClient(WScreen *scr, Window win, char *title)
1383 KWMDoNotManageList *ptr, *next;
1384 long val;
1386 if (getSimpleHint(win, _XA_KWM_DOCKWINDOW, &val) && val) {
1387 addDockWindow(scr, win);
1388 return False;
1391 ptr = KWMDoNotManageCrap;
1393 * TODO: support for glob patterns or regexes
1395 if (ptr && strncmp(ptr->title, title, strlen(ptr->title))==0) {
1396 next = ptr->next;
1397 wfree(ptr);
1398 KWMDoNotManageCrap = next;
1399 #ifdef DEBUG1
1400 printf("window %s not managed per KDE request\n", title);
1401 #endif
1403 sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
1404 sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
1406 return False;
1407 } else if (ptr) {
1408 while (ptr->next) {
1409 if (strncmp(ptr->next->title, title, strlen(ptr->next->title))==0) {
1410 #ifdef DEBUG1
1411 printf("window %s not managed per KDE request\n", title);
1412 #endif
1413 next = ptr->next->next;
1414 wfree(ptr->next);
1415 ptr->next = next;
1417 sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
1418 sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
1420 return False;
1423 ptr = ptr->next;
1427 return True;
1431 void
1432 wKWMUpdateCurrentWorkspaceHint(WScreen *scr)
1434 setSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP,
1435 scr->current_workspace+1);
1437 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_CHANGE, NULL,
1438 scr->current_workspace+1);
1442 void
1443 wKWMUpdateActiveWindowHint(WScreen *scr)
1445 long val;
1446 WWindow *wwin, *tmp;
1448 if (!scr->focused_window || !scr->focused_window->flags.focused)
1449 val = None;
1450 else {
1451 val = (long)(scr->focused_window->client_win);
1453 /* raise the menubar thing */
1454 wwin = scr->focused_window;
1455 tmp = wwin->prev;
1456 while (tmp) {
1457 if (tmp->flags.kwm_menubar
1458 && tmp->transient_for == wwin->client_win) {
1459 wRaiseFrame(tmp->frame->core);
1460 break;
1462 tmp = tmp->prev;
1466 XChangeProperty(dpy, scr->root_win, _XA_KWM_ACTIVE_WINDOW,
1467 _XA_KWM_ACTIVE_WINDOW, 32, PropModeReplace,
1468 (unsigned char*)&val, 1);
1469 XFlush(dpy);
1473 void
1474 wKWMUpdateWorkspaceCountHint(WScreen *scr)
1476 if (scr->flags.kwm_syncing_count)
1477 return;
1479 setSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS,
1480 scr->workspace_count);
1482 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE, NULL,
1483 scr->workspace_count);
1487 void
1488 wKWMCheckDestroy(XDestroyWindowEvent *event)
1490 WScreen *scr;
1492 if (event->event == event->window) {
1493 return;
1496 scr = wScreenSearchForRootWindow(event->event);
1497 if (!scr) {
1498 return;
1501 removeModule(scr, event->window);
1502 removeDockWindow(scr, event->window);
1506 void
1507 wKWMUpdateWorkspaceNameHint(WScreen *scr, int workspace)
1509 char buffer[64];
1511 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
1513 if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
1514 snprintf(buffer, sizeof(buffer), "KWM_DESKTOP_NAME_%d", workspace + 1);
1516 _XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
1519 XChangeProperty(dpy, scr->root_win, _XA_KWM_DESKTOP_NAME_[workspace],
1520 XA_STRING, 8, PropModeReplace,
1521 (unsigned char*)scr->workspaces[workspace]->name,
1522 strlen(scr->workspaces[workspace]->name)+1);
1524 sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NAME_CHANGE, NULL, workspace+1);
1529 void
1530 wKWMUpdateClientWorkspace(WWindow *wwin)
1532 #ifdef DEBUG1
1533 printf("updating workspace of %s to %i\n",
1534 wwin->frame->title, wwin->frame->workspace+1);
1535 #endif
1536 setSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP,
1537 wwin->frame->workspace+1);
1541 void
1542 wKWMUpdateClientGeometryRestore(WWindow *wwin)
1544 WArea rect;
1546 rect.x1 = wwin->old_geometry.x;
1547 rect.y1 = wwin->old_geometry.y;
1548 rect.x2 = wwin->old_geometry.x + wwin->old_geometry.width;
1549 rect.y2 = wwin->old_geometry.y + wwin->old_geometry.height;
1551 setAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, rect);
1555 void
1556 wKWMUpdateClientStateHint(WWindow *wwin, WKWMStateFlag flags)
1558 if (flags & KWMIconifiedFlag) {
1559 setSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED,
1560 wwin->flags.miniaturized /*|| wwin->flags.shaded
1561 || wwin->flags.hidden*/);
1563 if (flags & KWMStickyFlag) {
1564 setSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY,
1565 IS_OMNIPRESENT(wwin));
1567 if (flags & KWMMaximizedFlag) {
1568 int value = 0;
1570 if (wwin->flags.maximized & MAX_VERTICAL)
1571 value |= 2;
1572 if (wwin->flags.maximized & MAX_HORIZONTAL)
1573 value |= 1;
1575 setSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, value);
1580 Bool
1581 wKWMGetUsableArea(WScreen *scr, WArea *area)
1583 char buffer[64];
1585 if (_XA_KWM_WINDOW_REGION_[0]==0) {
1586 snprintf(buffer, sizeof(buffer), "KWM_WINDOW_REGION_%d", 1);
1588 _XA_KWM_WINDOW_REGION_[0] = XInternAtom(dpy, buffer, False);
1591 return getAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[0], area);
1596 Bool
1597 wKWMGetIconGeometry(WWindow *wwin, WArea *area)
1599 return getAreaHint(wwin->client_win, _XA_KWM_WIN_ICON_GEOMETRY, area);
1604 #ifdef not_used
1605 void
1606 wKWMSetUsableAreaHint(WScreen *scr, int workspace)
1608 /* if we set this after making changes of our own to the area,
1609 * the next time the area changes, we won't know what should
1610 * be the new final area. This protocol isn't worth a shit :/
1613 * According to Matthias Ettrich:
1614 * Indeed, there's no protocol to deal with the area yet in case several
1615 * clients want to influence it. It is sufficent, though, if it is clear
1616 * that one process is responsable for the area. For KDE this is kpanel, but
1617 * I see that there might be a conflict with the docking area of windowmaker
1618 * itself.
1622 #ifdef notdef
1623 char buffer[64];
1625 assert(workspace >= 0 && workspace < MAX_WORKSPACES);
1627 if (_XA_KWM_WINDOW_REGION_[workspace]==0) {
1628 snprintf(buffer, sizeof(buffer), "KWM_WINDOW_REGION_%d", workspace+1);
1630 _XA_KWM_WINDOW_REGION_[workspace] = XInternAtom(dpy, buffer, False);
1633 setAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[workspace],
1634 scr->totalUsableArea);
1635 #endif
1637 #endif /* not_used */
1639 void
1640 wKWMSendEventMessage(WWindow *wwin, WKWMEventMessage message)
1642 Atom msg;
1644 if (wwin && (wwin->flags.internal_window
1645 || wwin->flags.kwm_hidden_for_modules
1646 || !wwin->flags.kwm_managed
1647 || WFLAGP(wwin, skip_window_list)))
1648 return;
1650 switch (message) {
1651 case WKWMAddWindow:
1652 msg = _XA_KWM_MODULE_WIN_ADD;
1653 break;
1654 case WKWMRemoveWindow:
1655 msg = _XA_KWM_MODULE_WIN_REMOVE;
1656 break;
1657 case WKWMFocusWindow:
1658 msg = _XA_KWM_MODULE_WIN_ACTIVATE;
1659 break;
1660 case WKWMRaiseWindow:
1661 msg = _XA_KWM_MODULE_WIN_RAISE;
1662 break;
1663 case WKWMLowerWindow:
1664 msg = _XA_KWM_MODULE_WIN_LOWER;
1665 break;
1666 case WKWMChangedClient:
1667 msg = _XA_KWM_MODULE_WIN_CHANGE;
1668 break;
1669 case WKWMIconChange:
1670 msg = _XA_KWM_MODULE_WIN_ICON_CHANGE;
1671 break;
1672 default:
1673 return;
1676 sendToModules(wwin ? wwin->screen_ptr : NULL, msg, wwin, 0);
1680 static void
1681 writeSocket(int sock, char *data)
1683 char buffer[128];
1685 snprintf(buffer, sizeof(buffer), "%i ", strlen(data));
1686 write(sock, buffer, strlen(buffer));
1687 write(sock, data, strlen(data));
1691 static int
1692 connectKFM(WScreen *scr)
1694 char *path;
1695 char *buffer;
1696 char *ptr;
1697 FILE *f;
1698 int pid;
1699 int sock = 0;
1700 struct sockaddr_un addr;
1701 char buf[256];
1703 path = wstrconcat(wgethomedir(), "/.kde/share/apps/kfm/pid");
1704 buffer = wstrdup(getenv("DISPLAY"));
1706 ptr = strchr(buffer, ':');
1707 if (ptr)
1708 *ptr = '_';
1710 ptr = strrchr(buffer, '.');
1711 if (ptr)
1712 *ptr = 0;
1714 char b[32];
1716 snprintf(b, sizeof(b), ".%i", scr->screen);
1718 buffer = wstrappend(buffer, b);
1720 path = wstrappend(path, buffer);
1721 wfree(buffer);
1723 /* pid file */
1724 f = fopen(path, "r");
1725 wfree(path);
1726 if (!f)
1727 return -1;
1729 *buf = 0;
1730 fgets(buf, sizeof(buf), f);
1731 buf[sizeof(buf)] = 0;
1732 pid = atoi(buf);
1733 if (pid <= 0)
1734 return -1;
1736 if (kill(pid, 0) != 0)
1737 return -1;
1739 *buf = 0;
1740 fgets(buf, sizeof(buf), f);
1741 buf[sizeof(buf)] = 0;
1742 fclose(f);
1744 sock = socket(AF_UNIX, SOCK_STREAM, 0);
1745 if (sock < 0)
1746 return -1;
1747 addr.sun_family = AF_UNIX;
1748 strcpy(addr.sun_path, buf);
1750 if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
1751 close(sock);
1752 return -1;
1755 path = wstrconcat(wgethomedir(), "/.kde/share/apps/kfm/magic");
1756 f = fopen(path, "r");
1757 wfree(path);
1758 if (!f) {
1759 return -1;
1761 ptr = fgets(buf, sizeof(buf), f);
1762 fclose(f);
1763 if (!ptr) {
1764 return -1;
1766 puts(buffer);
1768 ptr = wstrconcat("auth", buf);
1770 writeSocket(sock, ptr);
1771 wfree(ptr);
1773 return sock;
1777 void
1778 wKWMSelectRootRegion(WScreen *scr, int x, int y, int w, int h, Bool control)
1780 #if 0
1781 char buffer[128];
1782 int sock;
1784 puts("CONNECTING");
1785 sock = connectKFM(scr);
1786 if (sock < 0)
1787 return;
1788 puts("SENDING DATA");
1790 sprintf(buffer, "selectRootIcons %i %i %i %i %c", x, y, w, h, control);
1791 writeSocket(sock, buffer);
1793 close(sock);
1794 #endif
1798 #endif /* KWM_HINTS */