latest composter!
authorDerek Foreman <manmower@gmail.com>
Sun, 3 Feb 2008 17:36:22 +0000 (12:36 -0500)
committerDana Jansens <danakj@orodu.net>
Mon, 4 Feb 2008 14:33:30 +0000 (09:33 -0500)
loco/loco.c

index 118790c..cabf57e 100644 (file)
 
 */
 
+#define glError()                                      \
+{                                                      \
+    /*const GLchar *err_file = strrchr(err_path, '/');*/ \
+    GLenum        gl_error = glGetError();             \
+                                                       \
+    /*++err_file;*/                                        \
+                                                       \
+    for (; (gl_error); gl_error = glGetError())        \
+      fprintf(stderr, "%s: %d caught at line %u\n",    \
+              __FUNCTION__, gl_error, __LINE__);       \
+              /*(const GLchar*)gluErrorString(gl_error)*/ \
+}
+
+
+#define MAX_DEPTH 32
+
 typedef struct {
     Window id;
     gint x, y, w, h;
+    gint depth;
     gboolean input_only;
     gboolean visible;
     gint type; /* XXX make this an enum */
+    GLuint texname;
+    GLXPixmap glpixmap;
 } LocoWindow;
 
 typedef struct _LocoList {
@@ -49,6 +68,7 @@ typedef struct _LocoList {
 } LocoList;
 
 static Window      loco_root;
+static Window      loco_overlay;
 /* Maps X Window ID -> LocoWindow* */
 static GHashTable *window_map;
 /* Maps X Window ID -> LocoList* which is in the stacking_top/bottom list */
@@ -56,6 +76,12 @@ static GHashTable *stacking_map;
 /* From top to bottom */
 static LocoList   *stacking_top;
 static LocoList   *stacking_bottom;
+static VisualID visualIDs[MAX_DEPTH + 1];
+static XVisualInfo *glxPixmapVisuals[MAX_DEPTH + 1];
+static int loco_screen_num;
+
+void (*BindTexImageEXT)(Display *, GLXDrawable, int, const int *);
+void (*ReleaseTexImageEXT)(Display *, GLXDrawable, int);
 
 /*
 static void print_stacking()
@@ -68,6 +94,146 @@ static void print_stacking()
 }
 */
 
+int create_glxpixmap(LocoWindow *lw)
+{
+    XVisualInfo  *visinfo;
+    Pixmap pixmap;
+    static const int attrs[] =
+        {
+            GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
+            None
+        };
+
+    static const int drawable_tfp_attrs[] =
+        {
+            GLX_CONFIG_CAVEAT, GLX_NONE,
+            GLX_DOUBLEBUFFER, False,
+            GLX_DEPTH_SIZE, 0,
+            GLX_RED_SIZE, 1,
+            GLX_GREEN_SIZE, 1,
+            GLX_BLUE_SIZE, 1,
+            GLX_ALPHA_SIZE, 1,
+            GLX_RENDER_TYPE, GLX_RGBA_BIT,
+            GLX_BIND_TO_TEXTURE_RGBA_EXT, True, // additional for tfp
+            None
+        };
+    int count;
+
+    pixmap = XCompositeNameWindowPixmap(obt_display, lw->id);
+    visinfo = glxPixmapVisuals[lw->depth];
+    if (!visinfo) {
+        printf("no visinfo for depth %d\n", lw->depth);
+       return 0;
+    }
+
+    GLXFBConfig fbc;
+    GLXFBConfig *fbconfigs = glXChooseFBConfig(obt_display,
+                                               loco_screen_num,
+                                               drawable_tfp_attrs, &count);
+
+    int i;
+    fbc = 0;
+    for(i = 0; i < count; ++i ) {
+        int value;
+        glXGetFBConfigAttrib(obt_display,
+                             fbconfigs[i], GLX_VISUAL_ID, &value);
+        if(value == (int)visinfo->visualid)
+        {
+            fbc = fbconfigs[i];
+            XFree(fbconfigs);
+        }
+    }
+
+    if (!fbc) {
+        printf("fbconfigless\n");
+        return 0;
+    }
+
+    lw->glpixmap = glXCreatePixmap(obt_display, fbc, pixmap, attrs);
+}
+
+int bindPixmapToTexture(LocoWindow *lw)
+{
+    unsigned int target;
+    int success = 0;
+
+    if (lw->glpixmap == None) {
+        create_glxpixmap(lw);
+    }
+    if (lw->glpixmap == None)
+        return 0;
+/*
+    if (screen->queryDrawable (screen->display->display,
+                              texture->pixmap,
+                              GLX_TEXTURE_TARGET_EXT,
+                              &target))
+    {
+       fprintf (stderr, "%s: glXQueryDrawable failed\n", programName);
+
+       glXDestroyGLXPixmap (screen->display->display, texture->pixmap);
+       texture->pixmap = None;
+
+       return FALSE;
+    }
+*/
+
+    glBindTexture(GL_TEXTURE_2D, lw->texname);
+glError();
+    BindTexImageEXT(obt_display, lw->glpixmap, GLX_FRONT_LEFT_EXT, NULL);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+    return 1;
+}
+
+void destroy_glxpixmap(LocoWindow *lw)
+{
+    glXDestroyGLXPixmap(obt_display, lw->glpixmap);
+    lw->glpixmap = None;
+}
+
+
+void releasePixmapFromTexture (LocoWindow *lw)
+{
+    if (lw->glpixmap) {
+       glEnable(GL_TEXTURE_2D);
+       glBindTexture(GL_TEXTURE_2D, lw->texname);
+
+       ReleaseTexImageEXT(obt_display, lw->glpixmap, GLX_FRONT_LEFT_EXT);
+
+        glBindTexture(GL_TEXTURE_2D, 0);
+        glDisable(GL_TEXTURE_2D);
+    }
+}
+
+static void full_composite(void)
+{
+    int ret;
+    LocoList *it;
+    glClear(GL_COLOR_BUFFER_BIT);
+    for (it = stacking_bottom; it != stacking_top; it = it->prev) {
+        if (!it->window->visible)
+            continue;
+        ret = bindPixmapToTexture(it->window);
+        glBegin(GL_QUADS);
+        glColor3f(1.0, 1.0, 1.0);
+        glVertex2i(it->window->x, it->window->y);
+        glTexCoord2f(1, 0);
+        glVertex2i(it->window->x + it->window->w, it->window->y);
+        glTexCoord2f(1, 1);
+        glVertex2i(it->window->x + it->window->w, it->window->y + it->window->h);
+        glTexCoord2f(0, 1);
+        glVertex2i(it->window->x, it->window->y + it->window->h);
+        glTexCoord2f(0, 0);
+        glEnd();
+    }
+    glXSwapBuffers(obt_display, loco_overlay);
+}
+
 static LocoList* loco_list_prepend(LocoList **top, LocoList **bottom,
                                    LocoWindow *window)
 {
@@ -152,7 +318,7 @@ void composite_setup_window(LocoWindow *win)
 {
     if (win->input_only) return;
 
-    //XCompositeRedirectWindow(obt_display, win->id, CompositeRedirectAutomatic);
+    XCompositeRedirectWindow(obt_display, win->id, CompositeRedirectAutomatic);
     /*something useful = */XDamageCreate(obt_display, win->id, XDamageReportRawRectangles);
 }
 
@@ -174,6 +340,10 @@ static void add_window(Window window)
     lw->y = attrib.y;
     lw->w = attrib.width;
     lw->h = attrib.height;
+    lw->depth = attrib.depth;
+    lw->glpixmap = None;
+    glGenTextures(1, &lw->texname);
+  //  glTexImage2D(TARGET, 0, GL_RGB, lw->w, lw->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
     g_hash_table_insert(window_map, &lw->id, lw);
     /* new windows are at the top */
     it = loco_list_prepend(&stacking_top, &stacking_bottom, lw);
@@ -232,8 +402,11 @@ static void hide_window(LocoWindow *lw, gboolean destroyed)
 
 void COMPOSTER_RAWR(const XEvent *e, gpointer data)
 {
+    int redraw_required = 0;
+
     if (e->type == ConfigureNotify) {
         LocoWindow *lw;
+redraw_required = 1;
         printf("Window 0x%lx moved or something\n", e->xconfigure.window);
 
         lw = find_window(e->xconfigure.window);
@@ -249,8 +422,13 @@ void COMPOSTER_RAWR(const XEvent *e, gpointer data)
 
             lw->x = e->xconfigure.x;
             lw->y = e->xconfigure.y;
-            lw->w = e->xconfigure.width;
-            lw->h = e->xconfigure.height;
+            if ((lw->w != e->xconfigure.width) || (lw->h != e->xconfigure.height)) {
+                lw->w = e->xconfigure.width;
+                lw->h = e->xconfigure.height;
+                if (lw->glpixmap != None) {
+                    destroy_glxpixmap(lw);
+                }
+            }
             printf("Window 0x%lx above 0x%lx\n", pos->window->id,
                    above ? above->window->id : 0);
             loco_list_move_before(&stacking_top, &stacking_bottom, pos, above);
@@ -264,6 +442,9 @@ void COMPOSTER_RAWR(const XEvent *e, gpointer data)
         LocoWindow *lw = find_window(e->xdestroywindow.window);
         if (lw) {
             hide_window(lw, TRUE);
+            if (lw->glpixmap != None) {
+                destroy_glxpixmap(lw);
+            }
             remove_window(lw);
         }
         else
@@ -299,7 +480,12 @@ void COMPOSTER_RAWR(const XEvent *e, gpointer data)
                    e->xunmap.window);
     }
     else if (e->type == obt_display_extension_damage_basep + XDamageNotify) {
+//        LocoWindow *lw = find_window(e->xdamage.window);
+  //      if (lw->visible)
+            redraw_required = 1;
     }
+    if (redraw_required)
+        full_composite();
 }
 
 static void find_all_windows(gint screen)
@@ -321,19 +507,40 @@ static gboolean window_comp(Window *w1, Window *w2) { return *w1 == *w2; }
 
 void loco_set_mainloop(gint screen_num, ObtMainLoop *loop)
 {
+    int db, stencil, depth;
+    int i, j, value, count;
     int w, h;
-    XVisualInfo *vi;
+    XVisualInfo *vi, tvis, *visinfo;
     GLXContext cont;
     int config[] =
         { GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER, GLX_RGBA, None };
 
+    loco_screen_num = screen_num;
     loco_root = obt_root(screen_num);
+    loco_overlay = XCompositeGetOverlayWindow(obt_display, loco_root);
+XserverRegion region = XFixesCreateRegion(obt_display, NULL, 0);
+
+    XFixesSetWindowShapeRegion (obt_display,
+                                loco_overlay,
+                                ShapeBounding,
+                                0, 0,
+                                0);
+    XFixesSetWindowShapeRegion (obt_display,
+                                loco_overlay,
+                                ShapeInput,
+                                0, 0,
+                                region);
+
+    XFixesDestroyRegion (obt_display, region);
 
     vi = glXChooseVisual(obt_display, screen_num, config);
     cont = glXCreateContext(obt_display, vi, NULL, GL_TRUE);
     if (cont == NULL)
         printf("context creation failed\n");
-    glXMakeCurrent(obt_display, loco_root, cont);
+    glXMakeCurrent(obt_display, loco_overlay, cont);
+
+    BindTexImageEXT = glXGetProcAddress("glXBindTexImageEXT");
+    ReleaseTexImageEXT = glXGetProcAddress("glXReleaseTexImageEXT");
 
     w = WidthOfScreen(ScreenOfDisplay(obt_display, screen_num));
     h = HeightOfScreen(ScreenOfDisplay(obt_display, screen_num));
@@ -345,8 +552,49 @@ printf("Setting up an orthographic projection of %dx%d\n", w, h);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     glClear(GL_COLOR_BUFFER_BIT);
-    glEnable(GL_TEXTURE_RECTANGLE_ARB);
-    glXSwapBuffers(obt_display, loco_root);
+    glEnable(GL_TEXTURE_2D);
+glError();
+    glXSwapBuffers(obt_display, loco_overlay);
+    glClearColor(1.0, 0.0, 0.0, 1.0);
+//    glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
+//    glEnable(GL_BLEND);
+    db = 32767;
+    stencil = 32767;
+    depth = 32767;
+    for (i = 0; i <= MAX_DEPTH; i++) {
+        tvis.depth = i;
+        visualIDs[i] = 0;
+        visinfo = XGetVisualInfo(obt_display, VisualDepthMask, &tvis, &count);
+        for (j = 0; j < count; j++) {
+            glXGetConfig(obt_display, &visinfo[j], GLX_USE_GL, &value);
+            if (!value)
+                continue;
+
+            glXGetConfig(obt_display, &visinfo[j], GLX_DOUBLEBUFFER, &value);
+            if (value > db)
+                continue;
+            db = value;
+
+            glXGetConfig(obt_display, &visinfo[j], GLX_STENCIL_SIZE, &value);
+            if (value > stencil)
+                continue;
+            stencil = value;
+
+            glXGetConfig(obt_display, &visinfo[j], GLX_DEPTH_SIZE, &value);
+            if (value > depth)
+                continue;
+            depth = value;
+
+            visualIDs[i] = visinfo[j].visualid;
+        }
+    }
+
+    for (i = 0 ;i <= MAX_DEPTH; i++) {
+        tvis.visualid = visualIDs[i];
+        glxPixmapVisuals[i] = XGetVisualInfo(obt_display, VisualIDMask, &tvis, &count);
+        if (glxPixmapVisuals[i])
+            printf("supporting depth %d\n", i);
+    }
     obt_main_loop_x_add(loop, COMPOSTER_RAWR, NULL, NULL);
     window_map = g_hash_table_new((GHashFunc)window_hash,
                                   (GEqualFunc)window_comp);