From 6a9bccbfa253144c084212c3c394d1460e728b80 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Thu, 6 Mar 2008 00:46:31 -0500 Subject: [PATCH] add support for shaped windows, and the circulatenotify event --- dcompmgr.c | 36 ++++++++++++++++++++++++++++++++ display.c | 47 +++++++++++++++++++++++++++++++++++++++--- display.h | 1 + render.c | 36 ++++++++++++++++++++++++++++++-- screen.c | 14 +++++++++++++ screen.h | 3 +++ window.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- window.h | 3 +++ 8 files changed, 195 insertions(+), 14 deletions(-) diff --git a/dcompmgr.c b/dcompmgr.c index c16dc5e..175abde 100644 --- a/dcompmgr.c +++ b/dcompmgr.c @@ -16,6 +16,7 @@ #include #include #include +#include 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); diff --git a/display.c b/display.c index c3e6b07..5482d6b 100644 --- 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(); diff --git a/display.h b/display.h index 181dd6a..cd85ad4 100644 --- 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 */ diff --git a/render.c b/render.c index b5369ed..f31d0b8 100644 --- 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, diff --git a/screen.c b/screen.c index e02e4a6..8b6513f 100644 --- 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; } diff --git a/screen.h b/screen.h index 4c40e3b..79baa98 100644 --- 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); diff --git a/window.c b/window.c index 794a1e4..265e515 100644 --- 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; diff --git a/window.h b/window.h index a3fc770..5e79d4b 100644 --- a/window.h +++ b/window.h @@ -2,6 +2,7 @@ #define dc__window_h #include +#include #include 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); -- 1.9.1