]> icculus.org git repositories - dana/openbox.git/blob - loco/window.c
grab the server during composite rendering
[dana/openbox.git] / loco / 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) 2008        Derek Foreman
5    Copyright (c) 2008        Dana Jansens
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.
11
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.
16
17    See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "window.h"
21 #include "screen.h"
22 #include "list.h"
23 #include "obt/prop.h"
24
25 static void pixmap_create(LocoWindow *lw);
26 static void texture_create(LocoWindow *lw);
27 static void texture_destroy(LocoWindow *lw);
28 static void pixmap_destroy(LocoWindow *lw);
29 static Bool look_for_destroy(Display *d, XEvent *e, XPointer arg);
30
31 LocoWindow* loco_window_new(Window xwin, LocoScreen *screen)
32 {
33     LocoWindow *lw;
34     XWindowAttributes attrib;
35
36     if (!XGetWindowAttributes(obt_display, xwin, &attrib))
37         return NULL;
38
39     lw = g_new0(LocoWindow, 1);
40     lw->ref = 1;
41     lw->id = xwin;
42     lw->screen = screen;
43     lw->input_only = attrib.class == InputOnly;
44     lw->x = attrib.x;
45     lw->y = attrib.y;
46     lw->w = attrib.width;
47     lw->h = attrib.height;
48     lw->depth = attrib.depth;
49
50     if (!lw->input_only) {
51         glGenTextures(1, &lw->texname);
52         /*glTexImage2D(TARGET, 0, GL_RGB, lw->w, lw->h,
53                        0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);*/
54         lw->damage = XDamageCreate(obt_display, lw->id, XDamageReportNonEmpty);
55     }
56
57     loco_screen_add_window(lw->screen, lw);
58
59     if (attrib.map_state != IsUnmapped)
60         loco_window_show(lw);
61
62     return lw;
63 }
64
65 void loco_window_ref(LocoWindow *lw)
66 {
67     ++lw->ref;
68 }
69
70 void loco_window_unref(LocoWindow *lw)
71 {
72     if (lw && --lw->ref == 0) {
73         if (!lw->input_only) {
74             texture_destroy(lw);
75             pixmap_destroy(lw);
76
77             glDeleteTextures(1, &lw->texname);
78
79             obt_display_ignore_errors(TRUE);
80             XDamageDestroy(obt_display, lw->damage);
81             obt_display_ignore_errors(FALSE);
82         }
83
84         loco_screen_remove_window(lw->screen, lw);
85
86         g_free(lw);
87     }
88 }
89
90 void loco_window_show(LocoWindow *lw) {
91     guint32 *type;
92     guint i, ntype;
93
94     lw->visible = TRUE;
95
96     /* get the window's semantic type (for different effects!) */
97     lw->type = 0; /* XXX set this to the default type */
98     if (OBT_PROP_GETA32(lw->id, NET_WM_WINDOW_TYPE, ATOM, &type, &ntype)) {
99         /* use the first value that we know about in the array */
100         for (i = 0; i < ntype; ++i) {
101             /* XXX SET THESE TO AN ENUM'S VALUES */
102             if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP))
103                 lw->type = 1;
104             if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU))
105                 lw->type = 2;
106             /* XXX there are more TYPES that need to be added to prop.h */
107         }
108         g_free(type);
109     }
110
111     loco_screen_redraw(lw->screen);
112 }
113
114 void loco_window_hide(LocoWindow *lw, gboolean gone)
115 {
116     /* if gone = TRUE, then the window is no longer available and we
117        become a zombie */
118
119     lw->visible = FALSE;
120
121     /* leave the glx texture alone though.. */
122     lw->stale = TRUE;
123     pixmap_destroy(lw);
124
125     loco_screen_redraw(lw->screen);
126
127     if (gone) {
128         loco_screen_zombie_window(lw->screen, lw);
129         lw->id = None;
130     }
131 }
132
133 void loco_window_configure(LocoWindow *lw, const XConfigureEvent *e)
134 {
135     LocoList *above, *pos;
136
137     pos = loco_screen_find_stacking(lw->screen, e->window);
138     above = loco_screen_find_stacking(lw->screen, e->above);
139
140     g_assert(pos != NULL && pos->window != NULL);
141
142     if (e->above && !above)
143         g_print("missing windows from the stacking list!!\n");
144
145     if ((lw->x != e->x) || (lw->y != e->y)) {
146         lw->x = e->x;
147         lw->y = e->y;
148
149         loco_screen_redraw(lw->screen);
150     }
151         
152     if ((lw->w != e->width) || (lw->h != e->height)) {
153         lw->w = e->width;
154         lw->h = e->height;
155
156         /* leave the glx texture alone though.. */
157         lw->stale = TRUE;
158         pixmap_destroy(lw);
159
160         loco_screen_redraw(lw->screen);
161     }
162
163     if (pos->next != above) {
164         //printf("Window 0x%lx above 0x%lx\n", pos->window->id,
165         //       above ? above->window->id : 0);
166         loco_list_move_before(&lw->screen->stacking_top,
167                               &lw->screen->stacking_bottom,
168                               pos, above);
169
170         loco_screen_redraw(lw->screen);
171     }
172 }
173
174 static Bool look_for_destroy(Display *d, XEvent *e, XPointer arg)
175 {
176     const Window w = (Window)*arg;
177     return e->type == DestroyNotify && e->xdestroywindow.window == w;
178 }
179
180 static void pixmap_create(LocoWindow *lw)
181 {
182     XEvent ce;
183
184     if (lw->pixmap) return;
185
186     /* make sure the window exists */
187     if (!XCheckIfEvent(obt_display, &ce, look_for_destroy, (XPointer)&lw->id))
188         lw->pixmap = XCompositeNameWindowPixmap(obt_display, lw->id);
189 }
190
191 static void texture_create(LocoWindow *lw)
192 {
193     static const int attrs[] = {
194         GLX_TEXTURE_FORMAT_EXT,
195         GLX_TEXTURE_FORMAT_RGBA_EXT,
196         None
197     };
198
199     if (lw->glpixmap) return;
200     if (!lw->pixmap) return;
201
202     if (!lw->screen->glxFBConfig[lw->depth]) {
203         g_print("no glxFBConfig for depth %d for window 0x%lx\n",
204                 lw->depth, lw->id);
205         return;
206     }
207     
208     lw->glpixmap = glXCreatePixmap(obt_display,
209                                    lw->screen->glxFBConfig[lw->depth],
210                                    lw->pixmap, attrs);
211     if (!lw->glpixmap) return;
212
213 #if 0
214     if (screen->queryDrawable (screen->display->display,
215                                texture->pixmap,
216                                GLX_TEXTURE_TARGET_EXT,
217                                &target))
218     {
219         fprintf (stderr, "%s: glXQueryDrawable failed\n", programName);
220
221         glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
222         texture->pixmap = None;
223
224         return FALSE;
225     }
226 #endif
227
228     glBindTexture(GL_TEXTURE_2D, lw->texname);
229
230     lw->screen->bindTexImageEXT(obt_display, lw->glpixmap,
231                                 GLX_FRONT_LEFT_EXT, NULL);
232
233     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
234     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
235
236     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
237     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
238     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
239
240     glBindTexture(GL_TEXTURE_2D, 0);
241 }
242
243 static void texture_destroy(LocoWindow *lw)
244 {
245     if (!lw->glpixmap) return;
246
247     glBindTexture(GL_TEXTURE_2D, lw->texname);
248
249     lw->screen->releaseTexImageEXT(obt_display, lw->glpixmap,
250                                    GLX_FRONT_LEFT_EXT);
251
252     glBindTexture(GL_TEXTURE_2D, 0);
253
254     obt_display_ignore_errors(TRUE);
255     glXDestroyGLXPixmap(obt_display, lw->glpixmap);
256     obt_display_ignore_errors(FALSE);
257
258     lw->glpixmap = None;
259 }
260
261 static void pixmap_destroy(LocoWindow *lw)
262 {
263     if (!lw->pixmap) return;
264
265     XFreePixmap(obt_display, lw->pixmap);
266     lw->pixmap = None;
267 }
268
269 void loco_window_update_pixmap(LocoWindow *lw)
270 {
271     if (loco_window_is_zombie(lw)) return;
272
273     if (lw->stale || lw->glpixmap == None) {
274         g_assert(lw->pixmap == None);
275
276         texture_destroy(lw);
277         pixmap_create(lw);
278         texture_create(lw);
279         lw->stale = FALSE;
280     }
281 }
282
283 gboolean loco_window_is_zombie(LocoWindow *lw)
284 {
285     return lw->id == None;
286 }