]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/window.c
regextype
[mikachu/openbox.git] / openbox / window.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    window.c for the Openbox window manager
4    Copyright (c) 2003-2007   Dana Jansens
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 #include "window.h"
20 #include "menuframe.h"
21 #include "config.h"
22 #include "dock.h"
23 #include "client.h"
24 #include "frame.h"
25 #include "openbox.h"
26 #include "prompt.h"
27 #include "edges.h"
28 #include "debug.h"
29 #include "grab.h"
30 #include "obt/prop.h"
31 #include "obt/xqueue.h"
32
33 static GHashTable *window_map;
34
35 static guint window_hash(Window *w) { return *w; }
36 static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
37
38 void window_startup(gboolean reconfig)
39 {
40     if (reconfig) return;
41
42     window_map = g_hash_table_new((GHashFunc)window_hash,
43                                   (GEqualFunc)window_comp);
44 }
45
46 void window_shutdown(gboolean reconfig)
47 {
48     if (reconfig) return;
49
50     g_hash_table_destroy(window_map);
51 }
52
53 Window window_top(ObWindow *self)
54 {
55     switch (self->type) {
56     case OB_WINDOW_CLASS_MENUFRAME:
57         return WINDOW_AS_MENUFRAME(self)->window;
58     case OB_WINDOW_CLASS_DOCK:
59         return WINDOW_AS_DOCK(self)->frame;
60     case OB_WINDOW_CLASS_CLIENT:
61         return WINDOW_AS_CLIENT(self)->frame->window;
62     case OB_WINDOW_CLASS_INTERNAL:
63         return WINDOW_AS_INTERNAL(self)->window;
64     case OB_WINDOW_CLASS_PROMPT:
65         return WINDOW_AS_PROMPT(self)->super.window;
66     case OB_WINDOW_CLASS_EDGE:
67         return WINDOW_AS_EDGE(self)->win;
68     }
69     g_assert_not_reached();
70     return None;
71 }
72
73 ObStackingLayer window_layer(ObWindow *self)
74 {
75     switch (self->type) {
76     case OB_WINDOW_CLASS_DOCK:
77         return config_dock_layer;
78     case OB_WINDOW_CLASS_CLIENT:
79         return ((ObClient*)self)->layer;
80     case OB_WINDOW_CLASS_EDGE:
81     case OB_WINDOW_CLASS_MENUFRAME:
82     case OB_WINDOW_CLASS_INTERNAL:
83         return OB_STACKING_LAYER_INTERNAL;
84     case OB_WINDOW_CLASS_PROMPT:
85         /* not used directly for stacking, prompts are managed as clients */
86         g_assert_not_reached();
87         break;
88     }
89     g_assert_not_reached();
90     return None;
91 }
92
93 ObWindow* window_find(Window xwin)
94 {
95     return g_hash_table_lookup(window_map, &xwin);
96 }
97
98 void window_add(Window *xwin, ObWindow *win)
99 {
100     g_assert(xwin != NULL);
101     g_assert(win != NULL);
102     g_hash_table_insert(window_map, xwin, win);
103 }
104
105 void window_remove(Window xwin)
106 {
107     g_assert(xwin != None);
108     g_hash_table_remove(window_map, &xwin);
109 }
110
111 void window_manage_all(void)
112 {
113     guint i, j, nchild;
114     Window w, *children;
115     XWMHints *wmhints;
116     XWindowAttributes attrib;
117
118     if (!XQueryTree(obt_display, RootWindow(obt_display, ob_screen),
119                     &w, &w, &children, &nchild)) {
120         ob_debug("XQueryTree failed in window_manage_all");
121         nchild = 0;
122     }
123
124     /* remove all icon windows from the list */
125     for (i = 0; i < nchild; i++) {
126         if (children[i] == None) continue;
127         wmhints = XGetWMHints(obt_display, children[i]);
128         if (wmhints) {
129             if ((wmhints->flags & IconWindowHint) &&
130                 (wmhints->icon_window != children[i]))
131                 for (j = 0; j < nchild; j++)
132                     if (children[j] == wmhints->icon_window) {
133                         /* XXX watch the window though */
134                         children[j] = None;
135                         break;
136                     }
137             XFree(wmhints);
138         }
139     }
140
141     for (i = 0; i < nchild; ++i) {
142         if (children[i] == None) continue;
143         if (window_find(children[i])) continue; /* skip our own windows */
144         if (XGetWindowAttributes(obt_display, children[i], &attrib)) {
145             if (attrib.map_state == IsUnmapped)
146                 ;
147             else
148                 window_manage(children[i]);
149         }
150     }
151
152     if (children) XFree(children);
153 }
154
155 static gboolean check_unmap(XEvent *e, gpointer data)
156 {
157     const Window win = *(Window*)data;
158     return ((e->type == DestroyNotify && e->xdestroywindow.window == win) ||
159             (e->type == UnmapNotify && e->xunmap.window == win));
160 }
161
162 void window_manage(Window win)
163 {
164     XWindowAttributes attrib;
165     gboolean no_manage = FALSE;
166     gboolean is_dockapp = FALSE;
167     Window icon_win = None;
168
169     grab_server(TRUE);
170
171     /* check if it has already been unmapped by the time we started
172        mapping. the grab does a sync so we don't have to here */
173     if (xqueue_exists_local(check_unmap, &win)) {
174         ob_debug("Trying to manage unmapped window. Aborting that.");
175         no_manage = TRUE;
176     }
177     else if (!XGetWindowAttributes(obt_display, win, &attrib))
178         no_manage = TRUE;
179     else {
180         XWMHints *wmhints;
181
182         /* is the window a docking app */
183         is_dockapp = FALSE;
184         if ((wmhints = XGetWMHints(obt_display, win))) {
185             if ((wmhints->flags & StateHint) &&
186                 wmhints->initial_state == WithdrawnState)
187             {
188                 if (wmhints->flags & IconWindowHint)
189                     icon_win = wmhints->icon_window;
190                 is_dockapp = TRUE;
191             }
192             XFree(wmhints);
193         }
194         /* This is a new method to declare that a window is a dockapp, being
195            implemented by Windowmaker, to alleviate pain in writing GTK+
196            dock apps.
197            http://thread.gmane.org/gmane.comp.window-managers.openbox/4881
198         */
199         if (!is_dockapp) {
200             gchar **ss;
201             if (OBT_PROP_GETSS_TYPE(win, WM_CLASS, STRING_NO_CC, &ss))
202             {
203                 if (ss[0] && ss[1] && strcmp(ss[1], "DockApp") == 0)
204                     is_dockapp = TRUE;
205                 g_strfreev(ss);
206             }
207         }
208     }
209
210     if (!no_manage) {
211         if (attrib.override_redirect) {
212             ob_debug("not managing override redirect window 0x%x", win);
213             grab_server(FALSE);
214         }
215         else if (is_dockapp) {
216             if (!icon_win)
217                 icon_win = win;
218             dock_manage(icon_win, win);
219         }
220         else
221             client_manage(win, NULL);
222     }
223     else {
224         grab_server(FALSE);
225         ob_debug("FAILED to manage window 0x%x", win);
226     }
227 }
228
229 void window_unmanage_all(void)
230 {
231     dock_unmanage_all();
232     client_unmanage_all();
233 }