]> icculus.org git repositories - dana/openbox.git/blob - openbox/window.c
Watch stacking changes on managed windows also, as this can change the "above" relati...
[dana/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 "unmanaged.h"
25 #include "composite.h"
26 #include "frame.h"
27 #include "openbox.h"
28 #include "prompt.h"
29 #include "debug.h"
30 #include "grab.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 ObWindow* window_new_size(ObWindowClass type, gsize size)
54 {
55     ObWindow *self;
56
57     g_assert(size >= sizeof(ObWindow));
58     self = g_slice_alloc0(size);
59     self->bytes = size;
60     self->type = type;
61     return self;
62 }
63
64 void window_set_abstract(ObWindow *self,
65                          const Window *top,
66                          const Window *redir,
67                          const ObStackingLayer *layer,
68                          const int *depth,
69                          const guint32 *alpha)
70 {
71     g_assert(!self->top && !self->redir && !self->layer && !self->depth &&
72              !self->alpha);
73 #ifdef USE_COMPOSITING
74     g_assert(self->area.width > 0 && self->area.height > 0);
75 #endif
76
77     self->top = top;
78     self->redir = redir;
79     self->layer = layer;
80     self->depth = depth;
81     self->alpha = alpha;
82
83     /* set up any things in ObWindow that require use of the abstract pointers
84        now */
85
86 #ifdef SHAPE
87 #ifdef USE_COMPOSITING
88     if (window_redir(self)) {
89         gint foo;
90         guint ufoo;
91         gint s;
92
93         XShapeQueryExtents(obt_display, window_redir(self), &s, &foo,
94                            &foo, &ufoo, &ufoo, &foo, &foo, &foo, &ufoo,
95                            &ufoo);
96         if (s) window_adjust_redir_shape(self);
97     }
98 #endif
99 #endif
100
101     if (window_redir(self))
102         composite_window_setup(self);
103 }
104
105 void window_set_top_area(ObWindow *self, const Rect *r, gint border)
106 {
107     g_assert(!self->top);
108
109 #ifdef USE_COMPOSITING
110     self->toparea = *r;
111     self->topborder = border;
112     RECT_SET(self->area, -border, -border,
113              self->toparea.width + border * 2,
114              self->toparea.height + border * 2);
115 #endif
116 }
117
118 void window_cleanup(ObWindow *self)
119 {
120     if (window_redir(self)) {
121         composite_window_cleanup(self);
122         /* when the window goes away, we will need to redraw */
123         composite_dirty();
124     }
125 }
126
127 void window_free(ObWindow *self)
128 {
129     /* The abstract pointers must not be used here, they are likely invalid
130        by now ! */
131
132     if (self->rects) XFree(self->rects);
133     g_slice_free1(self->bytes, self);
134 }
135
136 ObWindow* window_find(Window xwin)
137 {
138     return g_hash_table_lookup(window_map, &xwin);
139 }
140
141 void wfe(gpointer k, gpointer v, gpointer data)
142 {
143     ((ObWindowForeachFunc)data)(v);
144 }
145
146 void window_foreach(ObWindowForeachFunc func)
147 {
148     g_hash_table_foreach(window_map, wfe, func);
149 }
150
151 void window_add(Window *xwin, ObWindow *win)
152 {
153     g_assert(xwin != NULL);
154     g_assert(win != NULL);
155     g_hash_table_insert(window_map, xwin, win);
156 }
157
158 void window_remove(Window xwin)
159 {
160     g_assert(xwin != None);
161     g_hash_table_remove(window_map, &xwin);
162 }
163
164 void window_adjust_redir_shape(ObWindow *self)
165 {
166 #ifdef USE_COMPOSITING
167 #ifdef SHAPE
168     gint ord;
169     if (self->rects)
170         XFree(self->rects);
171     self->rects = XShapeGetRectangles(obt_display, window_redir(self),
172                                       ShapeBounding, &self->n_rects, &ord);
173 #endif
174 #endif
175 }
176
177 ObInternalWindow* window_internal_new(Window window, const Rect *area,
178                                       gint border, gint depth)
179 {
180     ObInternalWindow *self;
181
182     self = window_new(OB_WINDOW_CLASS_INTERNAL, ObInternalWindow);
183     self->window = window;
184     self->layer = OB_STACKING_LAYER_INTERNAL;
185     self->depth = depth;
186     window_set_top_area(INTERNAL_AS_WINDOW(self), area, border);
187     window_set_abstract(INTERNAL_AS_WINDOW(self),
188                         &self->window,                  /* top-most window */
189                         (depth ? &self->window : NULL), /* comp redir window */
190                         &self->layer,                   /* stacking layer */
191                         &self->depth,                   /* window depth */
192                         NULL);                          /* opacity */
193     return self;
194 }
195
196 void window_manage_all(void)
197 {
198     guint i, j, nchild;
199     Window w, *children;
200     XWMHints *wmhints;
201     XWindowAttributes attrib;
202
203     if (!XQueryTree(obt_display, RootWindow(obt_display, ob_screen),
204                     &w, &w, &children, &nchild)) {
205         ob_debug("XQueryTree failed in window_manage_all");
206         nchild = 0;
207     }
208
209     /* remove all icon windows from the list */
210     for (i = 0; i < nchild; i++) {
211         if (children[i] == None) continue;
212         wmhints = XGetWMHints(obt_display, children[i]);
213         if (wmhints) {
214             if ((wmhints->flags & IconWindowHint) &&
215                 (wmhints->icon_window != children[i]))
216                 for (j = 0; j < nchild; j++)
217                     if (children[j] == wmhints->icon_window) {
218                         /* XXX watch the window though */
219                         children[j] = None;
220                         break;
221                     }
222             XFree(wmhints);
223         }
224     }
225
226     for (i = 0; i < nchild; ++i) {
227         if (children[i] == None) continue;
228         if (window_find(children[i])) continue; /* skip our own windows */
229         if (!XGetWindowAttributes(obt_display, children[i], &attrib)) continue;
230         if (attrib.map_state == IsUnmapped || attrib.override_redirect)
231             unmanaged_new(children[i]);
232         else
233             window_manage(children[i]);
234     }
235
236     if (children) XFree(children);
237 }
238
239 void window_manage(Window win)
240 {
241     gboolean is_dockapp = FALSE;
242     Window icon_win = None;
243     XWMHints *wmhints;
244
245     /* is the window a docking app */
246     is_dockapp = FALSE;
247     if ((wmhints = XGetWMHints(obt_display, win))) {
248         if ((wmhints->flags & StateHint) &&
249             wmhints->initial_state == WithdrawnState)
250         {
251             if (wmhints->flags & IconWindowHint)
252                 icon_win = wmhints->icon_window;
253             is_dockapp = TRUE;
254         }
255         XFree(wmhints);
256     }
257
258     grab_server(TRUE);
259
260     if (is_dockapp) {
261         if (!icon_win)
262             icon_win = win;
263         dock_manage(icon_win, win);
264     }
265     else
266         client_manage(win, NULL);
267 }
268
269 void window_unmanage_all(void)
270 {
271     dock_unmanage_all();
272     client_unmanage_all();
273     unmanaged_destroy_all();
274 }