From: Dana Jansens Date: Fri, 25 Jun 2010 12:57:19 +0000 (+0200) Subject: Add shape support to the composite code. X-Git-Tag: cgl~22 X-Git-Url: http://git.openbox.org/?a=commitdiff_plain;h=67b640a4fc7bac0aec00113b48c756bdd2628e5d;p=dana%2Fopenbox.git Add shape support to the composite code. 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. --- diff --git a/openbox/composite.c b/openbox/composite.c index 877ed20c..b970eb5e 100644 --- a/openbox/composite.c +++ b/openbox/composite.c @@ -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) diff --git a/openbox/event.c b/openbox/event.c index d23447b3..9033972a 100644 --- a/openbox/event.c +++ b/openbox/event.c @@ -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; diff --git a/openbox/unmanaged.c b/openbox/unmanaged.c index 06480157..8675fc81 100644 --- a/openbox/unmanaged.c +++ b/openbox/unmanaged.c @@ -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); diff --git a/openbox/window.c b/openbox/window.c index e516eea2..a0b9cebf 100644 --- a/openbox/window.c +++ b/openbox/window.c @@ -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) { diff --git a/openbox/window.h b/openbox/window.h index 21c4792a..5ab01443 100644 --- a/openbox/window.h +++ b/openbox/window.h @@ -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;