]> icculus.org git repositories - dana/openbox.git/blob - loco/window.c
split loco into a bunch of files.
[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     if (attrib.map_state != IsUnmapped)
58         loco_window_show(lw);
59
60     return lw;
61 }
62
63 void loco_window_ref(LocoWindow *lw)
64 {
65     ++lw->ref;
66 }
67
68 void loco_window_unref(LocoWindow *lw)
69 {
70     if (lw && --lw->ref == 0) {
71         if (!lw->input_only) {
72             glDeleteTextures(1, &lw->texname);
73
74             obt_display_ignore_errors(TRUE);
75             XDamageDestroy(obt_display, lw->damage);
76             obt_display_ignore_errors(FALSE);
77         }
78
79         g_free(lw);
80     }
81 }
82
83 void loco_window_show(LocoWindow *lw) {
84     guint32 *type;
85     guint i, ntype;
86
87     lw->visible = TRUE;
88
89     /* get the window's semantic type (for different effects!) */
90     lw->type = 0; /* XXX set this to the default type */
91     if (OBT_PROP_GETA32(lw->id, NET_WM_WINDOW_TYPE, ATOM, &type, &ntype)) {
92         /* use the first value that we know about in the array */
93         for (i = 0; i < ntype; ++i) {
94             /* XXX SET THESE TO AN ENUM'S VALUES */
95             if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP))
96                 lw->type = 1;
97             if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU))
98                 lw->type = 2;
99             /* XXX there are more TYPES that need to be added to prop.h */
100         }
101         g_free(type);
102     }
103
104     loco_screen_redraw(lw->screen);
105 }
106
107 void loco_window_hide(LocoWindow *lw, gboolean destroyed)
108 {
109     /* if destroyed = TRUE, then the window is no longer available */
110
111     lw->visible = FALSE;
112
113     /* leave the glx texture alone though.. */
114     lw->stale = TRUE;
115     pixmap_destroy(lw);
116
117     loco_screen_redraw(lw->screen);
118 }
119
120 void loco_window_configure(LocoWindow *lw, const XConfigureEvent *e)
121 {
122     LocoList *above, *pos;
123
124     pos = loco_screen_find_stacking(lw->screen, e->window);
125     above = loco_screen_find_stacking(lw->screen, e->above);
126
127     g_assert(pos != NULL && pos->window != NULL);
128
129     if (e->above && !above)
130         g_error("missing windows from the stacking list!!\n");
131
132     if ((lw->x != e->x) || (lw->y != e->y)) {
133         lw->x = e->x;
134         lw->y = e->y;
135
136         loco_screen_redraw(lw->screen);
137     }
138         
139     if ((lw->w != e->width) || (lw->h != e->height)) {
140         lw->w = e->width;
141         lw->h = e->height;
142
143         /* leave the glx texture alone though.. */
144         lw->stale = TRUE;
145         pixmap_destroy(lw);
146
147         loco_screen_redraw(lw->screen);
148     }
149
150     if (pos->next != above) {
151         //printf("Window 0x%lx above 0x%lx\n", pos->window->id,
152         //       above ? above->window->id : 0);
153         loco_list_move_before(&lw->screen->stacking_top,
154                               &lw->screen->stacking_bottom,
155                               pos, above);
156
157         loco_screen_redraw(lw->screen);
158     }
159 }
160
161 static Bool look_for_destroy(Display *d, XEvent *e, XPointer arg)
162 {
163     const Window w = (Window)*arg;
164     return e->type == DestroyNotify && e->xdestroywindow.window == w;
165 }
166
167 static void pixmap_create(LocoWindow *lw)
168 {
169     XEvent ce;
170
171     if (lw->pixmap) return;
172
173     /* make sure the window exists */
174     XGrabServer(obt_display);
175     XSync(obt_display, FALSE);
176
177     if (!XCheckIfEvent(obt_display, &ce, look_for_destroy, (XPointer)&lw->id))
178         lw->pixmap = XCompositeNameWindowPixmap(obt_display, lw->id);
179     XUngrabServer(obt_display);
180 }
181
182 static void texture_create(LocoWindow *lw)
183 {
184     static const int attrs[] = {
185         GLX_TEXTURE_FORMAT_EXT,
186         GLX_TEXTURE_FORMAT_RGBA_EXT,
187         None
188     };
189
190     if (lw->glpixmap) return;
191
192     g_assert(lw->pixmap);
193
194     if (!lw->screen->glxFBConfig[lw->depth]) {
195         g_print("no glxFBConfig for depth %d for window 0x%lx\n",
196                 lw->depth, lw->id);
197         return;
198     }
199     
200     lw->glpixmap = glXCreatePixmap(obt_display,
201                                    lw->screen->glxFBConfig[lw->depth],
202                                    lw->pixmap, attrs);
203     if (!lw->glpixmap) return;
204
205 #if 0
206     if (screen->queryDrawable (screen->display->display,
207                                texture->pixmap,
208                                GLX_TEXTURE_TARGET_EXT,
209                                &target))
210     {
211         fprintf (stderr, "%s: glXQueryDrawable failed\n", programName);
212
213         glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
214         texture->pixmap = None;
215
216         return FALSE;
217     }
218 #endif
219
220     glBindTexture(GL_TEXTURE_2D, lw->texname);
221
222     lw->screen->bindTexImageEXT(obt_display, lw->glpixmap,
223                                 GLX_FRONT_LEFT_EXT, NULL);
224
225     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
226     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
227
228     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
229     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
230     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
231
232     glBindTexture(GL_TEXTURE_2D, 0);
233 }
234
235 static void texture_destroy(LocoWindow *lw)
236 {
237     if (!lw->glpixmap) return;
238
239     glBindTexture(GL_TEXTURE_2D, lw->texname);
240
241     lw->screen->releaseTexImageEXT(obt_display, lw->glpixmap,
242                                    GLX_FRONT_LEFT_EXT);
243
244     glBindTexture(GL_TEXTURE_2D, 0);
245
246     obt_display_ignore_errors(TRUE);
247     glXDestroyGLXPixmap(obt_display, lw->glpixmap);
248     obt_display_ignore_errors(FALSE);
249
250     lw->glpixmap = None;
251 }
252
253 static void pixmap_destroy(LocoWindow *lw)
254 {
255     if (!lw->pixmap) return;
256
257     XFreePixmap(obt_display, lw->pixmap);
258     lw->pixmap = None;
259 }
260
261 void loco_window_update_pixmap(LocoWindow *lw)
262 {
263     if (lw->stale || lw->glpixmap == None) {
264         g_assert(lw->pixmap == None);
265
266         texture_destroy(lw);
267         pixmap_create(lw);
268         texture_create(lw);
269         lw->stale = FALSE;
270     }
271 }