1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 composite.c for the Openbox window manager
4 Copyright (c) 2010 Dana Jansens
5 Copyright (c) 2010 Derek Foreman
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.
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.
17 See the COPYING file for a copy of the GNU General Public License.
20 #include "composite.h"
22 #include "obt/display.h"
34 #ifdef USE_COMPOSITING
36 static gboolean composite(gpointer data);
38 static struct ObCompositor obcomp;
41 time_fix(struct timeval *tv)
43 while (tv->tv_usec >= 1000000) {
44 tv->tv_usec -= 1000000;
47 while (tv->tv_usec < 0) {
48 tv->tv_usec += 1000000;
53 static gboolean composite_need_redraw(void)
58 static void get_best_fbcon(GLXFBConfig *in, int count, int depth,
59 struct ObCompositeFBConfig *out)
63 int i, value, alpha, stencil, depthb;
71 for (i = 0; i < count; i++) {
72 vi = glXGetVisualFromFBConfig(obt_display, in[i]);
82 obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_ALPHA_SIZE, &alpha);
83 obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_BUFFER_SIZE, &value);
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;
91 obcomp.GetFBConfigAttrib(obt_display, in[i],
92 GLX_BIND_TO_TEXTURE_RGBA_EXT, &value);
96 if (rgba) continue; /* a different one has rgba, prefer that */
98 obcomp.GetFBConfigAttrib(obt_display, in[i],
99 GLX_BIND_TO_TEXTURE_RGB_EXT, &value);
101 if (!value) // neither bind to texture? no dice
104 /* get no doublebuffer if possible */
105 obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_DOUBLEBUFFER, &value);
106 if (value && !db) continue;
109 /* get the smallest stencil buffer */
110 obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_STENCIL_SIZE, &value);
111 if (value > stencil) continue;
114 /* get the smallest depth buffer */
115 obcomp.GetFBConfigAttrib(obt_display, in[i], GLX_DEPTH_SIZE, &value);
116 if (value > depthb) continue;
122 out->tf = rgba ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT;
126 void composite_startup(gboolean reconfig)
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
134 XWindowAttributes xa;
139 const char *glstring;
145 if (reconfig) return;
146 if (!config_comp) return;
148 if (ob_comp_indirect)
149 setenv("LIBGL_ALWAYS_INDIRECT", "1", TRUE);
153 astr = g_strdup_printf("_NET_WM_CM_S%d", ob_screen);
154 cm_atom = XInternAtom(obt_display, astr, FALSE);
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."));
163 timestamp = event_time();
164 XSetSelectionOwner(obt_display, cm_atom, screen_support_win, timestamp);
166 if (XGetSelectionOwner(obt_display, cm_atom) != screen_support_win) {
167 g_message(_("Failed to enable composite. Could not acquire the composite manager selection"));
171 if (!obt_display_extension_composite) {
173 _("Failed to enable composite. The %s extension is missing."),
178 if (!obt_display_extension_damage) {
180 _("Failed to enable composite. The %s extension is missing."),
185 if (!obt_display_extension_fixes) {
187 _("Failed to enable composite. The %s extension is missing."),
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");
199 obcomp.CreatePixmap = (CreatePixmapT)
200 glXGetProcAddress((const unsigned char*)"glXCreatePixmap");
201 if (!obcomp.CreatePixmap) {
202 g_message(_("Failed to enable composite. %s unavailable."),
207 obcomp.BindTexImage = (BindTexImageT)
208 glXGetProcAddress((const unsigned char*)"glXBindTexImageEXT");
209 if (!obcomp.BindTexImage) {
210 g_message(_("Failed to enable composite. %s unavailable."),
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");
223 obcomp.GetFBConfigs = (GetFBConfigsT)glXGetProcAddress(
224 (const unsigned char*)"glXGetFBConfigs");
225 if (!obcomp.GetFBConfigs) {
226 g_message(_("Failed to enable composite. %s unavailable."),
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");
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?
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);
249 if (!XGetWindowAttributes(obt_display, obt_root(ob_screen), &xa)) {
250 g_message(_("Failed to enable composite. %s failed."),
251 "XGetWindowAttributes");
255 tmp.visualid = XVisualIDFromVisual(xa.visual);
256 vi = XGetVisualInfo(obt_display, VisualIDMask, &tmp, &count);
260 _("Failed to enable composite. Failed to get visual info."));
265 glXGetConfig(obt_display, vi, GLX_USE_GL, &val);
267 g_message(_("Failed to enable composite. Visual is not GL capable"));
271 glXGetConfig(obt_display, vi, GLX_DOUBLEBUFFER, &val);
274 _("Failed to enable composite. Visual is not double buffered"));
278 obcomp.ctx = glXCreateContext(obt_display, vi, NULL, !ob_comp_indirect);
281 fbcs = obcomp.GetFBConfigs(obt_display, ob_screen, &count);
284 g_message(_("Failed to enable composite. No valid FBConfigs."));
288 memset(&obcomp.PixmapConfig, 0, sizeof(obcomp.PixmapConfig));
290 for (i = 1; i < MAX_DEPTH + 1; i++) {
291 get_best_fbcon(fbcs, count, i, &obcomp.PixmapConfig[i]);
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);
302 g_idle_add(composite, NULL);
304 glXMakeCurrent(obt_display, obcomp.overlay, obcomp.ctx);
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);
312 glOrtho(obcomp.screendims->x,
313 obcomp.screendims->x + obcomp.screendims->width,
314 obcomp.screendims->y + obcomp.screendims->height,
315 obcomp.screendims->y,
317 glMatrixMode(GL_MODELVIEW);
319 glDisable(GL_DEPTH_TEST);
320 glEnable(GL_TEXTURE_2D);
322 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
326 void composite_shutdown(gboolean reconfig)
328 #ifdef USE_COMPOSITING
329 if (reconfig) return;
333 static gboolean composite(gpointer data)
335 #ifdef USE_COMPOSITING
337 GLX_TEXTURE_FORMAT_EXT,
339 GLX_TEXTURE_TARGET_EXT,
343 struct timeval start, end, dif;
348 // if (!obcomp.need_redraw)
350 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
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)) {
357 if (win->type == OB_WINDOW_CLASS_PROMPT)
363 if (win->type == OB_WINDOW_CLASS_CLIENT) {
364 client = WINDOW_AS_CLIENT(win);
365 if (!client->frame->visible)
369 d = window_depth(win);
371 attribs[1] = obcomp.PixmapConfig[d].tf;
373 if (win->pixmap == None)
374 win->pixmap = XCompositeNameWindowPixmap(obt_display,
377 if (win->gpixmap == None)
378 win->gpixmap = obcomp.CreatePixmap(obt_display,
379 obcomp.PixmapConfig[d].fbc,
380 win->pixmap, attribs);
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;
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);
399 glVertex3f(win->comp_area.x, win->comp_area.y, 0.0);
401 glVertex3f(win->comp_area.x,
402 win->comp_area.y + win->comp_area.height,
405 glVertex3f(win->comp_area.x + win->comp_area.width,
406 win->comp_area.y + win->comp_area.height,
409 glVertex3f(win->comp_area.x + win->comp_area.width,
414 glXSwapBuffers(obt_display, obcomp.overlay);
417 while ((gler = glGetError()) != GL_NO_ERROR) {
418 printf("gl error %d\n", gler);
421 obcomp.need_redraw = 0;