X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fframe.c;h=d88074c6aaf8dca3a7189529a093333c1841f495;hb=fa6f70ce3a1e5aff0cdafb4b641128f360278f2a;hp=3565f54ee0d4c2080b95792f4bc29755f21fd0af;hpb=89c7b236b580a78ea529c4c65bc5944c0a52bdf5;p=chaz%2Fopenbox diff --git a/openbox/frame.c b/openbox/frame.c index 3565f54e..d88074c6 100644 --- a/openbox/frame.c +++ b/openbox/frame.c @@ -27,26 +27,22 @@ #include "mainloop.h" #include "focus_cycle.h" #include "focus_cycle_indicator.h" +#include "composite.h" #include "moveresize.h" #include "screen.h" #include "render/theme.h" -#define PLATE_EVENTMASK (SubstructureRedirectMask | FocusChangeMask) #define FRAME_EVENTMASK (EnterWindowMask | LeaveWindowMask | \ - ButtonPressMask | ButtonReleaseMask) + ButtonPressMask | ButtonReleaseMask | \ + SubstructureRedirectMask | FocusChangeMask) #define ELEMENT_EVENTMASK (ButtonPressMask | ButtonReleaseMask | \ ButtonMotionMask | PointerMotionMask | \ EnterWindowMask | LeaveWindowMask) -/* The inner window does not need enter/leave events. - If it does get them, then it needs its own context for enter events - because sloppy focus will focus the window when you enter the inner window - from the frame. */ -#define INNER_EVENTMASK (ButtonPressMask) #define FRAME_ANIMATE_ICONIFY_TIME 150000 /* .15 seconds */ #define FRAME_ANIMATE_ICONIFY_STEP_TIME (G_USEC_PER_SEC / 60) /* 60 Hz */ -#define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_y) +#define FRAME_HANDLE_Y(f) (f->size.top + f->client->area.height + f->cbwidth_b) static void flash_done(gpointer data); static gboolean flash_timeout(gpointer data); @@ -56,6 +52,8 @@ static void set_theme_statics(ObFrame *self); static void free_theme_statics(ObFrame *self); static gboolean frame_animate_iconify(gpointer self); static void frame_adjust_cursors(ObFrame *self); +static void frame_get_offscreen_buffer(ObFrame *self); +static void frame_free_offscreen_buffer(ObFrame *self); static Window createWindow(Window parent, Visual *visual, gulong mask, XSetWindowAttributes *attrib) @@ -67,70 +65,61 @@ static Window createWindow(Window parent, Visual *visual, } -static Visual *check_32bit_client(ObClient *c) -{ - XWindowAttributes wattrib; - Status ret; - - /* we're already running at 32 bit depth, yay. we don't need to use their - visual */ - if (RrDepth(ob_rr_inst) == 32) - return NULL; - - ret = XGetWindowAttributes(ob_display, c->window, &wattrib); - g_assert(ret != BadDrawable); - g_assert(ret != BadWindow); - - if (wattrib.depth == 32) - return wattrib.visual; - return NULL; -} - ObFrame *frame_new(ObClient *client) { XSetWindowAttributes attrib; gulong mask; ObFrame *self; - Visual *visual; + XWindowAttributes wattrib; + Status ret; self = g_new0(ObFrame, 1); self->client = client; - visual = check_32bit_client(client); + ret = XGetWindowAttributes(ob_display, client->window, &wattrib); + g_assert(ret != BadDrawable); + g_assert(ret != BadWindow); + self->has_alpha = composite_window_has_alpha(wattrib.visual); /* create the non-visible decor windows */ - mask = CWEventMask; - if (visual) { - /* client has a 32-bit visual */ - mask |= CWColormap | CWBackPixel | CWBorderPixel; + mask = 0; + if (self->has_alpha) { + /* the colormap/backpixel/borderpixel are required for supporting + windows with 32bit visuals */ + mask = CWColormap | CWBackPixel | CWBorderPixel; /* create a colormap with the visual */ self->colormap = attrib.colormap = XCreateColormap(ob_display, RootWindow(ob_display, ob_screen), - visual, AllocNone); + wattrib.visual, AllocNone); attrib.background_pixel = BlackPixel(ob_display, ob_screen); attrib.border_pixel = BlackPixel(ob_display, ob_screen); } - attrib.event_mask = FRAME_EVENTMASK; - self->window = createWindow(RootWindow(ob_display, ob_screen), visual, - mask, &attrib); - attrib.event_mask = INNER_EVENTMASK; - self->inner = createWindow(self->window, visual, mask, &attrib); - - mask &= ~CWEventMask; - self->plate = createWindow(self->inner, visual, mask, &attrib); + self->window = createWindow(RootWindow(ob_display, ob_screen), + (self->has_alpha ? wattrib.visual : NULL), + mask, &attrib); /* create the visible decor windows */ - mask = CWEventMask; - if (visual) { + mask = 0; + if (self->has_alpha) { /* client has a 32-bit visual */ mask |= CWColormap | CWBackPixel | CWBorderPixel; attrib.colormap = RrColormap(ob_rr_inst); } + + self->backback = createWindow(self->window, NULL, mask, &attrib); + self->backfront = createWindow(self->backback, NULL, mask, &attrib); + + mask |= CWEventMask; attrib.event_mask = ELEMENT_EVENTMASK; + self->innerleft = createWindow(self->window, NULL, mask, &attrib); + self->innertop = createWindow(self->window, NULL, mask, &attrib); + self->innerright = createWindow(self->window, NULL, mask, &attrib); + self->innerbottom = createWindow(self->window, NULL, mask, &attrib); + self->title = createWindow(self->window, NULL, mask, &attrib); self->titleleft = createWindow(self->window, NULL, mask, &attrib); self->titletop = createWindow(self->window, NULL, mask, &attrib); @@ -175,9 +164,9 @@ ObFrame *frame_new(ObClient *client) self->focused = FALSE; /* the other stuff is shown based on decor settings */ - XMapWindow(ob_display, self->plate); - XMapWindow(ob_display, self->inner); XMapWindow(ob_display, self->label); + XMapWindow(ob_display, self->backback); + XMapWindow(ob_display, self->backfront); self->max_press = self->close_press = self->desk_press = self->iconify_press = self->shade_press = FALSE; @@ -242,6 +231,7 @@ void frame_free(ObFrame *self) XDestroyWindow(ob_display, self->window); if (self->colormap) XFreeColormap(ob_display, self->colormap); + frame_free_offscreen_buffer(self); g_free(self); } @@ -250,9 +240,11 @@ void frame_show(ObFrame *self) { if (!self->visible) { self->visible = TRUE; + framerender_frame(self); XMapWindow(ob_display, self->client->window); - XMapWindow(ob_display, self->plate); XMapWindow(ob_display, self->window); + + frame_get_offscreen_buffer(self); } } @@ -262,7 +254,7 @@ void frame_hide(ObFrame *self) self->visible = FALSE; if (!frame_iconify_animating(self)) XUnmapWindow(ob_display, self->window); - XUnmapWindow(ob_display, self->plate); + /* we unmap the client itself so that we can get MapRequest events, and because the ICCCM tells us to! */ XUnmapWindow(ob_display, self->client->window); @@ -301,8 +293,7 @@ void frame_adjust_shape(ObFrame *self) xrect[0].x = 0; xrect[0].y = 0; xrect[0].width = self->area.width; - xrect[0].height = ob_rr_theme->title_height + - self->bwidth + self->rbwidth; + xrect[0].height = self->size.top; ++num; } @@ -321,6 +312,11 @@ void frame_adjust_shape(ObFrame *self) ShapeBounding, 0, 0, xrect, num, ShapeUnion, Unsorted); } + + if (self->pixmap) + XShapeCombineShape(ob_display, self->pixmap, ShapeBounding, + 0, 0, self->window, ShapeBounding, ShapeSet); + #endif } @@ -339,30 +335,43 @@ void frame_adjust_area(ObFrame *self, gboolean moved, self->decorations = self->client->decorations; self->max_horz = self->client->max_horz; self->max_vert = self->client->max_vert; + self->shaded = self->client->shaded; - if (self->decorations & OB_FRAME_DECOR_BORDER) { + if (self->decorations & OB_FRAME_DECOR_BORDER || + (self->client->undecorated && config_theme_keepborder)) self->bwidth = ob_rr_theme->fbwidth; - self->cbwidth_x = ob_rr_theme->cbwidthx; - self->cbwidth_y = ob_rr_theme->cbwidthy; - } else { - self->bwidth = self->cbwidth_x = self->cbwidth_y = 0; - } - self->rbwidth = self->bwidth; + else + self->bwidth = 0; + + if (self->decorations & OB_FRAME_DECOR_BORDER) { + self->cbwidth_l = self->cbwidth_r = ob_rr_theme->cbwidthx; + self->cbwidth_t = self->cbwidth_b = ob_rr_theme->cbwidthy; + } else + self->cbwidth_l = self->cbwidth_t = + self->cbwidth_r = self->cbwidth_b = 0; if (self->max_horz) { - self->cbwidth_x = 0; - self->width = self->client->area.width - self->bwidth * 2; + self->cbwidth_l = self->cbwidth_r = 0; + self->width = self->client->area.width; + if (self->max_vert) + self->cbwidth_b = 0; } else - self->width = self->client->area.width + self->cbwidth_x * 2; + self->width = self->client->area.width + + self->cbwidth_l + self->cbwidth_r; + + /* some elements are sized based of the width, so don't let them have + negative values */ + self->width = MAX(self->width, + (ob_rr_theme->grip_width + self->bwidth) * 2 + 1); STRUT_SET(self->size, - self->cbwidth_x + (!self->max_horz ? self->bwidth : 0), - self->cbwidth_y + self->bwidth, - self->cbwidth_x + (!self->max_horz ? self->bwidth : 0), - self->cbwidth_y + self->bwidth); + self->cbwidth_l + (!self->max_horz ? self->bwidth : 0), + self->cbwidth_t + self->bwidth, + self->cbwidth_r + (!self->max_horz ? self->bwidth : 0), + self->cbwidth_b + (!self->max_horz || !self->max_vert ? self->bwidth : 0)); if (self->decorations & OB_FRAME_DECOR_TITLEBAR) - self->size.top += ob_rr_theme->title_height + self->rbwidth; + self->size.top += ob_rr_theme->title_height + self->bwidth; if (self->decorations & OB_FRAME_DECOR_HANDLE && ob_rr_theme->handle_height > 0) { @@ -372,7 +381,56 @@ void frame_adjust_area(ObFrame *self, gboolean moved, /* position/size and map/unmap all the windows */ if (!fake) { + if (self->cbwidth_l) { + XMoveResizeWindow(ob_display, self->innerleft, + self->size.left - self->cbwidth_l, + self->size.top, + self->cbwidth_l, self->client->area.height); + + XMapWindow(ob_display, self->innerleft); + } else + XUnmapWindow(ob_display, self->innerleft); + + if (self->cbwidth_r) { + XMoveResizeWindow(ob_display, self->innerright, + self->size.left + self->client->area.width, + self->size.top, + self->cbwidth_r, self->client->area.height); + + XMapWindow(ob_display, self->innerright); + } else + XUnmapWindow(ob_display, self->innerright); + + if (self->cbwidth_t) { + XMoveResizeWindow(ob_display, self->innertop, + self->size.left - self->cbwidth_l, + self->size.top - self->cbwidth_t, + self->client->area.width + + self->cbwidth_l + self->cbwidth_r, + self->cbwidth_t); + + XMapWindow(ob_display, self->innertop); + } else + XUnmapWindow(ob_display, self->innertop); + + if (self->cbwidth_b) { + XMoveResizeWindow(ob_display, self->innerbottom, + self->size.left - self->cbwidth_l, + self->size.top + self->client->area.height, + self->client->area.width + + self->cbwidth_l + self->cbwidth_r, + self->cbwidth_b); + + XMapWindow(ob_display, self->innerbottom); + } else + XUnmapWindow(ob_display, self->innerbottom); + if (self->bwidth) { + gint titlesides; + + /* height of titleleft and titleright */ + titlesides = (!self->max_horz ? ob_rr_theme->grip_width : 0); + XMoveResizeWindow(ob_display, self->titletop, ob_rr_theme->grip_width + self->bwidth, 0, /* width + bwidth*2 - bwidth*2 - grips*2 */ @@ -390,36 +448,36 @@ void frame_adjust_area(ObFrame *self, gboolean moved, ob_rr_theme->grip_width + self->bwidth, self->bwidth); - XMoveResizeWindow(ob_display, self->titleleft, - 0, self->bwidth, - self->bwidth, - (!self->max_horz ? - ob_rr_theme->grip_width : - self->size.top - self->bwidth)); - XMoveResizeWindow(ob_display, self->titleright, - self->client->area.width + - self->size.left + self->size.right - - self->bwidth, - self->bwidth, - self->bwidth, - (!self->max_horz ? - ob_rr_theme->grip_width : - self->size.top - self->bwidth)); + if (titlesides > 0) { + XMoveResizeWindow(ob_display, self->titleleft, + 0, self->bwidth, + self->bwidth, + titlesides); + XMoveResizeWindow(ob_display, self->titleright, + self->client->area.width + + self->size.left + self->size.right - + self->bwidth, + self->bwidth, + self->bwidth, + titlesides); + + XMapWindow(ob_display, self->titleleft); + XMapWindow(ob_display, self->titleright); + } else { + XUnmapWindow(ob_display, self->titleleft); + XUnmapWindow(ob_display, self->titleright); + } XMapWindow(ob_display, self->titletop); XMapWindow(ob_display, self->titletopleft); XMapWindow(ob_display, self->titletopright); - XMapWindow(ob_display, self->titleleft); - XMapWindow(ob_display, self->titleright); - if (self->decorations & OB_FRAME_DECOR_TITLEBAR && - self->rbwidth) - { + if (self->decorations & OB_FRAME_DECOR_TITLEBAR) { XMoveResizeWindow(ob_display, self->titlebottom, - self->bwidth, + (self->max_horz ? 0 : self->bwidth), ob_rr_theme->title_height + self->bwidth, self->width, - self->rbwidth); + self->bwidth); XMapWindow(ob_display, self->titlebottom); } else @@ -436,26 +494,25 @@ void frame_adjust_area(ObFrame *self, gboolean moved, if (self->decorations & OB_FRAME_DECOR_TITLEBAR) { XMoveResizeWindow(ob_display, self->title, - self->bwidth, self->bwidth, + (self->max_horz ? 0 : self->bwidth), + self->bwidth, self->width, ob_rr_theme->title_height); XMapWindow(ob_display, self->title); if (self->decorations & OB_FRAME_DECOR_GRIPS) { XMoveResizeWindow(ob_display, self->topresize, - ob_rr_theme->grip_width + self->bwidth, + ob_rr_theme->grip_width, 0, self->width - ob_rr_theme->grip_width *2, ob_rr_theme->paddingy + 1); - XMoveWindow(ob_display, self->tltresize, self->bwidth, 0); - XMoveWindow(ob_display, self->tllresize, self->bwidth, 0); + XMoveWindow(ob_display, self->tltresize, 0, 0); + XMoveWindow(ob_display, self->tllresize, 0, 0); XMoveWindow(ob_display, self->trtresize, - self->bwidth + self->width - - ob_rr_theme->grip_width, 0); + self->width - ob_rr_theme->grip_width, 0); XMoveWindow(ob_display, self->trrresize, - self->bwidth + self->width - - ob_rr_theme->paddingx - 1, 0); + self->width - ob_rr_theme->paddingx - 1, 0); XMapWindow(ob_display, self->topresize); XMapWindow(ob_display, self->tltresize); @@ -478,49 +535,63 @@ void frame_adjust_area(ObFrame *self, gboolean moved, layout_title(self); if (!fake) { - if (self->bwidth) { + gint sidebwidth = self->max_horz ? 0 : self->bwidth; + + if (self->bwidth && self->size.bottom) { XMoveResizeWindow(ob_display, self->handlebottom, ob_rr_theme->grip_width + - self->bwidth * 2, + self->bwidth + sidebwidth, self->size.top + self->client->area.height + self->size.bottom - self->bwidth, self->width - (ob_rr_theme->grip_width + - self->bwidth) * 2, + sidebwidth) * 2, self->bwidth); - XMoveResizeWindow(ob_display, self->lgripleft, - 0, - self->size.top + self->client->area.height + - self->size.bottom - - (!self->max_horz ? - ob_rr_theme->grip_width : - self->size.bottom), - self->bwidth, - (!self->max_horz ? - ob_rr_theme->grip_width : - self->size.bottom)); - XMoveResizeWindow(ob_display, self->rgripright, - self->size.left + self->client->area.width + - self->size.right - self->bwidth, - self->size.top + self->client->area.height + - self->size.bottom - - (!self->max_horz ? - ob_rr_theme->grip_width : - self->size.bottom), - self->bwidth, - (!self->max_horz ? - ob_rr_theme->grip_width : - self->size.bottom)); + + if (sidebwidth) { + XMoveResizeWindow(ob_display, self->lgripleft, + 0, + self->size.top + + self->client->area.height + + self->size.bottom - + (!self->max_horz ? + ob_rr_theme->grip_width : + self->size.bottom - self->cbwidth_b), + self->bwidth, + (!self->max_horz ? + ob_rr_theme->grip_width : + self->size.bottom - self->cbwidth_b)); + XMoveResizeWindow(ob_display, self->rgripright, + self->size.left + + self->client->area.width + + self->size.right - self->bwidth, + self->size.top + + self->client->area.height + + self->size.bottom - + (!self->max_horz ? + ob_rr_theme->grip_width : + self->size.bottom - self->cbwidth_b), + self->bwidth, + (!self->max_horz ? + ob_rr_theme->grip_width : + self->size.bottom - self->cbwidth_b)); + + XMapWindow(ob_display, self->lgripleft); + XMapWindow(ob_display, self->rgripright); + } else { + XUnmapWindow(ob_display, self->lgripleft); + XUnmapWindow(ob_display, self->rgripright); + } XMoveResizeWindow(ob_display, self->lgripbottom, - self->bwidth, + sidebwidth, self->size.top + self->client->area.height + self->size.bottom - self->bwidth, ob_rr_theme->grip_width + self->bwidth, self->bwidth); XMoveResizeWindow(ob_display, self->rgripbottom, self->size.left + self->client->area.width + - self->size.right - self->bwidth * 2 - + self->size.right - self->bwidth - sidebwidth - ob_rr_theme->grip_width, self->size.top + self->client->area.height + self->size.bottom - self->bwidth, @@ -528,8 +599,6 @@ void frame_adjust_area(ObFrame *self, gboolean moved, self->bwidth); XMapWindow(ob_display, self->handlebottom); - XMapWindow(ob_display, self->lgripleft); - XMapWindow(ob_display, self->rgripright); XMapWindow(ob_display, self->lgripbottom); XMapWindow(ob_display, self->rgripbottom); @@ -538,10 +607,10 @@ void frame_adjust_area(ObFrame *self, gboolean moved, { XMoveResizeWindow(ob_display, self->handletop, ob_rr_theme->grip_width + - self->bwidth * 2, + self->bwidth + sidebwidth, FRAME_HANDLE_Y(self), self->width - (ob_rr_theme->grip_width + - self->bwidth) * 2, + sidebwidth) * 2, self->bwidth); XMapWindow(ob_display, self->handletop); @@ -560,7 +629,7 @@ void frame_adjust_area(ObFrame *self, gboolean moved, ob_rr_theme->handle_height); XMoveResizeWindow(ob_display, self->lgriptop, - self->bwidth, + sidebwidth, FRAME_HANDLE_Y(self), ob_rr_theme->grip_width + self->bwidth, @@ -568,8 +637,8 @@ void frame_adjust_area(ObFrame *self, gboolean moved, XMoveResizeWindow(ob_display, self->rgriptop, self->size.left + self->client->area.width + - self->size.right - self->bwidth * 2 - - ob_rr_theme->grip_width, + self->size.right - self->bwidth - + sidebwidth - ob_rr_theme->grip_width, FRAME_HANDLE_Y(self), ob_rr_theme->grip_width + self->bwidth, @@ -612,7 +681,7 @@ void frame_adjust_area(ObFrame *self, gboolean moved, ob_rr_theme->handle_height > 0) { XMoveResizeWindow(ob_display, self->handle, - self->bwidth, + sidebwidth, FRAME_HANDLE_Y(self) + self->bwidth, self->width, ob_rr_theme->handle_height); XMapWindow(ob_display, self->handle); @@ -657,7 +726,7 @@ void frame_adjust_area(ObFrame *self, gboolean moved, if (self->bwidth && !self->max_horz) { XMoveResizeWindow(ob_display, self->right, self->client->area.width + - self->cbwidth_x * 2 + self->bwidth, + self->cbwidth_l + self->cbwidth_r + self->bwidth, self->bwidth + ob_rr_theme->grip_width, self->bwidth, self->client->area.height + @@ -668,24 +737,10 @@ void frame_adjust_area(ObFrame *self, gboolean moved, } else XUnmapWindow(ob_display, self->right); - /* move and resize the inner border window which contains the plate - */ - XMoveResizeWindow(ob_display, self->inner, - 0, - self->size.top - self->cbwidth_y, - self->client->area.width + - self->cbwidth_x * 2 + - (!self->max_horz ? self->bwidth * 2 : 0), - self->client->area.height + - self->cbwidth_y * 2); - - /* move the plate */ - XMoveWindow(ob_display, self->plate, - (!self->max_horz ? self->bwidth : 0) + self->cbwidth_x, - self->cbwidth_y); - - /* when the client has StaticGravity, it likes to move around. */ - XMoveWindow(ob_display, self->client->window, 0, 0); + XMoveResizeWindow(ob_display, self->backback, + self->size.left, self->size.top, + self->client->area.width, + self->client->area.height); } } @@ -722,9 +777,21 @@ void frame_adjust_area(ObFrame *self, gboolean moved, self->area.width, self->area.height); + /* when the client has StaticGravity, it likes to move around. + also this correctly positions the client when it maps. + this also needs to be run when the frame's decorations sizes change! + */ + XMoveWindow(ob_display, self->client->window, + self->size.left, self->size.top); + if (resized) { + self->need_render = TRUE; framerender_frame(self); frame_adjust_shape(self); + + /* the offscreen buffer is invalid when the window is resized */ + if (self->visible) + frame_get_offscreen_buffer(self); } if (!STRUT_EQUAL(self->size, oldsize)) { @@ -747,40 +814,55 @@ void frame_adjust_area(ObFrame *self, gboolean moved, if (resized && (self->decorations & OB_FRAME_DECOR_TITLEBAR)) XResizeWindow(ob_display, self->label, self->label_width, ob_rr_theme->label_height); + } static void frame_adjust_cursors(ObFrame *self) { if ((self->functions & OB_CLIENT_FUNC_RESIZE) != (self->client->functions & OB_CLIENT_FUNC_RESIZE) || - ((self->max_horz && self->max_vert) != - (self->client->max_horz && self->client->max_vert))) + self->max_horz != self->client->max_horz || + self->max_vert != self->client->max_vert || + self->shaded != self->client->shaded) { gboolean r = (self->client->functions & OB_CLIENT_FUNC_RESIZE) && !(self->client->max_horz && self->client->max_vert); + gboolean topbot = !self->client->max_vert; + gboolean sh = self->client->shaded; XSetWindowAttributes a; - a.cursor = ob_cursor(r ? OB_CURSOR_NORTH : OB_CURSOR_NONE); + /* these ones turn off when max vert, and some when shaded */ + a.cursor = ob_cursor(r && topbot && !sh ? + OB_CURSOR_NORTH : OB_CURSOR_NONE); XChangeWindowAttributes(ob_display, self->topresize, CWCursor, &a); XChangeWindowAttributes(ob_display, self->titletop, CWCursor, &a); - a.cursor = ob_cursor(r ? OB_CURSOR_NORTHWEST : OB_CURSOR_NONE); + a.cursor = ob_cursor(r && topbot ? OB_CURSOR_SOUTH : OB_CURSOR_NONE); + XChangeWindowAttributes(ob_display, self->handle, CWCursor, &a); + XChangeWindowAttributes(ob_display, self->handletop, CWCursor, &a); + XChangeWindowAttributes(ob_display, self->handlebottom, CWCursor, &a); + XChangeWindowAttributes(ob_display, self->innerbottom, CWCursor, &a); + + /* these ones change when shaded */ + a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_WEST : OB_CURSOR_NORTHWEST) : + OB_CURSOR_NONE); + XChangeWindowAttributes(ob_display, self->titleleft, CWCursor, &a); XChangeWindowAttributes(ob_display, self->tltresize, CWCursor, &a); XChangeWindowAttributes(ob_display, self->tllresize, CWCursor, &a); XChangeWindowAttributes(ob_display, self->titletopleft, CWCursor, &a); - XChangeWindowAttributes(ob_display, self->titleleft, CWCursor, &a); - a.cursor = ob_cursor(r ? OB_CURSOR_NORTHEAST : OB_CURSOR_NONE); + a.cursor = ob_cursor(r ? (sh ? OB_CURSOR_EAST : OB_CURSOR_NORTHEAST) : + OB_CURSOR_NONE); + XChangeWindowAttributes(ob_display, self->titleright, CWCursor, &a); XChangeWindowAttributes(ob_display, self->trtresize, CWCursor, &a); XChangeWindowAttributes(ob_display, self->trrresize, CWCursor, &a); XChangeWindowAttributes(ob_display, self->titletopright, CWCursor, &a); - XChangeWindowAttributes(ob_display, self->titleright, CWCursor, &a); + + /* these ones are pretty static */ a.cursor = ob_cursor(r ? OB_CURSOR_WEST : OB_CURSOR_NONE); XChangeWindowAttributes(ob_display, self->left, CWCursor, &a); + XChangeWindowAttributes(ob_display, self->innerleft, CWCursor, &a); a.cursor = ob_cursor(r ? OB_CURSOR_EAST : OB_CURSOR_NONE); XChangeWindowAttributes(ob_display, self->right, CWCursor, &a); - a.cursor = ob_cursor(r ? OB_CURSOR_SOUTH : OB_CURSOR_NONE); - XChangeWindowAttributes(ob_display, self->handle, CWCursor, &a); - XChangeWindowAttributes(ob_display, self->handletop, CWCursor, &a); - XChangeWindowAttributes(ob_display, self->handlebottom, CWCursor, &a); + XChangeWindowAttributes(ob_display, self->innerright, CWCursor, &a); a.cursor = ob_cursor(r ? OB_CURSOR_SOUTHWEST : OB_CURSOR_NONE); XChangeWindowAttributes(ob_display, self->lgrip, CWCursor, &a); XChangeWindowAttributes(ob_display, self->handleleft, CWCursor, &a); @@ -798,60 +880,69 @@ static void frame_adjust_cursors(ObFrame *self) void frame_adjust_client_area(ObFrame *self) { - /* resize the plate */ - XResizeWindow(ob_display, self->plate, - self->client->area.width, self->client->area.height); + /* adjust the window which is there to prevent flashing on unmap */ + XMoveResizeWindow(ob_display, self->backfront, 0, 0, + self->client->area.width, + self->client->area.height); } void frame_adjust_state(ObFrame *self) { + self->need_render = TRUE; framerender_frame(self); } void frame_adjust_focus(ObFrame *self, gboolean hilite) { self->focused = hilite; + self->need_render = TRUE; framerender_frame(self); XFlush(ob_display); } void frame_adjust_title(ObFrame *self) { + self->need_render = TRUE; framerender_frame(self); } void frame_adjust_icon(ObFrame *self) { + self->need_render = TRUE; framerender_frame(self); } void frame_grab_client(ObFrame *self) { + /* DO NOT map the client window here. we used to do that, but it is bogus. + we need to set up the client's dimensions and everything before we + send a mapnotify or we create race conditions. + */ + /* reparent the client to the frame */ - XReparentWindow(ob_display, self->client->window, self->plate, 0, 0); + XReparentWindow(ob_display, self->client->window, self->window, 0, 0); /* When reparenting the client window, it is usually not mapped yet, since this occurs from a MapRequest. However, in the case where Openbox is - starting up, the window is already mapped, so we'll see unmap events for - it. There are 2 unmap events generated that we see, one with the 'event' - member set the root window, and one set to the client, but both get - handled and need to be ignored. + starting up, the window is already mapped, so we'll see an unmap event + for it. */ if (ob_state() == OB_STATE_STARTING) - self->client->ignore_unmaps += 2; + ++self->client->ignore_unmaps; /* select the event mask on the client's parent (to receive config/map req's) the ButtonPress is to catch clicks on the client border */ - XSelectInput(ob_display, self->plate, PLATE_EVENTMASK); - - /* map the client so it maps when the frame does */ - XMapWindow(ob_display, self->client->window); + XSelectInput(ob_display, self->window, FRAME_EVENTMASK); /* set all the windows for the frame in the window_map */ g_hash_table_insert(window_map, &self->window, self->client); - g_hash_table_insert(window_map, &self->plate, self->client); - g_hash_table_insert(window_map, &self->inner, self->client); + g_hash_table_insert(window_map, &self->backback, self->client); + g_hash_table_insert(window_map, &self->backfront, self->client); + g_hash_table_insert(window_map, &self->innerleft, self->client); + g_hash_table_insert(window_map, &self->innertop, self->client); + g_hash_table_insert(window_map, &self->innerright, self->client); + g_hash_table_insert(window_map, &self->innerbottom, self->client); g_hash_table_insert(window_map, &self->title, self->client); g_hash_table_insert(window_map, &self->label, self->client); g_hash_table_insert(window_map, &self->max, self->client); @@ -908,7 +999,7 @@ void frame_release_client(ObFrame *self) Reparent events that are generated by us are just discarded here. They are of no consequence to us anyhow. */ - if (ev.xreparent.parent != self->plate) { + if (ev.xreparent.parent != self->window) { reparent = FALSE; XPutBackEvent(ob_display, &ev); break; @@ -926,8 +1017,12 @@ void frame_release_client(ObFrame *self) /* remove all the windows for the frame from the window_map */ g_hash_table_remove(window_map, &self->window); - g_hash_table_remove(window_map, &self->plate); - g_hash_table_remove(window_map, &self->inner); + g_hash_table_remove(window_map, &self->backback); + g_hash_table_remove(window_map, &self->backfront); + g_hash_table_remove(window_map, &self->innerleft); + g_hash_table_remove(window_map, &self->innertop); + g_hash_table_remove(window_map, &self->innerright); + g_hash_table_remove(window_map, &self->innerbottom); g_hash_table_remove(window_map, &self->title); g_hash_table_remove(window_map, &self->label); g_hash_table_remove(window_map, &self->max); @@ -996,7 +1091,7 @@ static void layout_title(ObFrame *self) /* position of the left most button */ const gint left = ob_rr_theme->paddingx + 1; /* position of the right most button */ - const gint right = self->width - bwidth; + const gint right = self->width; /* turn them all off */ self->icon_on = self->desk_on = self->shade_on = self->iconify_on = @@ -1037,43 +1132,49 @@ static void layout_title(ObFrame *self) if ((self->icon_on = is_button_present(self, lc, i))) { /* icon is bigger than buttons */ self->label_width -= bwidth + 2; - self->icon_x = x; + if (i > 0) self->icon_x = x; x += i * (bwidth + 2); + if (i < 0) self->icon_x = x; } } else if (*lc == 'D') { if (firstcon) *firstcon = OB_FRAME_CONTEXT_ALLDESKTOPS; if ((self->desk_on = is_button_present(self, lc, i))) { self->label_width -= bwidth; - self->desk_x = x; + if (i > 0) self->desk_x = x; x += i * bwidth; + if (i < 0) self->desk_x = x; } } else if (*lc == 'S') { if (firstcon) *firstcon = OB_FRAME_CONTEXT_SHADE; if ((self->shade_on = is_button_present(self, lc, i))) { self->label_width -= bwidth; - self->shade_x = x; + if (i > 0) self->shade_x = x; x += i * bwidth; + if (i < 0) self->shade_x = x; } } else if (*lc == 'I') { if (firstcon) *firstcon = OB_FRAME_CONTEXT_ICONIFY; if ((self->iconify_on = is_button_present(self, lc, i))) { self->label_width -= bwidth; - self->iconify_x = x; + if (i > 0) self->iconify_x = x; x += i * bwidth; + if (i < 0) self->iconify_x = x; } } else if (*lc == 'M') { if (firstcon) *firstcon = OB_FRAME_CONTEXT_MAXIMIZE; if ((self->max_on = is_button_present(self, lc, i))) { self->label_width -= bwidth; - self->max_x = x; + if (i > 0) self->max_x = x; x += i * bwidth; + if (i < 0) self->max_x = x; } } else if (*lc == 'C') { if (firstcon) *firstcon = OB_FRAME_CONTEXT_CLOSE; if ((self->close_on = is_button_present(self, lc, i))) { self->label_width -= bwidth; - self->close_x = x; + if (i > 0) self->close_x = x; x += i * bwidth; + if (i < 0) self->close_x = x; } } else continue; /* don't set firstcon */ @@ -1197,13 +1298,6 @@ ObFrameContext frame_context(ObClient *client, Window win, gint x, gint y) } self = client->frame; - if (win == self->inner || win == self->plate) { - /* conceptually, this is the desktop, as far as users are - concerned */ - if (client->type == OB_CLIENT_TYPE_DESKTOP) - return OB_FRAME_CONTEXT_DESKTOP; - return OB_FRAME_CONTEXT_CLIENT; - } /* when the user clicks in the corners of the titlebar and the client is fully maximized, then treat it like they clicked in the @@ -1259,6 +1353,14 @@ ObFrameContext frame_context(ObClient *client, Window win, gint x, gint y) context */ return OB_FRAME_CONTEXT_TITLEBAR; } + else if (self->max_vert && + (win == self->titletop || win == self->topresize)) + /* can't resize vertically when max vert */ + return OB_FRAME_CONTEXT_TITLEBAR; + else if (self->shaded && + (win == self->titletop || win == self->topresize)) + /* can't resize vertically when shaded */ + return OB_FRAME_CONTEXT_TITLEBAR; if (win == self->window) return OB_FRAME_CONTEXT_FRAME; if (win == self->label) return OB_FRAME_CONTEXT_TITLEBAR; @@ -1276,6 +1378,7 @@ ObFrameContext frame_context(ObClient *client, Window win, gint x, gint y) if (win == self->rgriptop) return OB_FRAME_CONTEXT_BLCORNER; if (win == self->rgripbottom) return OB_FRAME_CONTEXT_BLCORNER; if (win == self->title) return OB_FRAME_CONTEXT_TITLEBAR; + if (win == self->titlebottom) return OB_FRAME_CONTEXT_TITLEBAR; if (win == self->titleleft) return OB_FRAME_CONTEXT_TLCORNER; if (win == self->titletopleft) return OB_FRAME_CONTEXT_TLCORNER; if (win == self->titleright) return OB_FRAME_CONTEXT_TRCORNER; @@ -1288,6 +1391,10 @@ ObFrameContext frame_context(ObClient *client, Window win, gint x, gint y) if (win == self->trrresize) return OB_FRAME_CONTEXT_TRCORNER; if (win == self->left) return OB_FRAME_CONTEXT_LEFT; if (win == self->right) return OB_FRAME_CONTEXT_RIGHT; + if (win == self->innertop) return OB_FRAME_CONTEXT_TITLEBAR; + if (win == self->innerleft) return OB_FRAME_CONTEXT_LEFT; + if (win == self->innerbottom) return OB_FRAME_CONTEXT_BOTTOM; + if (win == self->innerright) return OB_FRAME_CONTEXT_RIGHT; if (win == self->max) return OB_FRAME_CONTEXT_MAXIMIZE; if (win == self->iconify) return OB_FRAME_CONTEXT_ICONIFY; if (win == self->close) return OB_FRAME_CONTEXT_CLOSE; @@ -1319,13 +1426,14 @@ void frame_client_gravity(ObFrame *self, gint *x, gint *y, gint w, gint h) case SouthEastGravity: case EastGravity: /* the right side of the client will be the right side of the frame */ - *x -= self->size.right + self->size.left; + *x -= self->size.right + self->size.left - + self->client->border_width * 2; break; case ForgetGravity: case StaticGravity: /* the client's position won't move */ - *x -= self->size.left; + *x -= self->size.left - self->client->border_width; break; } @@ -1348,13 +1456,14 @@ void frame_client_gravity(ObFrame *self, gint *x, gint *y, gint w, gint h) case SouthEastGravity: case SouthGravity: /* the bottom of the client will be the bottom of the frame */ - *y -= self->size.bottom + self->size.top; + *y -= self->size.bottom + self->size.top - + self->client->border_width * 2; break; case ForgetGravity: case StaticGravity: /* the client's position won't move */ - *y -= self->size.top; + *y -= self->size.top - self->client->border_width; break; } } @@ -1378,12 +1487,13 @@ void frame_frame_gravity(ObFrame *self, gint *x, gint *y, gint w, gint h) case EastGravity: case SouthEastGravity: /* the right side of the client will be the right side of the frame */ - *x += self->size.right + self->size.left; + *x += self->size.right + self->size.left - + self->client->border_width * 2; break; case StaticGravity: case ForgetGravity: /* the client's position won't move */ - *x -= self->size.left; + *x += self->size.left - self->client->border_width; break; } @@ -1404,16 +1514,24 @@ void frame_frame_gravity(ObFrame *self, gint *x, gint *y, gint w, gint h) case SouthGravity: case SouthEastGravity: /* the bottom of the client will be the bottom of the frame */ - *y += self->size.bottom + self->size.top; + *y += self->size.bottom + self->size.top - + self->client->border_width * 2; break; case StaticGravity: case ForgetGravity: /* the client's position won't move */ - *y += self->size.top; + *y += self->size.top - self->client->border_width; break; } } +void frame_rect_to_frame(ObFrame *self, Rect *r) +{ + r->width += self->size.left + self->size.right; + r->height += self->size.top + self->size.bottom; + frame_client_gravity(self, &r->x, &r->y, r->width, r->height); +} + static void flash_done(gpointer data) { ObFrame *self = data; @@ -1492,10 +1610,12 @@ static gboolean frame_animate_iconify(gpointer p) if (self->client->icon_geometry.width == 0) { /* there is no icon geometry set so just go straight down */ - Rect *a = screen_physical_area(); + Rect *a = screen_physical_area_monitor + (screen_find_monitor(&self->area)); iconx = self->area.x + self->area.width / 2 + 32; icony = a->y + a->width; iconw = 64; + g_free(a); } else { iconx = self->client->icon_geometry.x; icony = self->client->icon_geometry.y; @@ -1556,10 +1676,14 @@ void frame_end_iconify_animation(ObFrame *self) if (!self->visible) XUnmapWindow(ob_display, self->window); - else + else { /* Send a ConfigureNotify when the animation is done, this fixes KDE's pager showing the window in the wrong place. */ - client_reconfigure(self->client); + client_reconfigure(self->client, TRUE); + + /* the offscreen buffer is invalid when the window is resized */ + frame_get_offscreen_buffer(self); + } /* we're not animating any more ! */ self->iconify_animation_going = 0; @@ -1567,6 +1691,8 @@ void frame_end_iconify_animation(ObFrame *self) XMoveResizeWindow(ob_display, self->window, self->area.x, self->area.y, self->area.width, self->area.height); + /* we delay re-rendering until after we're done animating */ + framerender_frame(self); XFlush(ob_display); } @@ -1621,3 +1747,26 @@ void frame_begin_iconify_animation(ObFrame *self, gboolean iconifying) XMapWindow(ob_display, self->window); } } + +static void frame_get_offscreen_buffer(ObFrame *self) +{ + frame_free_offscreen_buffer(self); + + if (self->visible || frame_iconify_animating(self)) { + self->pixmap = composite_get_window_pixmap(self->window); + /* + self->picture = composite_create_picture(self->window, + wattrib.visual, + &self->has_alpha); + */ + } + +} + +static void frame_free_offscreen_buffer(ObFrame *self) +{ + if (self->pixmap) { + XFreePixmap(ob_display, self->pixmap); + self->pixmap = None; + } +}