1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 loco.c for the Openbox window manager
4 Copyright (c) 2008 Derek Foreman
5 Copyright (c) 2008 Dana Jansens
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.
21 #include "obt/mainloop.h"
22 #include "obt/display.h"
23 #include "obt/mainloop.h"
28 #include <GL/glxext.h>
29 #include <GL/glxtokens.h>
31 <dana> you want CreateNotify, DestroyNotify, MapNotify, UnmapNotify, and
33 <dana> and then xdamage or whatever
39 /*const GLchar *err_file = strrchr(err_path, '/');*/ \
40 GLenum gl_error = glGetError(); \
44 for (; (gl_error); gl_error = glGetError()) \
45 fprintf(stderr, "%s: %d caught at line %u\n", \
46 __FUNCTION__, gl_error, __LINE__); \
47 /*(const GLchar*)gluErrorString(gl_error)*/ \
59 gint type; /* XXX make this an enum */
64 typedef struct _LocoList {
65 struct _LocoList *next;
66 struct _LocoList *prev;
70 static Window loco_root;
71 static Window loco_overlay;
72 /* Maps X Window ID -> LocoWindow* */
73 static GHashTable *window_map;
74 /* Maps X Window ID -> LocoList* which is in the stacking_top/bottom list */
75 static GHashTable *stacking_map;
76 /* From top to bottom */
77 static LocoList *stacking_top;
78 static LocoList *stacking_bottom;
79 static VisualID visualIDs[MAX_DEPTH + 1];
80 static XVisualInfo *glxPixmapVisuals[MAX_DEPTH + 1];
81 static int loco_screen_num;
83 void (*BindTexImageEXT)(Display *, GLXDrawable, int, const int *);
84 void (*ReleaseTexImageEXT)(Display *, GLXDrawable, int);
87 static void print_stacking()
91 for (it = stacking_top; it; it = it->next) {
92 printf("0x%lx\n", it->window->id);
97 int create_glxpixmap(LocoWindow *lw)
101 static const int attrs[] =
103 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
107 static const int drawable_tfp_attrs[] =
109 GLX_CONFIG_CAVEAT, GLX_NONE,
110 GLX_DOUBLEBUFFER, False,
116 GLX_RENDER_TYPE, GLX_RGBA_BIT,
117 GLX_BIND_TO_TEXTURE_RGBA_EXT, True, // additional for tfp
122 pixmap = XCompositeNameWindowPixmap(obt_display, lw->id);
123 visinfo = glxPixmapVisuals[lw->depth];
125 printf("no visinfo for depth %d\n", lw->depth);
130 GLXFBConfig *fbconfigs = glXChooseFBConfig(obt_display,
132 drawable_tfp_attrs, &count);
136 for(i = 0; i < count; ++i ) {
138 glXGetFBConfigAttrib(obt_display,
139 fbconfigs[i], GLX_VISUAL_ID, &value);
140 if(value == (int)visinfo->visualid)
148 printf("fbconfigless\n");
152 lw->glpixmap = glXCreatePixmap(obt_display, fbc, pixmap, attrs);
153 return !!lw->glpixmap;
156 int bindPixmapToTexture(LocoWindow *lw)
158 if (lw->glpixmap != None)
159 return 1; /* already bound */
161 if (!create_glxpixmap(lw))
162 return 0; /* horrible failure */
165 if (screen->queryDrawable (screen->display->display,
167 GLX_TEXTURE_TARGET_EXT,
170 fprintf (stderr, "%s: glXQueryDrawable failed\n", programName);
172 glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
173 texture->pixmap = None;
179 glBindTexture(GL_TEXTURE_2D, lw->texname);
181 BindTexImageEXT(obt_display, lw->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
183 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
184 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
186 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
187 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
188 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
192 void releasePixmapFromTexture(LocoWindow *lw)
195 glBindTexture(GL_TEXTURE_2D, lw->texname);
197 ReleaseTexImageEXT(obt_display, lw->glpixmap, GLX_FRONT_LEFT_EXT);
199 glBindTexture(GL_TEXTURE_2D, 0);
203 void destroy_glxpixmap(LocoWindow *lw)
206 releasePixmapFromTexture(lw);
208 glXDestroyGLXPixmap(obt_display, lw->glpixmap);
213 static void full_composite(void)
218 glClear(GL_COLOR_BUFFER_BIT);
219 for (it = stacking_bottom; it != stacking_top; it = it->prev) {
220 if (it->window->input_only) continue;
221 if (!it->window->visible) continue;
223 glBindTexture(GL_TEXTURE_2D, it->window->texname);
224 ret = bindPixmapToTexture(it->window);
226 glColor3f(1.0, 1.0, 1.0);
227 glVertex2i(it->window->x, it->window->y);
229 glVertex2i(it->window->x + it->window->w, it->window->y);
231 glVertex2i(it->window->x + it->window->w, it->window->y + it->window->h);
233 glVertex2i(it->window->x, it->window->y + it->window->h);
237 glXSwapBuffers(obt_display, loco_overlay);
240 static LocoList* loco_list_prepend(LocoList **top, LocoList **bottom,
243 LocoList *n = g_new(LocoList, 1);
248 if (n->next) n->next->prev = n;
251 if (!*bottom) *bottom = n;
255 static void loco_list_delete_link(LocoList **top, LocoList **bottom,
258 LocoList *prev = pos->prev;
259 LocoList *next = pos->next;
273 static void loco_list_move_before(LocoList **top, LocoList **bottom,
274 LocoList *move, LocoList *before)
276 LocoList *prev, *next;
278 /* these won't move it anywhere */
279 if (move == before || move->next == before) return;
284 /* remove it from the list */
285 if (next) next->prev = prev;
287 if (prev) prev->next = next;
293 move->prev = before->prev;
294 move->next->prev = move;
295 if (move->prev) move->prev->next = move;
298 /* after the bottom */
299 move->prev = *bottom;
301 if (move->prev) move->prev->next = move;
305 if (!move->prev) *top = move;
308 /* Returns a LocoWindow structure */
309 static LocoWindow* find_window(Window window)
311 return g_hash_table_lookup(window_map, &window);
314 /* Returns a node from the stacking_top/bottom list */
315 static LocoList* find_stacking(Window window)
317 return g_hash_table_lookup(stacking_map, &window);
320 void composite_setup_window(LocoWindow *win)
322 /*something useful = */XDamageCreate(obt_display, win->id, XDamageReportRawRectangles);
325 static void add_window(Window window)
329 XWindowAttributes attrib;
331 printf("add window 0x%lx\n", window);
333 if (!XGetWindowAttributes(obt_display, window, &attrib))
336 lw = g_new0(LocoWindow, 1);
338 lw->input_only = attrib.class == InputOnly;
341 lw->w = attrib.width;
342 lw->h = attrib.height;
343 lw->depth = attrib.depth;
344 lw->visible = attrib.map_state != IsUnmapped;
346 g_hash_table_insert(window_map, &lw->id, lw);
347 /* new windows are at the top */
348 it = loco_list_prepend(&stacking_top, &stacking_bottom, lw);
349 g_hash_table_insert(stacking_map, &lw->id, it);
351 if (!lw->input_only) {
352 glGenTextures(1, &lw->texname);
353 // glTexImage2D(TARGET, 0, GL_RGB, lw->w, lw->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
354 composite_setup_window(lw);
360 static void remove_window(LocoWindow *lw)
362 printf("remove window 0x%lx\n", lw->id);
364 LocoList *pos = find_stacking(lw->id);
367 glDeleteTextures(1, &lw->texname);
369 loco_list_delete_link(&stacking_top, &stacking_bottom, pos);
370 g_hash_table_remove(stacking_map, &lw->id);
371 g_hash_table_remove(window_map, &lw->id);
378 static void show_window(LocoWindow *lw)
385 /* get the window's semantic type (for different effects!) */
386 lw->type = 0; /* XXX set this to the default type */
387 if (OBT_PROP_GETA32(lw->id, NET_WM_WINDOW_TYPE, ATOM, &type, &ntype)) {
388 /* use the first value that we know about in the array */
389 for (i = 0; i < ntype; ++i) {
390 /* XXX SET THESE TO AN ENUM'S VALUES */
391 if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP))
393 if (type[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU))
395 /* XXX there are more TYPES that need to be added to prop.h */
402 static void hide_window(LocoWindow *lw, gboolean destroyed)
404 /* if destroyed, then the window is no longer available */
406 destroy_glxpixmap(lw);
409 void COMPOSTER_RAWR(const XEvent *e, gpointer data)
411 int redraw_required = 0;
413 //g_print("COMPOSTER_RAWR() %d\n", e->type);
415 if (e->type == ConfigureNotify) {
418 printf("Window 0x%lx moved or something\n", e->xconfigure.window);
420 lw = find_window(e->xconfigure.window);
422 LocoList *above, *pos;
424 pos = find_stacking(e->xconfigure.window);
425 above = find_stacking(e->xconfigure.above);
427 g_assert(pos != NULL && pos->window != NULL);
428 if (e->xconfigure.above && !above)
429 printf("missing windows from the stacking list!!\n");
431 lw->x = e->xconfigure.x;
432 lw->y = e->xconfigure.y;
433 if ((lw->w != e->xconfigure.width) ||
434 (lw->h != e->xconfigure.height))
436 lw->w = e->xconfigure.width;
437 lw->h = e->xconfigure.height;
439 destroy_glxpixmap(lw);
441 printf("Window 0x%lx above 0x%lx\n", pos->window->id,
442 above ? above->window->id : 0);
443 loco_list_move_before(&stacking_top, &stacking_bottom, pos, above);
447 else if (e->type == CreateNotify) {
448 add_window(e->xmap.window);
450 else if (e->type == DestroyNotify) {
451 LocoWindow *lw = find_window(e->xdestroywindow.window);
453 hide_window(lw, TRUE);
454 if (lw->glpixmap != None) {
455 destroy_glxpixmap(lw);
460 printf("destroy notify for unknown window 0x%lx\n",
461 e->xdestroywindow.window);
463 else if (e->type == ReparentNotify) {
464 if (e->xreparent.parent == loco_root)
465 add_window(e->xreparent.window);
467 LocoWindow *lw = find_window(e->xreparent.window);
469 printf("window 0x%lx reparented from root\n", lw->id);
470 hide_window(lw, FALSE);
474 printf("reparent notify away from root for unknown window "
475 "0x%lx\n", e->xreparent.window);
479 else if (e->type == MapNotify) {
480 LocoWindow *lw = find_window(e->xmap.window);
484 printf("map notify for unknown window 0x%lx\n",
487 else if (e->type == UnmapNotify) {
488 LocoWindow *lw = find_window(e->xunmap.window);
490 hide_window(lw, FALSE);
492 printf("unmap notify for unknown window 0x%lx\n",
495 else if (e->type == obt_display_extension_damage_basep + XDamageNotify) {
496 // LocoWindow *lw = find_window(e->xdamage.window);
500 if (redraw_required && !XPending(obt_display))
504 static void find_all_windows(gint screen)
509 if (!XQueryTree(obt_display, loco_root, &w, &w, &children, &nchild))
512 for (i = 0; i < nchild; ++i)
513 if (children[i] != None) add_window(children[i]);
515 if (children) XFree(children);
518 static guint window_hash(Window *w) { return *w; }
519 static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
521 void loco_set_mainloop(gint screen_num, ObtMainLoop *loop)
523 int db, stencil, depth;
524 int i, j, value, count;
526 XVisualInfo *vi, tvis, *visinfo;
529 { GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER, GLX_RGBA, None };
531 loco_screen_num = screen_num;
532 loco_root = obt_root(screen_num);
533 loco_overlay = XCompositeGetOverlayWindow(obt_display, loco_root);
534 XserverRegion region = XFixesCreateRegion(obt_display, NULL, 0);
536 XFixesSetWindowShapeRegion (obt_display,
541 XFixesSetWindowShapeRegion (obt_display,
547 XFixesDestroyRegion (obt_display, region);
549 vi = glXChooseVisual(obt_display, screen_num, config);
550 cont = glXCreateContext(obt_display, vi, NULL, GL_TRUE);
552 printf("context creation failed\n");
553 glXMakeCurrent(obt_display, loco_overlay, cont);
556 glXGetProcAddress((const guchar*)"glXBindTexImageEXT");
558 glXGetProcAddress((const guchar*)"glXReleaseTexImageEXT");
560 w = WidthOfScreen(ScreenOfDisplay(obt_display, screen_num));
561 h = HeightOfScreen(ScreenOfDisplay(obt_display, screen_num));
562 glViewport(0, 0, w, h);
563 glMatrixMode(GL_PROJECTION);
565 printf("Setting up an orthographic projection of %dx%d\n", w, h);
566 glOrtho(0, w, h, 0.0, -1.0, 100.0);
567 glMatrixMode(GL_MODELVIEW);
569 glClear(GL_COLOR_BUFFER_BIT);
570 glEnable(GL_TEXTURE_2D);
572 glXSwapBuffers(obt_display, loco_overlay);
573 glClearColor(1.0, 0.0, 0.0, 1.0);
574 // glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
575 // glEnable(GL_BLEND);
579 for (i = 0; i <= MAX_DEPTH; i++) {
582 visinfo = XGetVisualInfo(obt_display, VisualDepthMask, &tvis, &count);
583 for (j = 0; j < count; j++) {
584 glXGetConfig(obt_display, &visinfo[j], GLX_USE_GL, &value);
588 glXGetConfig(obt_display, &visinfo[j], GLX_DOUBLEBUFFER, &value);
593 glXGetConfig(obt_display, &visinfo[j], GLX_STENCIL_SIZE, &value);
598 glXGetConfig(obt_display, &visinfo[j], GLX_DEPTH_SIZE, &value);
603 visualIDs[i] = visinfo[j].visualid;
607 for (i = 0 ;i <= MAX_DEPTH; i++) {
608 tvis.visualid = visualIDs[i];
609 glxPixmapVisuals[i] = XGetVisualInfo(obt_display, VisualIDMask, &tvis, &count);
610 if (glxPixmapVisuals[i])
611 printf("supporting depth %d\n", i);
613 obt_main_loop_x_add(loop, COMPOSTER_RAWR, NULL, NULL);
614 window_map = g_hash_table_new((GHashFunc)window_hash,
615 (GEqualFunc)window_comp);
616 stacking_map = g_hash_table_new((GHashFunc)window_hash,
617 (GEqualFunc)window_comp);
618 stacking_top = stacking_bottom = NULL;
620 XCompositeRedirectSubwindows(obt_display, loco_root, CompositeRedirectManual);
621 find_all_windows(screen_num);
624 void loco_shutdown(void)