]> icculus.org git repositories - dana/openbox.git/blob - openbox/composite.c
don't draw windows if they are not "visible" rather than only considering their curre...
[dana/openbox.git] / openbox / composite.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    composite.c for the Openbox window manager
4    Copyright (c) 2010        Dana Jansens
5    Copyright (c) 2010        Derek Foreman
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 "composite.h"
21 #include "config.h"
22 #include "obt/display.h"
23 #include "openbox.h"
24 #include "screen.h"
25 #include "event.h"
26 #include "client.h"
27 #include "frame.h"
28 #include "geom.h"
29 #include "gettext.h"
30
31 #include <X11/Xlib.h>
32 #include <glib.h>
33
34 #ifdef USE_COMPOSITING
35
36 static gboolean composite(gpointer data);
37
38 static struct ObCompositor obcomp;
39
40 static inline void
41 time_fix(struct timeval *tv)
42 {
43     while (tv->tv_usec >= 1000000) {
44         tv->tv_usec -= 1000000;
45         ++tv->tv_sec;
46     }
47     while (tv->tv_usec < 0) {
48         tv->tv_usec += 1000000;
49         --tv->tv_sec;
50     }
51 }
52
53 static gboolean composite_need_redraw(void)
54 {
55     return TRUE;
56 }
57
58 static void get_best_fbcon(GLXFBConfig *in, int count, int depth,
59                            struct ObCompositeFBConfig *out)
60 {
61     GLXFBConfig best = 0;
62     XVisualInfo *vi;
63     int i, value, alpha, stencil, depthb;
64     gboolean rgba, db;
65
66     rgba = FALSE;
67     db = TRUE;
68     stencil = G_MAXSHORT;
69     depthb = G_MAXSHORT;
70
71     for (i = 0; i < count; i++) {
72         vi = glXGetVisualFromFBConfig(obt_display, in[i]);
73         if (vi == NULL)
74             continue;
75
76         value = vi->depth;
77         XFree(vi);
78
79         if (value != depth)
80             continue;
81
82         obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_ALPHA_SIZE, &alpha);
83         obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_BUFFER_SIZE, &value);
84
85         /* the buffer size should equal the depth or else the buffer size minus
86            the alpha size should */
87         if (value != depth && value - alpha != depth) continue;
88
89         value = 0;
90         if (depth == 32) {
91             obcomp.GetFBConfigAttrib(obt_display, in[i],
92                                      GLX_BIND_TO_TEXTURE_RGBA_EXT, &value);
93             rgba = TRUE;
94         }
95         if (!value) {
96             if (rgba) continue; /* a different one has rgba, prefer that */
97
98             obcomp.GetFBConfigAttrib(obt_display, in[i],
99                                      GLX_BIND_TO_TEXTURE_RGB_EXT, &value);
100         }
101         if (!value) // neither bind to texture?  no dice
102             continue;
103
104         /* get no doublebuffer if possible */
105         obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_DOUBLEBUFFER, &value);
106         if (value && !db) continue;
107         db = value;
108
109         /* get the smallest stencil buffer */
110         obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_STENCIL_SIZE, &value);
111         if (value > stencil) continue;
112         stencil = value;
113
114         /* get the smallest depth buffer */
115         obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_DEPTH_SIZE, &value);
116         if (value > depthb) continue;
117         depthb = value;
118
119         best = in[i];
120     }
121     out->fbc = best;
122     out->tf = rgba ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT;
123 }
124 #endif
125
126 void composite_startup(gboolean reconfig)
127 {
128     /* This function will try enable composite if config_comp is TRUE.  At the
129        end of this process, config_comp will be set to TRUE only if composite
130        is enabled, and FALSE otherwise. */
131 #ifdef USE_COMPOSITING
132     int count, val;
133     Time timestamp;
134     XWindowAttributes xa;
135     XserverRegion xr;
136     XVisualInfo tmp;
137     XVisualInfo *vi;
138     GLXFBConfig *fbcs;
139     const char *glstring;
140     gchar *astr;
141     Atom cm_atom;
142     Window cm_owner;
143     int i;
144
145     if (reconfig) return;
146     if (!config_comp) return;
147
148     if (ob_comp_indirect)
149         setenv("LIBGL_ALWAYS_INDIRECT", "1", TRUE);
150
151     config_comp = FALSE;
152
153     astr = g_strdup_printf("_NET_WM_CM_S%d", ob_screen);
154     cm_atom = XInternAtom(obt_display, astr, FALSE);
155     g_free(astr);
156
157     cm_owner = XGetSelectionOwner(obt_display, cm_atom);
158     if (cm_owner != None) {
159         g_message(_("Failed to enable composite. There is already a compositor running."));
160         return;
161     }
162
163     timestamp = event_time();
164     XSetSelectionOwner(obt_display, cm_atom, screen_support_win, timestamp);
165
166     if (XGetSelectionOwner(obt_display, cm_atom) != screen_support_win) {
167         g_message(_("Failed to enable composite. Could not acquire the composite manager selection"));
168         return;
169     }
170
171     if (!obt_display_extension_composite) {
172         g_message(
173             _("Failed to enable composite. The %s extension is missing."),
174             "XComposite");
175         return;
176     }
177
178     if (!obt_display_extension_damage) {
179         g_message(
180             _("Failed to enable composite. The %s extension is missing."),
181             "XDamage");
182         return;
183     }
184
185     if (!obt_display_extension_fixes) {
186         g_message(
187             _("Failed to enable composite. The %s extension is missing."),
188             "XFixes");
189         return;
190     }
191
192     glstring = glXQueryExtensionsString(obt_display, ob_screen);
193     if (!strstr(glstring, "GLX_EXT_texture_from_pixmap")) {
194         g_message(_("Failed to enable composite. %s is not present."),
195                   "GLX_EXT_texture_from_pixmap");
196         return;
197     }
198
199     obcomp.CreatePixmap = (CreatePixmapT)
200         glXGetProcAddress((const unsigned char*)"glXCreatePixmap");
201     if (!obcomp.CreatePixmap) {
202         g_message(_("Failed to enable composite. %s unavailable."),
203                   "glXCreatePixmap");
204         return;
205     }
206
207     obcomp.BindTexImage = (BindTexImageT)
208         glXGetProcAddress((const unsigned char*)"glXBindTexImageEXT");
209     if (!obcomp.BindTexImage) {
210         g_message(_("Failed to enable composite. %s unavailable."),
211                   "glXBindTexImage");
212         return;
213     }
214
215     obcomp.ReleaseTexImage = (ReleaseTexImageT)
216         glXGetProcAddress((const unsigned char*)"glXReleaseTexImageEXT");
217     if (!obcomp.ReleaseTexImage) {
218         g_message(_("Failed to enable composite. %s unavailable."),
219                   "glXReleaseTexImage");
220         return;
221     }
222
223     obcomp.GetFBConfigs = (GetFBConfigsT)glXGetProcAddress(
224         (const unsigned char*)"glXGetFBConfigs");
225     if (!obcomp.GetFBConfigs) {
226         g_message(_("Failed to enable composite. %s unavailable."),
227                   "glXGetFBConfigs");
228         return;
229     }
230
231     obcomp.GetFBConfigAttrib = (GetFBConfigAttribT)glXGetProcAddress(
232         (const unsigned char*)"glXGetFBConfigAttrib");
233     if (!obcomp.GetFBConfigAttrib) {
234         g_message(_("Failed to enable composite. %s unavailable."),
235                   "glXGetFBConfigAttrib");
236         return;
237     }
238
239     obcomp.overlay = XCompositeGetOverlayWindow(obt_display,
240                                                 obt_root(ob_screen));
241 //now you've done it.  better release this if we fail later!
242 //or move this get to the end?
243
244     xr = XFixesCreateRegion(obt_display, NULL, 0);
245     XFixesSetWindowShapeRegion(obt_display, obcomp.overlay, ShapeBounding, 0, 0, 0);
246     XFixesSetWindowShapeRegion(obt_display, obcomp.overlay, ShapeInput, 0, 0, xr);
247     XFixesDestroyRegion(obt_display, xr);
248
249     if (!XGetWindowAttributes(obt_display, obt_root(ob_screen), &xa)) {
250         g_message(_("Failed to enable composite. %s failed."),
251                   "XGetWindowAttributes");
252         return;
253     }
254
255     tmp.visualid = XVisualIDFromVisual(xa.visual);
256     vi = XGetVisualInfo(obt_display, VisualIDMask, &tmp, &count);
257
258     if (!count) {
259         g_message(
260             _("Failed to enable composite. Failed to get visual info."));
261         return;
262     }
263
264
265     glXGetConfig(obt_display, vi, GLX_USE_GL, &val);
266     if (!val) {
267         g_message(_("Failed to enable composite. Visual is not GL capable"));
268         return;
269     }
270
271     glXGetConfig(obt_display, vi, GLX_DOUBLEBUFFER, &val);
272     if (!val) {
273         g_message(
274             _("Failed to enable composite. Visual is not double buffered"));
275         return;
276     }
277
278     obcomp.ctx = glXCreateContext(obt_display, vi, NULL, !ob_comp_indirect);
279     XFree(vi);
280
281     fbcs = obcomp.GetFBConfigs(obt_display, ob_screen, &count);
282
283     if (!count) {
284         g_message(_("Failed to enable composite. No valid FBConfigs."));
285         return;
286     }
287
288     memset(&obcomp.PixmapConfig, 0, sizeof(obcomp.PixmapConfig));
289
290     for (i = 1; i < MAX_DEPTH + 1; i++) {
291         get_best_fbcon(fbcs, count, i, &obcomp.PixmapConfig[i]);
292     }
293
294     if (count)
295         XFree(fbcs);
296
297     printf("Best visual for 24bpp was 0x%lx\n",
298            (gulong)obcomp.PixmapConfig[24].fbc);
299     printf("Best visual for 32bpp was 0x%lx\n",
300            (gulong)obcomp.PixmapConfig[32].fbc);
301
302     g_idle_add(composite, NULL);
303
304     glXMakeCurrent(obt_display, obcomp.overlay, obcomp.ctx);
305     config_comp = TRUE;
306     obcomp.screendims = screen_physical_area_all_monitors();
307     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
308     glXSwapBuffers(obt_display, obcomp.overlay);
309     glMatrixMode(GL_PROJECTION);
310     glLoadIdentity();
311
312     glOrtho(obcomp.screendims->x,
313             obcomp.screendims->x + obcomp.screendims->width,
314             obcomp.screendims->y + obcomp.screendims->height,
315             obcomp.screendims->y,
316             -100, 100);
317     glMatrixMode(GL_MODELVIEW);
318     glLoadIdentity();
319     glDisable(GL_DEPTH_TEST);
320     glEnable(GL_TEXTURE_2D);
321     glEnable(GL_BLEND);
322     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
323 #endif
324 }
325
326 void composite_shutdown(gboolean reconfig)
327 {
328 #ifdef USE_COMPOSITING
329     if (reconfig) return;
330 #endif
331 }
332
333 static gboolean composite(gpointer data)
334 {
335 #ifdef USE_COMPOSITING
336     int attribs[] = {
337         GLX_TEXTURE_FORMAT_EXT,
338         None,
339         GLX_TEXTURE_TARGET_EXT,
340         GLX_TEXTURE_2D_EXT,
341         None
342     };
343     struct timeval start, end, dif;
344     GList *it;
345     ObWindow *win;
346     ObClient *client;
347
348 //    if (!obcomp.need_redraw)
349 //        return;
350     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
351
352 //    for (it = stacking_list; it; it = g_list_next(it)) {
353     for (it = g_list_last(stacking_list); it; it = g_list_previous(it)) {
354         gint d;
355
356         win = it->data;
357         if (win->type == OB_WINDOW_CLASS_PROMPT)
358             continue;
359
360         if (!win->mapped)
361             continue;
362
363         if (win->type == OB_WINDOW_CLASS_CLIENT) {
364             client = WINDOW_AS_CLIENT(win);
365             if (!client->frame->visible)
366                 continue;
367         }
368
369         d = window_depth(win);
370
371         attribs[1] = obcomp.PixmapConfig[d].tf;
372
373         if (win->pixmap == None)
374             win->pixmap = XCompositeNameWindowPixmap(obt_display,
375                                                      window_top(win));
376
377         if (win->gpixmap == None)
378             win->gpixmap = obcomp.CreatePixmap(obt_display,
379                                                obcomp.PixmapConfig[d].fbc,
380                                                win->pixmap, attribs);
381
382         glBindTexture(GL_TEXTURE_2D, win->texture);
383 gettimeofday(&start, NULL);
384         obcomp.BindTexImage(obt_display, win->gpixmap,
385                             GLX_FRONT_LEFT_EXT, NULL);
386 gettimeofday(&end, NULL);
387 dif.tv_sec = end.tv_sec - start.tv_sec;
388 dif.tv_usec = end.tv_usec - start.tv_usec;
389 time_fix(&dif);
390 //printf("took %f ms\n", dif.tv_sec * 1000.0 + dif.tv_usec / 1000.0);
391         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
392         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
393         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
394         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
395         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
396
397         glBegin(GL_QUADS);
398         glTexCoord2f(0, 0);
399         glVertex3f(win->comp_area.x, win->comp_area.y, 0.0);
400         glTexCoord2f(0, 1);
401         glVertex3f(win->comp_area.x,
402                    win->comp_area.y + win->comp_area.height,
403                    0.0);
404         glTexCoord2f(1, 1);
405         glVertex3f(win->comp_area.x + win->comp_area.width,
406                    win->comp_area.y + win->comp_area.height,
407                    0.0);
408         glTexCoord2f(1, 0);
409         glVertex3f(win->comp_area.x + win->comp_area.width,
410                    win->comp_area.y,
411                    0.0);
412         glEnd();
413     }
414     glXSwapBuffers(obt_display, obcomp.overlay);
415     glFinish();
416     GLenum gler;
417     while ((gler = glGetError()) != GL_NO_ERROR) {
418         printf("gl error %d\n", gler);
419     }
420     
421     obcomp.need_redraw = 0;
422 #endif
423     return TRUE;
424 }