initiate
[wmaker-crm.git] / src / gnome.c
blob72be528b058b87a5574fc1860c10c01f22c9fd04
1 /* gnome.c-- support for the GNOME Hints
2 *
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.
24 * According to the author of this thing, it should not be taken seriously.
25 * IMHO, there are lot's of weirdnesses and it's quite unelegant. I'd
26 * rather not support it, but here it goes anyway.
29 #include "wconfig.h"
31 #ifdef GNOME_STUFF
33 #include <X11/Xlib.h>
34 #include <X11/Xutil.h>
35 #include <X11/Xatom.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
42 #include "WindowMaker.h"
43 #include "screen.h"
44 #include "wcore.h"
45 #include "framewin.h"
46 #include "window.h"
47 #include "workspace.h"
48 #include "funcs.h"
49 #include "actions.h"
50 #include "stacking.h"
52 #include "gnome.h"
59 #define WIN_HINTS_SKIP_FOCUS (1<<0) /*"alt-tab" skips this win*/
60 #define WIN_HINTS_SKIP_WINLIST (1<<1) /*do not show in window list*/
61 #define WIN_HINTS_SKIP_TASKBAR (1<<2) /*do not show on taskbar*/
62 #define WIN_HINTS_GROUP_TRANSIENT (1<<3) /*Reserved - definition is unclear*/
63 #define WIN_HINTS_FOCUS_ON_CLICK (1<<4) /*app only accepts focus if clicked*/
64 #ifdef HADESS_PATCH /* hadess patch but still has problem said him */
65 #define WIN_HINTS_DO_NOT_COVER (1<<5) /* attempt to not cover this window */
66 #endif
69 #define WIN_STATE_STICKY (1<<0) /*everyone knows sticky*/
70 #define WIN_STATE_MINIMIZED (1<<1) /*Reserved - definition is unclear*/
71 #define WIN_STATE_MAXIMIZED_VERT (1<<2) /*window in maximized V state*/
72 #define WIN_STATE_MAXIMIZED_HORIZ (1<<3) /*window in maximized H state*/
73 #define WIN_STATE_HIDDEN (1<<4) /*not on taskbar but window visible*/
74 #define WIN_STATE_SHADED (1<<5) /*shaded (MacOS / Afterstep style)*/
75 /* these are bogus states defined in "the spec" */
76 #define WIN_STATE_HID_WORKSPACE (1<<6) /*not on current desktop*/
77 #define WIN_STATE_HID_TRANSIENT (1<<7) /*owner of transient is hidden*/
78 #define WIN_STATE_FIXED_POSITION (1<<8) /*window is fixed in position even*/
79 #define WIN_STATE_ARRANGE_IGNORE (1<<9) /*ignore for auto arranging*/
82 #define WIN_LAYER_DESKTOP 0
83 #define WIN_LAYER_BELOW 2
84 #define WIN_LAYER_NORMAL 4
85 #define WIN_LAYER_ONTOP 6
86 #define WIN_LAYER_DOCK 8
87 #define WIN_LAYER_ABOVE_DOCK 10
88 #define WIN_LAYER_MENU 12
92 static Atom _XA_WIN_SUPPORTING_WM_CHECK = 0;
93 static Atom _XA_WIN_PROTOCOLS;
94 static Atom _XA_WIN_LAYER;
95 static Atom _XA_WIN_STATE;
96 static Atom _XA_WIN_HINTS;
97 static Atom _XA_WIN_APP_STATE;
98 static Atom _XA_WIN_EXPANDED_SIZE;
99 static Atom _XA_WIN_ICONS;
100 static Atom _XA_WIN_WORKSPACE;
101 static Atom _XA_WIN_WORKSPACE_COUNT;
102 static Atom _XA_WIN_WORKSPACE_NAMES;
103 static Atom _XA_WIN_CLIENT_LIST;
104 static Atom _XA_WIN_DESKTOP_BUTTON_PROXY;
107 void
108 wGNOMEInitStuff(WScreen *scr)
110 Atom supportedStuff[10];
111 int count;
113 if (!_XA_WIN_SUPPORTING_WM_CHECK) {
115 _XA_WIN_SUPPORTING_WM_CHECK =
116 XInternAtom(dpy, "_WIN_SUPPORTING_WM_CHECK", False);
118 _XA_WIN_PROTOCOLS = XInternAtom(dpy, "_WIN_PROTOCOLS", False);
120 _XA_WIN_LAYER = XInternAtom(dpy, "_WIN_LAYER", False);
122 _XA_WIN_STATE = XInternAtom(dpy, "_WIN_STATE", False);
124 _XA_WIN_HINTS = XInternAtom(dpy, "_WIN_HINTS", False);
126 _XA_WIN_APP_STATE = XInternAtom(dpy, "_WIN_APP_STATE", False);
128 _XA_WIN_EXPANDED_SIZE = XInternAtom(dpy, "_WIN_EXPANDED_SIZE", False);
130 _XA_WIN_ICONS = XInternAtom(dpy, "_WIN_ICONS", False);
132 _XA_WIN_WORKSPACE = XInternAtom(dpy, "_WIN_WORKSPACE", False);
134 _XA_WIN_WORKSPACE_COUNT =
135 XInternAtom(dpy, "_WIN_WORKSPACE_COUNT", False);
137 _XA_WIN_WORKSPACE_NAMES =
138 XInternAtom(dpy, "_WIN_WORKSPACE_NAMES", False);
140 _XA_WIN_CLIENT_LIST = XInternAtom(dpy, "_WIN_CLIENT_LIST", False);
142 _XA_WIN_DESKTOP_BUTTON_PROXY =
143 XInternAtom(dpy, "_WIN_DESKTOP_BUTTON_PROXY", False);
146 /* I'd rather use the ICCCM 2.0 mechanisms, but
147 * since some people prefer to reinvent the wheel instead of
148 * conforming to standards... */
150 /* setup the "We're compliant, you idiot!" hint */
152 /* why XA_CARDINAL instead of XA_WINDOW? */
153 XChangeProperty(dpy, scr->root_win, _XA_WIN_SUPPORTING_WM_CHECK,
154 XA_CARDINAL, 32, PropModeReplace,
155 (unsigned char*)&scr->no_focus_win, 1);
157 XChangeProperty(dpy, scr->no_focus_win, _XA_WIN_SUPPORTING_WM_CHECK,
158 XA_CARDINAL, 32, PropModeReplace,
159 (unsigned char*)&scr->no_focus_win, 1);
162 /* setup the "desktop button proxy" thing */
163 XChangeProperty(dpy, scr->root_win, _XA_WIN_DESKTOP_BUTTON_PROXY,
164 XA_CARDINAL, 32, PropModeReplace,
165 (unsigned char*)&scr->no_focus_win, 1);
166 XChangeProperty(dpy, scr->no_focus_win, _XA_WIN_DESKTOP_BUTTON_PROXY,
167 XA_CARDINAL, 32, PropModeReplace,
168 (unsigned char*)&scr->no_focus_win, 1);
171 /* setup the list of supported protocols */
172 count = 0;
173 supportedStuff[count++] = _XA_WIN_LAYER;
174 supportedStuff[count++] = _XA_WIN_STATE;
175 supportedStuff[count++] = _XA_WIN_HINTS;
176 supportedStuff[count++] = _XA_WIN_APP_STATE;
177 supportedStuff[count++] = _XA_WIN_EXPANDED_SIZE;
178 supportedStuff[count++] = _XA_WIN_ICONS;
179 supportedStuff[count++] = _XA_WIN_WORKSPACE;
180 supportedStuff[count++] = _XA_WIN_WORKSPACE_COUNT;
181 supportedStuff[count++] = _XA_WIN_WORKSPACE_NAMES;
182 supportedStuff[count++] = _XA_WIN_CLIENT_LIST;
184 XChangeProperty(dpy, scr->root_win, _XA_WIN_PROTOCOLS, XA_ATOM, 32,
185 PropModeReplace, (unsigned char*)supportedStuff, count);
187 XFlush(dpy);
191 void
192 wGNOMEUpdateClientListHint(WScreen *scr)
194 WWindow *wwin;
195 Window *windows;
196 int count;
198 windows = malloc(sizeof(Window)*scr->window_count);
199 if (!windows) {
200 wwarning(_("out of memory while updating GNOME hints"));
201 return;
204 count = 0;
205 wwin = scr->focused_window;
206 while (wwin) {
207 if (!wwin->flags.internal_window) {
209 windows[count++] = wwin->client_win;
212 wwin = wwin->prev;
215 XChangeProperty(dpy, scr->root_win, _XA_WIN_CLIENT_LIST, XA_CARDINAL, 32,
216 PropModeReplace, (unsigned char *)windows, count);
218 wfree(windows);
219 XFlush(dpy);
223 void
224 wGNOMEUpdateWorkspaceHints(WScreen *scr)
226 long val;
228 val = scr->workspace_count;
230 XChangeProperty(dpy, scr->root_win, _XA_WIN_WORKSPACE_COUNT, XA_CARDINAL,
231 32, PropModeReplace, (unsigned char*)&val, 1);
233 wGNOMEUpdateWorkspaceNamesHint(scr);
237 void
238 wGNOMEUpdateWorkspaceNamesHint(WScreen *scr)
240 char *wsNames[MAX_WORKSPACES];
241 XTextProperty textProp;
242 int i;
244 for (i = 0; i < scr->workspace_count; i++) {
245 wsNames[i] = scr->workspaces[i]->name;
248 if (XStringListToTextProperty(wsNames, scr->workspace_count, &textProp)) {
249 XSetTextProperty(dpy, scr->root_win, &textProp,
250 _XA_WIN_WORKSPACE_NAMES);
251 XFree(textProp.value);
256 void
257 wGNOMEUpdateCurrentWorkspaceHint(WScreen *scr)
259 long val;
261 val = scr->current_workspace;
263 XChangeProperty(dpy, scr->root_win, _XA_WIN_WORKSPACE, XA_CARDINAL,
264 32, PropModeReplace, (unsigned char*)&val, 1);
268 static int
269 getWindowLevel(int layer)
271 int level;
273 if (layer <= WIN_LAYER_DESKTOP)
274 level = WMDesktopLevel;
275 else if (layer <= WIN_LAYER_BELOW)
276 level = WMSunkenLevel;
277 else if (layer <= WIN_LAYER_NORMAL)
278 level = WMNormalLevel;
279 else if (layer <= WIN_LAYER_ONTOP)
280 level = WMFloatingLevel;
281 else if (layer <= WIN_LAYER_DOCK)
282 level = WMDockLevel;
283 else if (layer <= WIN_LAYER_ABOVE_DOCK)
284 level = WMSubmenuLevel;
285 else if (layer <= WIN_LAYER_MENU)
286 level = WMMainMenuLevel;
287 else
288 level = WMOuterSpaceLevel;
290 return level;
294 Bool
295 wGNOMECheckClientHints(WWindow *wwin, int *layer, int *workspace)
297 Atom type_ret;
298 int fmt_ret;
299 unsigned long nitems_ret;
300 unsigned long bytes_after_ret;
301 long flags, val, *data = 0;
302 Bool hasHints = False;
304 /* hints */
306 if (XGetWindowProperty(dpy, wwin->client_win, _XA_WIN_HINTS, 0, 1, False,
307 /* should be XA_INTEGER, but spec is broken */
308 XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret,
309 &bytes_after_ret,
310 (unsigned char**)&data)==Success && data) {
311 flags = *data;
313 XFree(data);
315 if (flags & (WIN_HINTS_SKIP_FOCUS|WIN_HINTS_SKIP_WINLIST)) {
316 wwin->client_flags.skip_window_list = 1;
319 #ifdef HADESS_PATCH /* hadess patch but still has problem said him */
320 if (flags & (WIN_HINTS_DO_NOT_COVER)) {
321 XWindowAttributes wattribs;
322 WReservedArea *area;
324 area = malloc(sizeof(WReservedArea));
325 if (!area) {
326 wwarning(_("out of memory while updating GNOME hints"));
327 } else {
328 XGetWindowAttributes(dpy, wwin->client_win, &wattribs);
329 wClientGetNormalHints(wwin, &wattribs, False, &area->area.x1, &area->area.y1, &area->area.x2, &area->area.y2);
330 area->area.x2 = area->area.x2 + area->area.x1;
331 area->area.y2 = area->area.y2 + area->area.y1;
333 area->window = wwin->client_win;
334 printf("area x:%d y:%d w:%d h:%d\n %s.%s\n", area->area.x1, area->area.y1, area->area.x2, area->area.y2, wwin->wm_class, wwin->wm_instance);
336 area->next = wwin->screen_ptr->reservedAreas;
337 wwin->screen_ptr->reservedAreas = area;
339 wScreenUpdateUsableArea(wwin->screen_ptr);
342 #endif
344 hasHints = True;
347 /* layer */
348 if (XGetWindowProperty(dpy, wwin->client_win, _XA_WIN_LAYER, 0, 1, False,
349 XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret,
350 &bytes_after_ret,
351 (unsigned char**)&data)==Success && data) {
352 val = *data;
354 XFree(data);
356 *layer = getWindowLevel(val);
357 hasHints = True;
360 /* workspace */
361 if (XGetWindowProperty(dpy, wwin->client_win, _XA_WIN_WORKSPACE, 0, 1,
362 False, XA_CARDINAL, &type_ret, &fmt_ret,
363 &nitems_ret, &bytes_after_ret,
364 (unsigned char**)&data)==Success && data) {
365 val = *data;
367 XFree(data);
369 if (val > 0)
370 *workspace = val;
371 hasHints = True;
374 /* reserved area */
375 if (XGetWindowProperty(dpy, wwin->client_win, _XA_WIN_EXPANDED_SIZE, 0, 1,
376 False, XA_CARDINAL, &type_ret, &fmt_ret,
377 &nitems_ret, &bytes_after_ret,
378 (unsigned char**)&data)==Success && data) {
379 WReservedArea *area;
381 area = malloc(sizeof(WReservedArea));
382 if (!area) {
383 wwarning(_("out of memory while updating GNOME hints"));
384 } else {
385 area->area.x1 = data[0];
386 area->area.y1 = data[1];
387 area->area.x2 = data[2] - data[0];
388 area->area.y2 = data[3] - data[1];
389 XFree(data);
391 area->window = wwin->client_win;
394 area->next = wwin->screen_ptr->reservedAreas;
395 wwin->screen_ptr->reservedAreas = area;
397 wScreenUpdateUsableArea(wwin->screen_ptr);
398 hasHints = True;
401 return hasHints;
405 Bool
406 wGNOMECheckInitialClientState(WWindow *wwin)
408 Atom type_ret;
409 int fmt_ret;
410 unsigned long nitems_ret;
411 unsigned long bytes_after_ret;
412 long flags, *data = 0;
414 if (XGetWindowProperty(dpy, wwin->client_win, _XA_WIN_STATE, 0, 1, False,
415 XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret,
416 &bytes_after_ret,
417 (unsigned char**)&data)!=Success || !data)
418 return False;
420 flags = *data;
422 XFree(data);
424 if (flags & WIN_STATE_STICKY)
425 wwin->client_flags.omnipresent = 1;
427 if (flags & (WIN_STATE_MAXIMIZED_VERT|WIN_STATE_MAXIMIZED_HORIZ)) {
429 if (flags & WIN_STATE_MAXIMIZED_VERT)
430 wwin->flags.maximized |= MAX_VERTICAL;
432 if (flags & WIN_STATE_MAXIMIZED_HORIZ)
433 wwin->flags.maximized |= MAX_HORIZONTAL;
436 if (flags & WIN_STATE_SHADED)
437 wwin->flags.shaded = 1;
439 return True;
443 void
444 wGNOMEUpdateClientStateHint(WWindow *wwin, Bool changedWorkspace)
446 long val;
447 long flags = 0;
449 if (changedWorkspace) {
450 val = wwin->frame->workspace;
452 XChangeProperty(dpy, wwin->client_win, _XA_WIN_WORKSPACE, XA_CARDINAL,
453 32, PropModeReplace, (unsigned char*)&val, 1);
455 if (val != wwin->screen_ptr->current_workspace)
456 flags |= WIN_STATE_HID_WORKSPACE;
459 if (IS_OMNIPRESENT(wwin))
460 flags |= WIN_STATE_STICKY;
462 if (wwin->flags.miniaturized)
463 flags |= WIN_STATE_MINIMIZED;
465 if (wwin->flags.maximized & MAX_VERTICAL)
466 flags |= WIN_STATE_MAXIMIZED_VERT;
468 if (wwin->flags.maximized & MAX_HORIZONTAL)
469 flags |= WIN_STATE_MAXIMIZED_HORIZ;
471 if (wwin->flags.shaded)
472 flags |= WIN_STATE_SHADED;
474 if (wwin->transient_for != None) {
475 WWindow *owner = wWindowFor(wwin->transient_for);
477 if (owner && !owner->flags.mapped)
478 flags |= WIN_STATE_HID_TRANSIENT;
481 /* ? */
482 if (wwin->flags.hidden)
483 flags |= WIN_STATE_HIDDEN;
485 XChangeProperty(dpy, wwin->client_win, _XA_WIN_STATE, XA_CARDINAL,
486 32, PropModeReplace, (unsigned char*)&flags, 1);
490 Bool
491 wGNOMEProcessClientMessage(XClientMessageEvent *event)
493 WScreen *scr;
494 WWindow *wwin;
495 Bool done = True;
497 scr = wScreenForWindow(event->window);
498 if (scr) {
499 /* generic client messages */
500 if (event->message_type == _XA_WIN_WORKSPACE) {
501 wWorkspaceChange(scr, event->data.l[0]);
502 } else {
503 done = False;
506 if (done)
507 return True;
510 /* window specific client messages */
512 wwin = wWindowFor(event->window);
513 if (!wwin)
514 return False;
516 if (event->message_type == _XA_WIN_LAYER) {
517 int level = getWindowLevel(event->data.l[0]);
519 if (WINDOW_LEVEL(wwin) != level) {
520 ChangeStackingLevel(wwin->frame->core, level);
522 } else if (event->message_type == _XA_WIN_STATE) {
523 int flags, mask;
524 Bool updateWindowList = False;
525 int maximize = 0;
527 mask = event->data.l[0];
528 flags = event->data.l[1];
530 if (mask & WIN_STATE_STICKY) {
531 if ((flags & WIN_STATE_STICKY) != WFLAGP(wwin, omnipresent)) {
532 wwin->client_flags.omnipresent = (flags & WIN_STATE_STICKY)!=0;
533 wGNOMEUpdateClientStateHint(wwin, False);
534 updateWindowList = True;
538 if (mask & WIN_STATE_MAXIMIZED_VERT) {
539 if (flags & WIN_STATE_MAXIMIZED_VERT)
540 maximize = MAX_VERTICAL;
541 else
542 maximize = 0;
543 } else {
544 maximize = wwin->flags.maximized & MAX_VERTICAL;
547 if (mask & WIN_STATE_MAXIMIZED_HORIZ) {
548 if (flags & WIN_STATE_MAXIMIZED_HORIZ)
549 maximize |= MAX_HORIZONTAL;
550 else
551 maximize |= 0;
552 } else {
553 maximize |= wwin->flags.maximized & MAX_HORIZONTAL;
556 if (maximize != wwin->flags.maximized) {
557 #define both (MAX_HORIZONTAL|MAX_VERTICAL)
558 if (!(maximize & both) && (wwin->flags.maximized & both)) {
559 wUnmaximizeWindow(wwin);
561 if ((maximize & both) && !(wwin->flags.maximized & both)) {
562 wMaximizeWindow(wwin, maximize);
564 updateWindowList = False;
565 #undef both
568 if (mask & WIN_STATE_SHADED) {
569 if ((flags & WIN_STATE_SHADED) != wwin->flags.shaded) {
570 if (wwin->flags.shaded)
571 wUnshadeWindow(wwin);
572 else
573 wShadeWindow(wwin);
574 updateWindowList = False;
578 if (updateWindowList) {
579 UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
581 } else if (event->message_type == _XA_WIN_WORKSPACE) {
583 if (event->data.l[0] != wwin->frame->workspace) {
584 wWindowChangeWorkspace(wwin, event->data.l[0]);
586 } else {
587 done = False;
590 return done;
594 Bool
595 wGNOMEProxyizeButtonEvent(WScreen *scr, XEvent *event)
597 if (event->type == ButtonPress)
598 XUngrabPointer(dpy, CurrentTime);
599 XSendEvent(dpy, scr->no_focus_win, False, SubstructureNotifyMask, event);
601 return True;
605 void
606 wGNOMERemoveClient(WWindow *wwin)
608 int flag = 0;
609 WReservedArea *area;
611 wGNOMEUpdateClientListHint(wwin->screen_ptr);
613 area = wwin->screen_ptr->reservedAreas;
615 if (area) {
616 if (area->window == wwin->client_win) {
617 wwin->screen_ptr->reservedAreas = area->next;
618 wfree(area);
619 flag = 1;
620 } else {
621 while (area->next && area->next->window != wwin->client_win)
622 area = area->next;
624 if (area->next) {
625 WReservedArea *next;
627 next = area->next->next;
628 wfree(area->next);
629 area->next = next;
631 flag = 1;
636 if (flag) {
637 wScreenUpdateUsableArea(wwin->screen_ptr);
642 #endif /* GNOME_STUFF */