add support for shaped windows, and the circulatenotify event
authorDana Jansens <danakj@orodu.net>
Thu, 6 Mar 2008 05:46:31 +0000 (00:46 -0500)
committerDana Jansens <danakj@orodu.net>
Thu, 6 Mar 2008 05:46:31 +0000 (00:46 -0500)
dcompmgr.c
display.c
display.h
render.c
screen.c
screen.h
window.c
window.h

index c16dc5e..175abde 100644 (file)
@@ -16,6 +16,7 @@
 #include <signal.h>
 #include <xcb/xcb.h>
 #include <xcb/damage.h>
+#include <xcb/shape.h>
 
 typedef struct {
     int foo;
@@ -129,6 +130,22 @@ event(d_display_t *dpy)
             screen_refresh(w->sc);
             break;
         }
+        case XCB_CIRCULATE_NOTIFY:
+        {
+            xcb_circulate_notify_event_t *cev;
+            d_screen_t *sc;
+            d_window_t *w;
+
+            cev = (xcb_circulate_notify_event_t*)ev;
+            sc = display_screen_from_root(dpy, cev->event);
+            if (!sc) break;
+            w = screen_find_window(sc, cev->window);
+            if (cev->place == XCB_PLACE_ON_TOP)
+                screen_stacking_move_to_top(sc, w);
+            else
+                screen_stacking_move_to_bottom(sc, w);
+            screen_refresh(w->sc);
+        }
         case XCB_CONFIGURE_NOTIFY:
         {
             xcb_configure_notify_event_t *cev;
@@ -196,6 +213,25 @@ event(d_display_t *dpy)
                 xcb_damage_subtract(dpy->conn, dev->damage,
                                     XCB_NONE, XCB_NONE);
             }
+            else if (dpy->shape.present &&
+                     ev->response_type - dpy->shape.event == XCB_SHAPE_NOTIFY)
+            {
+                xcb_shape_notify_event_t *sev;
+                d_list_it_t *it;
+
+                sev = (xcb_shape_notify_event_t*)ev;
+                for (it = list_top(dpy->screens); it; it = it->next) {
+                    d_screen_t *sc = it->data;
+                    d_window_t *w;
+
+                    w = screen_find_window(sc, sev->affected_window);
+                    if (w) {
+                        sc->window_reshape(w);
+                        screen_refresh(w->sc);
+                        break;
+                    }
+                }
+            }
             break;
         }
         free(ev);
index c3e6b07..5482d6b 100644 (file)
--- a/display.c
+++ b/display.c
@@ -27,6 +27,7 @@ typedef struct {
 #define find_extension_render(dpy) &dpy->render;
 #define find_extension_composite(dpy) &dpy->composite;
 #define find_extension_damage(dpy) &dpy->damage;
+#define find_extension_shape(dpy) &dpy->shape;
 
 #define version_extension_xfixes \
   XCB_XFIXES_MAJOR_VERSION, XCB_XFIXES_MAJOR_VERSION
@@ -50,12 +51,29 @@ typedef struct {
     ext->error   = rep ? rep->first_error : 0;   \
     ext->event   = rep ? rep->first_event : 0;   \
     ext->opcode  = rep ? rep->major_opcode : 0;  \
+}
+
+#define query_extension_version(dpy, name) \
+{ \
+    d_display_ext_t *ext; \
+\
+    ext = find_extension_##name(dpy) \
 \
     if (ext->present) \
         ck_##name = xcb_##name##_query_version(dpy->conn, \
                                                version_extension_##name); \
 }
 
+#define query_extension_version_no_client_version(dpy, name) \
+{ \
+    d_display_ext_t *ext; \
+\
+    ext = find_extension_##name(dpy) \
+\
+    if (ext->present) \
+        ck_##name = xcb_##name##_query_version(dpy->conn); \
+}
+
 #define reply_extension(dpy, name) \
 { \
     xcb_##name##_query_version_reply_t *rep; \
@@ -144,11 +162,19 @@ query_statics(d_display_t *dpy)
     setup_extension(render);
     setup_extension(composite);
     setup_extension(damage);
+    setup_extension(shape);
 
     query_extension(dpy, xfixes);
     query_extension(dpy, render);
     query_extension(dpy, composite);
     query_extension(dpy, damage);
+    query_extension(dpy, shape);
+
+    query_extension_version(dpy, xfixes);
+    query_extension_version(dpy, render);
+    query_extension_version(dpy, composite);
+    query_extension_version(dpy, damage);
+    query_extension_version_no_client_version(dpy, shape);
 
     for (i = 0; atoms[i].atom != NULL; ++i)
         query_atom(dpy, &atoms[i]);
@@ -159,6 +185,7 @@ query_statics(d_display_t *dpy)
     reply_extension(dpy, render);
     reply_extension(dpy, composite);
     reply_extension(dpy, damage);
+    reply_extension(dpy, shape);
 
     for (i = 0; atoms[i].atom != NULL; ++i)
         reply_atom(dpy, &atoms[i]);
@@ -331,15 +358,29 @@ display_error(d_display_t *dpy, xcb_generic_error_t *ev)
         case 8: req = "CompositeReleaseOverlayWindow";       break;
         default: break;
         }
+    else if (major_opcode == dpy->shape.opcode)
+        switch (minor_opcode)
+        {
+        case 0: req = "ShapeQueryVersion";  break;
+        case 1: req = "ShapeRectangles";    break;
+        case 2: req = "ShapeMask";          break;
+        case 3: req = "ShapeCombine";       break;
+        case 4: req = "ShapeOffset";        break;
+        case 5: req = "ShapeQueryExtents";  break;
+        case 6: req = "ShapeSelectInput";   break;
+        case 7: req = "ShapeInputSelected"; break;
+        case 8: req = "ShapeGetRectangles"; break;
+        default: break;
+        }
 
     if (name && req)
-        printf("XError: %s %s!\n",
+        printf("XError: %s %s\n",
                name, req);
     else if (name)
-        printf("XError: %s major opcode %d minor opcode %d!\n",
+        printf("XError: %s major opcode %d minor opcode %d\n",
                name, major_opcode, minor_opcode);
     else
-        printf("XError: code %d major opcode %d minor opcode %d!\n",
+        printf("XError: code %d major opcode %d minor opcode %d\n",
                ev->error_code, major_opcode, minor_opcode);
 
     //abort();
index 181dd6a..cd85ad4 100644 (file)
--- a/display.h
+++ b/display.h
@@ -26,6 +26,7 @@ typedef struct d_display {
     d_display_ext_t render;
     d_display_ext_t composite;
     d_display_ext_t damage;
+    d_display_ext_t shape;
 
     struct {
         /* types */
index b5369ed..f31d0b8 100644 (file)
--- a/render.c
+++ b/render.c
@@ -18,6 +18,7 @@ typedef struct {
     void (*window_show)(d_window_t *w);
     void (*window_hide)(d_window_t *w);
     void (*window_resize)(d_window_t *w);
+    void (*window_reshape)(d_window_t *w);
 
     xcb_render_pictformat_t root_format;
     xcb_render_query_pict_formats_reply_t *pict_formats;
@@ -47,6 +48,7 @@ static xcb_render_picture_t solid_picture(d_screen_t *sc,
 static void render_window_show(d_window_t *window);
 static void render_window_hide(d_window_t *window);
 static void render_window_resize(d_window_t *window);
+static void render_window_reshape(d_window_t *window);
 
 void
 render_init(d_screen_t *sc, int id)
@@ -62,6 +64,7 @@ render_init(d_screen_t *sc, int id)
     d->window_show = sc->window_show;
     d->window_hide = sc->window_hide;
     d->window_resize = sc->window_resize;
+    d->window_reshape = sc->window_reshape;
     screen_add_plugin_data(sc, plugin_id, d);
 
     sc->screen_paint = render_paint;
@@ -69,6 +72,7 @@ render_init(d_screen_t *sc, int id)
     sc->window_show = render_window_show;
     sc->window_hide = render_window_hide;
     sc->window_resize = render_window_resize;
+    sc->window_reshape = render_window_reshape;
 
     ck = xcb_render_query_pict_formats_unchecked(sc->dpy->conn);
     d->pict_formats = xcb_render_query_pict_formats_reply(sc->dpy->conn, ck,
@@ -242,10 +246,36 @@ render_update_picture(d_window_t *w, data_t *d, window_data_t *wd)
                                   wd->picture, px, format,
                                   XCB_RENDER_CP_SUBWINDOW_MODE,
                                   &vals);
+
+        xcb_xfixes_set_picture_clip_region(w->sc->dpy->conn,
+                                           wd->picture,
+                                           window_get_region(w),
+                                           0, 0);
+
     }
 }
 
 static void
+render_window_reshape(d_window_t *w)
+{
+    data_t *d;
+    window_data_t *wd;
+
+    d = screen_find_plugin_data(w->sc, plugin_id);
+    wd = window_find_plugin_data(w, plugin_id);
+
+    /* pass it on, and let the window update it's region before we query
+       it */
+    d->window_reshape(w);
+
+    if (wd->picture)
+        xcb_xfixes_set_picture_clip_region(w->sc->dpy->conn,
+                                           wd->picture,
+                                           window_get_region(w),
+                                           0, 0);
+}
+
+static void
 render_window_resize(d_window_t *w)
 {
     data_t *d;
@@ -253,11 +283,12 @@ render_window_resize(d_window_t *w)
 
     d = screen_find_plugin_data(w->sc, plugin_id);
     wd = window_find_plugin_data(w, plugin_id);
-    assert(wd != NULL);
-    render_free_picture(w, wd);
 
     /* pass it on */
     d->window_resize(w);
+
+    assert(wd != NULL);
+    render_free_picture(w, wd);
 }
 
 static void
@@ -352,6 +383,7 @@ paint_window(d_window_t *w, data_t *d)
         window_get_area(w, &x, &y, &width, &height, &bwidth);
         op = (window_is_argb(w) ?
               XCB_RENDER_PICT_OP_OVER : XCB_RENDER_PICT_OP_SRC);
+
         xcb_render_composite(w->sc->dpy->conn,
                              op,
                              wd->picture,
index e02e4a6..8b6513f 100644 (file)
--- a/screen.c
+++ b/screen.c
@@ -352,6 +352,19 @@ screen_stacking_move_above(d_screen_t *sc, struct d_window *w,
     list_move_before(sc->stacking, wit, ait);
 }
 
+void screen_stacking_move_to_top(d_screen_t *sc, struct d_window *w)
+{
+    d_list_it_t *wit = list_find(sc->stacking, w);
+    d_list_it_t *ait = list_top(sc->stacking);
+    list_move_before(sc->stacking, wit, ait);
+}
+
+void screen_stacking_move_to_bottom(d_screen_t *sc, struct d_window *w)
+{
+    d_list_it_t *wit = list_find(sc->stacking, w);
+    list_move_before(sc->stacking, wit, NULL);
+}
+
 static void
 screen_set_next_repaint(d_screen_t *sc)
 {
@@ -370,6 +383,7 @@ screen_setup_default_functions(d_screen_t *sc)
     sc->window_become_zombie = window_become_zombie;
     sc->window_move = window_move;
     sc->window_resize = window_resize;
+    sc->window_reshape = window_reshape;
     sc->screen_root_pixmap_changed = screen_update_root_pixmap;
 }
 
index 4c40e3b..79baa98 100644 (file)
--- a/screen.h
+++ b/screen.h
@@ -39,6 +39,7 @@ typedef struct d_screen {
     void (*window_become_zombie)(struct d_window *w);
     void (*window_move)(struct d_window *w);
     void (*window_resize)(struct d_window *w);
+    void (*window_reshape)(struct d_window *w);
     void (*screen_root_pixmap_changed)(struct d_screen *sc);
 } d_screen_t;
 
@@ -61,6 +62,8 @@ void screen_stacking_add(d_screen_t *sc, struct d_window *w);
 void screen_stacking_remove(d_screen_t *sc, struct d_window *w);
 void screen_stacking_move_above(d_screen_t *sc, struct d_window *w,
                                 struct d_window *above);
+void screen_stacking_move_to_top(d_screen_t *sc, struct d_window *w);
+void screen_stacking_move_to_bottom(d_screen_t *sc, struct d_window *w);
 
 void screen_setup_default_functions(d_screen_t *sc);
 
index 794a1e4..265e515 100644 (file)
--- a/window.c
+++ b/window.c
@@ -20,12 +20,13 @@ typedef struct {
     int              ref;
 
     /* queried things, don't read them directly from the struct */
-    int              x, y, w, h, bw;
-    gboolean         attr_mapped;
-    gboolean         input_only;
-    gboolean         argb;
-    xcb_visualid_t   visual;
-    xcb_pixmap_t     pixmap;
+    int                 x, y, w, h, bw;
+    gboolean            attr_mapped;
+    gboolean            input_only;
+    gboolean            argb;
+    xcb_visualid_t      visual;
+    xcb_pixmap_t        pixmap;
+    xcb_xfixes_region_t region;
 
     double           opacity;
 
@@ -44,6 +45,8 @@ typedef struct {
 
 static void window_get_attributes_reply(d_window_priv_t *w);
 static void window_get_geometry_reply(d_window_priv_t *w);
+static void window_update_pixmap(d_window_priv_t *w);
+static void window_update_region(d_window_priv_t *w);
 
 d_window_t*
 window_new(xcb_window_t id, struct d_screen *sc)
@@ -58,6 +61,7 @@ window_new(xcb_window_t id, struct d_screen *sc)
     w->mapped = FALSE;
     w->pixmap = XCB_NONE;
     w->damage = XCB_NONE;
+    w->region = XCB_NONE;
 
     screen_stacking_add(sc, (d_window_t*)w);
 
@@ -90,6 +94,11 @@ window_unref(d_window_t *pubw)
     if (w && --w->ref == 0) {
         screen_stacking_remove(w->sc, (d_window_t*)w);
 
+        if (w->region) {
+            xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region);
+            w->region = XCB_NONE;
+        }
+
         if (w->pixmap) {
             /* this may cause an error if the pixmap was never valid, but
                that's fine */
@@ -110,6 +119,24 @@ window_get_pixmap(d_window_t *pubw)
     return w->pixmap;
 }
 
+static void
+window_update_region(d_window_priv_t *w)
+{
+    int x, y, wi, hei, bw;
+
+    if (window_is_zombie((d_window_t*)w)) return;
+
+    if (w->region) {
+        xcb_xfixes_destroy_region(w->sc->dpy->conn, w->region);
+        w->region = XCB_NONE;
+    }
+
+    w->region = xcb_generate_id(w->sc->dpy->conn);
+    xcb_xfixes_create_region_from_window(w->sc->dpy->conn, w->region,
+                                         w->id, XCB_SHAPE_SK_BOUNDING);
+    window_get_area((d_window_t*)w, &x, &y, &wi, &hei, &bw);
+    xcb_xfixes_translate_region(w->sc->dpy->conn, w->region, bw, bw);
+}
 
 static void
 window_update_pixmap(d_window_priv_t *w)
@@ -145,7 +172,12 @@ window_show(d_window_t *pubw)
 
     //printf("show window 0x%x\n", w->id);
 
+    /* make sure this is before we update the window's region */
+    if (w->sc->dpy->shape.present)
+        xcb_shape_select_input(w->sc->dpy->conn, w->id, TRUE);
+
     window_update_pixmap(w);
+    window_update_region(w);
     w->mapped = TRUE;
 }
 
@@ -157,6 +189,8 @@ window_hide(d_window_t *pubw)
     assert(w->mapped);
 
     //printf("hide window 0x%x\n", w->id);
+    if (w->sc->dpy->shape.present)
+        xcb_shape_select_input(w->sc->dpy->conn, w->id, FALSE);
 
     w->mapped = FALSE;
 }
@@ -304,6 +338,14 @@ window_get_visual(d_window_t *pubw)
     return w->visual;
 }
 
+xcb_xfixes_region_t
+window_get_region(d_window_t *pubw)
+{
+    d_window_priv_t *w = (d_window_priv_t*)pubw;
+
+    return w->region;
+}
+
 void
 window_configure(d_window_t *pubw, int x, int y, int width, int height,
                  int border_width)
@@ -321,15 +363,23 @@ window_configure(d_window_t *pubw, int x, int y, int width, int height,
 }
 
 void
-window_move(d_window_t *w)
+window_move(d_window_t *pubw)
 {
-    (void)w;
+    //d_window_priv_t *w = (d_window_priv_t*)pubw;
+    (void)pubw;
 }
 
 void
 window_resize(d_window_t *w)
 {
     window_update_pixmap((d_window_priv_t*)w);
+    window_update_region((d_window_priv_t*)w);
+}
+
+void
+window_reshape(d_window_t *w)
+{
+    window_update_region((d_window_priv_t*)w);
 }
 
 void
@@ -367,7 +417,8 @@ window_create_damage(d_window_t *pubw)
     }
 }
 
-void window_destroy_damage(d_window_t *pubw)
+void
+window_destroy_damage(d_window_t *pubw)
 {
     d_window_priv_t *w = (d_window_priv_t*)pubw;
 
index a3fc770..5e79d4b 100644 (file)
--- a/window.h
+++ b/window.h
@@ -2,6 +2,7 @@
 #define dc__window_h
 
 #include <xcb/xcb.h>
+#include <xcb/xfixes.h>
 #include <glib.h>
 
 struct d_screen;
@@ -26,6 +27,7 @@ void window_configure(d_window_t *w, int x, int y, int width, int height,
                       int border_width);
 void window_move(d_window_t *w);
 void window_resize(d_window_t *w);
+void window_reshape(d_window_t *w);
 
 gboolean window_is_zombie(d_window_t *w);
 gboolean window_is_input_only(d_window_t *w);
@@ -38,6 +40,7 @@ void window_get_area(d_window_t *pubw, int *x, int *y, int *width, int *height,
 
 xcb_pixmap_t window_get_pixmap(d_window_t *w);
 xcb_visualid_t window_get_visual(d_window_t *w);
+xcb_xfixes_region_t window_get_region(d_window_t *w);
 
 void  window_add_plugin_data(d_window_t *w, int id, void *data);
 void* window_find_plugin_data(d_window_t *w, int id);