Add shape support to the composite code.
authorDana Jansens <danakj@orodu.net>
Fri, 25 Jun 2010 12:57:19 +0000 (14:57 +0200)
committerDana Jansens <danakj@orodu.net>
Sat, 26 Jun 2010 23:30:51 +0000 (01:30 +0200)
Keeps the window's shape in an array of XRectangles in the ObWindow.
Also, moved the event handlers that are handled for ObWindows rather than
 subclasses into a function event_handle_window().  The function returns a
 bool saying it the event can also be handled by others or should be treated
 as finished.

openbox/composite.c
openbox/event.c
openbox/unmanaged.c
openbox/window.c
openbox/window.h

index 877ed20c91b6562d4dce6b99a7149c60b7436066..b970eb5e464daa4bbb5ef8b58dc62d3e6aa756eb 100644 (file)
@@ -493,7 +493,8 @@ static gboolean composite(gpointer data)
         gettimeofday(&start, NULL);
 #endif
         obt_display_ignore_errors(TRUE);
-        glXBindTexImageEXT(obt_display, win->gpixmap, GLX_FRONT_LEFT_EXT, NULL);
+        glXBindTexImageEXT(obt_display, win->gpixmap, GLX_FRONT_LEFT_EXT,
+                           NULL);
         obt_display_ignore_errors(FALSE);
         if (obt_display_error_occured)
             g_assert(0 && "ERROR BINDING GLX PIXMAP");
@@ -511,8 +512,8 @@ static gboolean composite(gpointer data)
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
-        x = win->toparea.x + win->area.x;
-        y = win->toparea.y + win->area.y;
+        x = win->toparea.x + win->topborder + win->area.x;
+        y = win->toparea.y + win->topborder + win->area.y;
         w = win->area.width;
         h = win->area.height;
 
@@ -520,14 +521,46 @@ static gboolean composite(gpointer data)
             glColor4ui(0xffffffff, 0xffffffff, 0xffffffff, *win->alpha);
 
         glBegin(GL_QUADS);
-        glTexCoord2f(0, 0);
-        glVertex3f(x, y, 0.0);
-        glTexCoord2f(0, 1);
-        glVertex3f(x, y + h, 0.0);
-        glTexCoord2f(1, 1);
-        glVertex3f(x + w, y + h, 0.0);
-        glTexCoord2f(1, 0);
-        glVertex3f(x + w, y, 0.0);
+        if (!win->n_rects) {
+            glTexCoord2f(0, 0);
+            glVertex3f(x, y, 0.0);
+            glTexCoord2f(0, 1);
+            glVertex3f(x, y + h, 0.0);
+            glTexCoord2f(1, 1);
+            glVertex3f(x + w, y + h, 0.0);
+            glTexCoord2f(1, 0);
+            glVertex3f(x + w, y, 0.0);
+        }
+        else {
+            gint i;
+            /* the border is not included in the shape rect coords */
+            const gint sb = window_top(win) == window_redir(win) ?
+                win->topborder : 0;
+
+
+            for (i = 0; i < win->n_rects; ++i) {
+                const gint xb = win->rects[i].x + sb;
+                const gint yb = win->rects[i].y + sb;
+                const gint wb = win->rects[i].width;
+                const gint hb = win->rects[i].height;
+
+                glTexCoord2d((GLdouble)xb/w,
+                             (GLdouble)yb/h);
+                glVertex3f(x + xb, y + yb, 0.0f);
+
+                glTexCoord2d((GLdouble)xb/w,
+                             (GLdouble)(yb+hb)/h);
+                glVertex3f(x + xb, y + yb + hb, 0.0f);
+
+                glTexCoord2d((GLdouble)(xb+wb)/w,
+                             (GLdouble)(yb+hb)/h);
+                glVertex3f(x + xb + wb, y + yb + hb, 0.0f);
+
+                glTexCoord2d((GLdouble)(xb+wb)/w,
+                             (GLdouble)yb/h);
+                glVertex3f(x + xb + wb, y + yb, 0.0f);
+            }
+        }
         glEnd();
 
         if (win->alpha && *win->alpha < 0xffffffff)
index d23447b36251f9afa76329af4fb1df2dd95401c6..9033972a681e8f19b4e895fc57fa5574a9a7e303 100644 (file)
@@ -85,6 +85,7 @@ typedef struct
 static void event_process(const XEvent *e, gpointer data);
 static void event_handle_root(XEvent *e);
 static gboolean event_handle_menu_input(XEvent *e);
+static gboolean event_handle_window(ObWindow *w, XEvent *e);
 static void event_handle_menu(ObMenuFrame *frame, XEvent *e);
 static gboolean event_handle_prompt(ObPrompt *p, XEvent *e);
 static void event_handle_dock(ObDock *s, XEvent *e);
@@ -641,79 +642,8 @@ static void event_process(const XEvent *ec, gpointer data)
         if (!obwin && xe->parent == obt_root(ob_screen))
             obwin = UNMANAGED_AS_WINDOW(unmanaged_new(xe->window));
     }
-    else if ((obwin && obwin->type != OB_WINDOW_CLASS_PROMPT) &&
-             ((e->type == ConfigureNotify &&
-               /* for configure notify, track the position/size of
-                  both the top-level window and the redir window (when
-                  it is not the top-level window) */
-               e->xconfigure.send_event == FALSE &&
-               ((e->xconfigure.window == window_redir(obwin) &&
-                 window_redir(obwin) != window_top(obwin)) ||
-                (e->xconfigure.window == window_top(obwin)))) ||
-              (e->type == MapNotify &&
-               e->xmap.window == window_redir(obwin))))
-    {
-        gboolean pixchange = FALSE;
-
-        if (e->type == ConfigureNotify) {
-            XConfigureEvent const *xe = &e->xconfigure;
-
-            if (xe->window == window_redir(obwin)) {
-                int x, y, w, h;
-
-                /* if the redir window's size changes.. */
-                if (obwin->area.width != xe->width ||
-                    obwin->area.height != xe->height ||
-                    /* or its border changes.. (assume only the top-level
-                       window will ever have a border) */
-                    (window_top(obwin) == window_redir(obwin) &&
-                     obwin->topborder != xe->border_width))
-                {
-                    /* ..then need to change the pixmap */
-                    pixchange = TRUE;
-                }
-
-                /* set the redir window's area */
-                if (window_redir(obwin) == window_top(obwin)) {
-                    /* same window then its area fills the whole top level
-                       window */
-                    x = 0;
-                    y = 0;
-                    w = xe->width + xe->border_width * 2;
-                    h = xe->height + xe->border_width * 2;
-                }
-                else {
-                    /* different window then it is inside the top level
-                       window */
-                    x = xe->x;
-                    y = xe->y;
-                    w = xe->width;
-                    h = xe->height;
-                }
-                RECT_SET(obwin->area, x, y, w, h);
-            }
-
-            /* set the top window's area/border */
-            if (xe->window == window_top(obwin)) {
-                RECT_SET(obwin->toparea, xe->x, xe->y, xe->width, xe->height);
-                obwin->topborder = xe->border_width;
-            }
-        }
-
-        if (e->type == MapNotify) {
-            pixchange = TRUE;
-            obwin->mapped = TRUE;
-        }
-
-        if (pixchange)
-            composite_window_invalid(obwin);
-    }
-    else if ((e->type == UnmapNotify) && obwin &&
-             obwin->type != OB_WINDOW_CLASS_PROMPT &&
-             e->xunmap.window == window_top(obwin))
-    {
-        obwin->mapped = FALSE;
-    }
+    else if (obwin && event_handle_window(obwin, e))
+        /* handled it ! */;
     else if (client)
         event_handle_client(client, e);
     else if (um)
@@ -1773,16 +1703,17 @@ static void event_handle_client(ObClient *client, XEvent *e)
         ;
 #ifdef SHAPE
         {
-            int kind;
+            int kind = -1;
             if (obt_display_extension_shape &&
-                e->type == obt_display_extension_shape_basep)
+                e->type == obt_display_extension_shape_basep + ShapeNotify)
             {
                 switch (((XShapeEvent*)e)->kind) {
                     case ShapeBounding:
-                    case ShapeClip:
                         client->shaped = ((XShapeEvent*)e)->shaped;
                         kind = ShapeBounding;
                         break;
+                    case ShapeClip:
+                        break;
                     case ShapeInput:
                         client->shaped_input = ((XShapeEvent*)e)->shaped;
                         kind = ShapeInput;
@@ -1790,7 +1721,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
                     default:
                         g_assert_not_reached();
                 }
-                frame_adjust_shape_kind(client->frame, kind);
+                if (kind) frame_adjust_shape_kind(client->frame, kind);
             }
         }
 #endif
@@ -1811,6 +1742,94 @@ static void event_handle_dock(ObDock *s, XEvent *e)
     }
 }
 
+static gboolean event_handle_window(ObWindow *wi, XEvent *e)
+{
+    gboolean used = FALSE, pixchange = FALSE;
+
+    if (wi->type == OB_WINDOW_CLASS_PROMPT) return used;
+
+    switch (e->type) {
+    case ConfigureNotify:
+        if (e->xconfigure.send_event) break;
+
+        if (e->xconfigure.window == window_redir(wi)) {
+            XConfigureEvent const *xe = &e->xconfigure;
+            const gboolean same_window = window_top(wi) == window_redir(wi);
+            int x, y, w, h;
+
+            /* if the redir window's size changes.. */
+            if (wi->area.width != xe->width || wi->area.height != xe->height ||
+                /* or its border changes.. (assume only the top-level
+                   window will ever have a border) */
+                (same_window && wi->topborder != xe->border_width))
+            {
+                /* ..then need to change the pixmap */
+                pixchange = TRUE;
+            }
+
+            /* set the redir window's area */
+            if (same_window) {
+                /* same window then its area fills the whole top level
+                   window */
+                x = -xe->border_width;
+                y = -xe->border_width;
+                w = xe->width + xe->border_width * 2;
+                h = xe->height + xe->border_width * 2;
+            }
+            else {
+                /* different window then it is inside the top level
+                   window */
+                x = xe->x;
+                y = xe->y;
+                w = xe->width;
+                h = xe->height;
+            }
+            RECT_SET(wi->area, x, y, w, h);
+            used = TRUE;
+        }
+
+        /* set the top window's area/border */
+        if (e->xconfigure.window == window_top(wi)) {
+            XConfigureEvent const *xe = &e->xconfigure;
+            RECT_SET(wi->toparea, xe->x, xe->y, xe->width, xe->height);
+            wi->topborder = xe->border_width;
+            used = TRUE;
+        }
+        break;
+
+    case MapNotify:
+        if (e->xmap.window == window_redir(wi)) {
+            wi->mapped = TRUE;
+            pixchange = TRUE;
+            used = TRUE;
+        }
+        break;
+    case UnmapNotify:
+        if (e->xunmap.window == window_top(wi)) {
+            wi->mapped = FALSE;
+            used = TRUE;
+        }
+        break;
+    default:
+#ifdef SHAPE
+#ifdef USE_COMPOSITING
+        if (obt_display_extension_shape &&
+            e->type == obt_display_extension_shape_basep + ShapeNotify)
+        {
+            XShapeEvent *s = (XShapeEvent*)e;
+            if (s->window == window_redir(wi) && s->kind == ShapeBounding) {
+                window_adjust_redir_shape(wi);
+                used = FALSE; /* let other people get this event also */
+            }
+        }
+#endif
+#endif
+    }
+    if (pixchange)
+        composite_window_invalid(wi);
+    return used;
+}
+
 static void event_handle_unmanaged(ObUnmanaged *um, XEvent *e)
 {
     Window w;
index 0648015793568bbf70144ca7615697ff08db7c11..8675fc8196637c9e751f0efc268d0128fa0c43a5 100644 (file)
@@ -52,6 +52,9 @@ ObUnmanaged* unmanaged_new(Window w)
     self->alpha = 0xffffffff;
 
     XSelectInput(obt_display, self->window, PropertyChangeMask);
+#ifdef SHAPE
+    XShapeSelectInput(obt_display, self->window, ShapeNotifyMask);
+#endif
 
     unmanaged_update_opacity(self);
 
index e516eea22e9d043db09b6649c961455cd08d44dd..a0b9cebfd088e54c81e44bc59522659b7dd1a56e 100644 (file)
@@ -83,6 +83,21 @@ void window_set_abstract(ObWindow *self,
     /* set up any things in ObWindow that require use of the abstract pointers
        now */
 
+#ifdef SHAPE
+#ifdef USE_COMPOSITING
+    {
+        gint foo;
+        guint ufoo;
+        gint s;
+
+        XShapeQueryExtents(obt_display, window_redir(self), &s, &foo,
+                           &foo, &ufoo, &ufoo, &foo, &foo, &foo, &ufoo,
+                           &ufoo);
+        if (s) window_adjust_redir_shape(self);
+    }
+#endif
+#endif
+
     composite_window_setup(self);
 }
 
@@ -93,7 +108,9 @@ void window_set_top_area(ObWindow *self, const Rect *r, gint border)
 #ifdef USE_COMPOSITING
     self->toparea = *r;
     self->topborder = border;
-    RECT_SET(self->area, 0, 0, self->toparea.width, self->toparea.height);
+    RECT_SET(self->area, -border, -border,
+             self->toparea.width + border * 2,
+             self->toparea.height + border * 2);
 #endif
 }
 
@@ -107,6 +124,7 @@ void window_free(ObWindow *self)
     /* The abstract pointers must not be used here, they are likely invalid
        by now ! */
 
+    if (self->rects) XFree(self->rects);
     g_slice_free1(self->bytes, self);
 }
 
@@ -138,6 +156,19 @@ void window_remove(Window xwin)
     g_hash_table_remove(window_map, &xwin);
 }
 
+void window_adjust_redir_shape(ObWindow *self)
+{
+#ifdef USE_COMPOSITING
+#ifdef SHAPE
+    gint ord;
+    if (self->rects)
+        XFree(self->rects);
+    self->rects = XShapeGetRectangles(obt_display, window_redir(self),
+                                      ShapeBounding, &self->n_rects, &ord);
+#endif
+#endif
+}
+
 ObInternalWindow* window_internal_new(Window window, const Rect *area,
                                       gint border, gint depth)
 {
index 21c4792a54a8b2600addeb95d36b0301d284cd7a..5ab014430f4b02c5863e579dcb225a7257253fc0 100644 (file)
@@ -73,6 +73,8 @@ struct _ObWindow {
     Rect area; /* area of the redirected window */
     Rect toparea; /* area of the top-level window */
     gint topborder; /* the border around the top-level window */
+    XRectangle *rects; /* rects that make up the shape of the window */
+    gint n_rects; /* number of objects in @rects */
     gboolean mapped;
     gboolean is_redir;
 #endif
@@ -147,6 +149,8 @@ void      window_foreach(ObWindowForeachFunc func);
 #define window_area(w) (*((ObWindow*)w)->area)
 #define window_depth(w) (*((ObWindow*)w)->depth)
 
+void window_adjust_redir_shape(ObWindow *self);
+
 /* Internal openbox-owned windows like the alt-tab popup */
 struct _ObInternalWindow {
     ObWindow super;