]> icculus.org git repositories - dana/openbox.git/blob - loco/window.c
7f0722565af1234dad71738bc34780e875d9826c
[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     XGrabServer(obt_display);
188     XSync(obt_display, FALSE);
189
190     if (!XCheckIfEvent(obt_display, &ce, look_for_destroy, (XPointer)&lw->id))
191         lw->pixmap = XCompositeNameWindowPixmap(obt_display, lw->id);
192     XUngrabServer(obt_display);
193 }
194
195 static void texture_create(LocoWindow *lw)
196 {
197     static const int attrs[] = {
198         GLX_TEXTURE_FORMAT_EXT,
199         GLX_TEXTURE_FORMAT_RGBA_EXT,
200         None
201     };
202
203     if (lw->glpixmap) return;
204
205     g_assert(lw->pixmap);
206
207     if (!lw->screen->glxFBConfig[lw->depth]) {
208         g_print("no glxFBConfig for depth %d for window 0x%lx\n",
209                 lw->depth, lw->id);
210         return;
211     }
212     
213     lw->glpixmap = glXCreatePixmap(obt_display,
214                                    lw->screen->glxFBConfig[lw->depth],
215                                    lw->pixmap, attrs);
216     if (!lw->glpixmap) return;
217
218 #if 0
219     if (screen->queryDrawable (screen->display->display,
220                                texture->pixmap,
221                                GLX_TEXTURE_TARGET_EXT,
222                                &target))
223     {
224         fprintf (stderr, "%s: glXQueryDrawable failed\n", programName);
225
226         glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
227         texture->pixmap = None;
228
229         return FALSE;
230     }
231 #endif
232
233     glBindTexture(GL_TEXTURE_2D, lw->texname);
234
235     lw->screen->bindTexImageEXT(obt_display, lw->glpixmap,
236                                 GLX_FRONT_LEFT_EXT, NULL);
237
238     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
239     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
240
241     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
242     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
243     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
244
245     glBindTexture(GL_TEXTURE_2D, 0);
246 }
247
248 static void texture_destroy(LocoWindow *lw)
249 {
250     if (!lw->glpixmap) return;
251
252     glBindTexture(GL_TEXTURE_2D, lw->texname);
253
254     lw->screen->releaseTexImageEXT(obt_display, lw->glpixmap,
255                                    GLX_FRONT_LEFT_EXT);
256
257     glBindTexture(GL_TEXTURE_2D, 0);
258
259     obt_display_ignore_errors(TRUE);
260     glXDestroyGLXPixmap(obt_display, lw->glpixmap);
261     obt_display_ignore_errors(FALSE);
262
263     lw->glpixmap = None;
264 }
265
266 static void pixmap_destroy(LocoWindow *lw)
267 {
268     if (!lw->pixmap) return;
269
270     XFreePixmap(obt_display, lw->pixmap);
271     lw->pixmap = None;
272 }
273
274 void loco_window_update_pixmap(LocoWindow *lw)
275 {
276     if (loco_window_is_zombie(lw)) return;
277
278     if (lw->stale || lw->glpixmap == None) {
279         g_assert(lw->pixmap == None);
280
281         texture_destroy(lw);
282         pixmap_create(lw);
283         texture_create(lw);
284         lw->stale = FALSE;
285     }
286 }
287
288 gboolean loco_window_is_zombie(LocoWindow *lw)
289 {
290     return lw->id == None;
291 }