summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanny Baumann <dannybaumann@web.de>2008-02-12 07:41:09 +0100
committerDanny Baumann <dannybaumann@web.de>2008-02-12 07:41:09 +0100
commit8d46ffca44feadc50cd2108a180229bd250df99d (patch)
tree4255fa755893ed0460edc18cc1f751462c66c464
parent774d0ee8b78e56d16aa211ea2b79b6abd706ed94 (diff)
downloadshelf-8d46ffca44feadc50cd2108a180229bd250df99d.tar.gz
shelf-8d46ffca44feadc50cd2108a180229bd250df99d.tar.bz2
Correctly save and restore window and frame input shape.
-rw-r--r--shelf.c188
1 files changed, 153 insertions, 35 deletions
diff --git a/shelf.c b/shelf.c
index 9ce8c59..edae117 100644
--- a/shelf.c
+++ b/shelf.c
@@ -36,12 +36,24 @@
#include <math.h>
#include "shelf_options.h"
+typedef struct {
+ Window ipw;
+
+ XRectangle *inputRects;
+ int nInputRects;
+ int inputRectOrdering;
+
+ XRectangle *frameInputRects;
+ int frameNInputRects;
+ int frameInputRectOrdering;
+} ShelfedWindowInfo;
+
typedef struct {
float scale;
float targetScale;
float steps;
- Window ipw;
+ ShelfedWindowInfo *info;
} ShelfWindow;
typedef struct {
@@ -96,46 +108,117 @@ shelfGetRealWindow (CompWindow *w)
for (rw = w->screen->windows; rw; rw = rw->next)
{
SHELF_WINDOW (rw);
- if (sw->ipw == w->id)
+ if (sw->info && sw->info->ipw == w->id)
return rw;
}
return NULL;
}
+static void
+shelfSaveInputShape (CompWindow *w,
+ XRectangle **retRects,
+ int *retCount,
+ int *retOrdering)
+{
+ XRectangle *rects;
+ int count = 0, ordering;
+ Display *dpy = w->screen->display->display;
+
+ rects = XShapeGetRectangles (dpy, w->id, ShapeInput, &count, &ordering);
+
+ /* check if the returned shape exactly matches the window shape -
+ if that is true, the window currently has no set input shape */
+ if ((count == 1) &&
+ (rects[0].x == -w->serverBorderWidth) &&
+ (rects[0].y == -w->serverBorderWidth) &&
+ (rects[0].width == (w->serverWidth + w->serverBorderWidth)) &&
+ (rects[0].height == (w->serverHeight + w->serverBorderWidth)))
+ {
+ count = 0;
+ }
+
+ *retRects = rects;
+ *retCount = count;
+ *retOrdering = ordering;
+}
+
/* Shape the input of the window when scaled.
* Since the IPW will be dealing with the input, removing input
* from the window entirely is a perfectly good solution. */
static void
shelfShapeInput (CompWindow *w)
{
- XRectangle rect;
+ CompWindow *fw;
Display *dpy = w->screen->display->display;
SHELF_WINDOW (w);
- rect.x = 0;
- rect.y = 0;
- rect.width = 0;
- rect.height = 0;
- if (sw->targetScale == 1.0f)
+ /* save old shape */
+ shelfSaveInputShape (w, &sw->info->inputRects,
+ &sw->info->nInputRects, &sw->info->inputRectOrdering);
+
+ fw = findWindowAtDisplay (w->screen->display, w->frame);
+ if (fw)
{
- rect.x = -w->serverBorderWidth;
- rect.y = -w->serverBorderWidth;
- rect.width = (w->serverWidth + w->serverBorderWidth);
- rect.height = (w->serverHeight + w->serverBorderWidth);
+ shelfSaveInputShape(fw, &sw->info->frameInputRects,
+ &sw->info->frameNInputRects,
+ &sw->info->frameInputRectOrdering);
+ }
+ else
+ {
+ sw->info->frameInputRects = NULL;
+ sw->info->frameNInputRects = -1;
+ sw->info->frameInputRectOrdering = 0;
}
+ /* clear shape */
XShapeSelectInput (dpy, w->id, NoEventMask);
XShapeCombineRectangles (dpy, w->id, ShapeInput, 0, 0,
- &rect, 1, ShapeSet, 0);
+ NULL, 0, ShapeSet, 0);
if (w->frame)
XShapeCombineRectangles (dpy, w->frame, ShapeInput, 0, 0,
- &rect, 1, ShapeSet, 0);
+ NULL, 0, ShapeSet, 0);
+
XShapeSelectInput (dpy, w->id, ShapeNotify);
}
static void
+shelfUnshapeInput (CompWindow *w)
+{
+ Display *dpy = w->screen->display->display;
+
+ SHELF_WINDOW (w);
+
+ if (sw->info->nInputRects)
+ {
+ XShapeCombineRectangles (dpy, w->id, ShapeInput, 0, 0,
+ sw->info->inputRects, sw->info->nInputRects,
+ ShapeSet, sw->info->inputRectOrdering);
+ }
+ else
+ {
+ XShapeCombineMask (dpy, w->id, ShapeInput, 0, 0, None, ShapeSet);
+ }
+
+ if (sw->info->frameNInputRects >= 0)
+ {
+ if (sw->info->frameInputRects)
+ {
+ XShapeCombineRectangles (dpy, w->frame, ShapeInput, 0, 0,
+ sw->info->frameInputRects,
+ sw->info->frameNInputRects,
+ ShapeSet,
+ sw->info->frameInputRectOrdering);
+ }
+ else
+ {
+ XShapeCombineMask (dpy, w->frame, ShapeInput, 0, 0, None, ShapeSet);
+ }
+ }
+}
+
+static void
shelfPreparePaintScreen (CompScreen *s,
int msSinceLastPaint)
{
@@ -169,14 +252,8 @@ shelfAdjustIPW (CompWindow *w)
SHELF_WINDOW (w);
- if (!sw->ipw)
+ if (!sw->info || !sw->info->ipw)
return;
- if (sw->targetScale == 1.0f)
- {
- XDestroyWindow (w->screen->display->display, sw->ipw);
- sw->ipw = None;
- return;
- }
width = w->width + 2 * w->attrib.border_width +
w->input.left + w->input.right + 2.0f;
@@ -192,33 +269,66 @@ shelfAdjustIPW (CompWindow *w)
xwc.stack_mode = Above;
xwc.sibling = w->id;
- XConfigureWindow (w->screen->display->display, sw->ipw,
+ XConfigureWindow (w->screen->display->display, sw->info->ipw,
CWSibling | CWStackMode | CWX | CWY | CWWidth | CWHeight,
&xwc);
- XMapWindow (w->screen->display->display, sw->ipw);
+ XMapWindow (w->screen->display->display, sw->info->ipw);
}
/* Create an input prevention window */
static void
shelfCreateIPW (CompWindow *w)
{
+ Window ipw;
XSetWindowAttributes attrib;
SHELF_WINDOW (w);
- if (sw->ipw)
+ if (!sw->info || sw->info->ipw)
return;
attrib.override_redirect = TRUE;
- sw->ipw = XCreateWindow (w->screen->display->display,
- w->screen->root,
- w->serverX - w->input.left,
- w->serverY - w->input.top,
- w->serverWidth + w->input.left + w->input.right,
- w->serverHeight + w->input.top + w->input.bottom,
- 0, CopyFromParent, InputOnly, CopyFromParent,
- CWOverrideRedirect, &attrib);
+ ipw = XCreateWindow (w->screen->display->display,
+ w->screen->root,
+ w->serverX - w->input.left,
+ w->serverY - w->input.top,
+ w->serverWidth + w->input.left + w->input.right,
+ w->serverHeight + w->input.top + w->input.bottom,
+ 0, CopyFromParent, InputOnly, CopyFromParent,
+ CWOverrideRedirect, &attrib);
+
+ sw->info->ipw = ipw;
+}
+
+static Bool
+shelfHandleShelfInfo (CompWindow *w)
+{
+ SHELF_WINDOW (w);
+
+ if (sw->targetScale == 1.0f && sw->info)
+ {
+ if (sw->info->ipw)
+ XDestroyWindow (w->screen->display->display, sw->info->ipw);
+
+ shelfUnshapeInput (w);
+
+ free (sw->info);
+ sw->info = NULL;
+
+ return FALSE;
+ }
+ else if (sw->targetScale != 1.0f && !sw->info)
+ {
+ sw->info = calloc (1, sizeof (ShelfedWindowInfo));
+ if (!sw->info)
+ return FALSE;
+
+ shelfShapeInput (w);
+ shelfCreateIPW (w);
+ }
+
+ return TRUE;
}
/* Sets the scale level and adjust the shape */
@@ -236,8 +346,9 @@ shelfScaleWindow (CompWindow *w,
if ((float) w->width * sw->targetScale < SHELF_MIN_SIZE)
sw->targetScale = SHELF_MIN_SIZE / (float) w->width;
- shelfShapeInput (w);
- shelfCreateIPW (w);
+ if (!shelfHandleShelfInfo (w))
+ return;
+
shelfAdjustIPW (w);
damageScreen (w->screen);
@@ -726,7 +837,7 @@ shelfInitWindow (CompPlugin *p,
sw->scale = 1.0f;
sw->targetScale = 1.0f;
- sw->ipw = None;
+ sw->info = NULL;
w->base.privates[ss->windowPrivateIndex].ptr = sw;
@@ -739,6 +850,13 @@ shelfFiniWindow (CompPlugin *p,
{
SHELF_WINDOW (w);
+ if (sw->info)
+ {
+ sw->targetScale = 1.0f;
+ /* implicitly frees sw->info */
+ shelfHandleShelfInfo (w);
+ }
+
free (sw);
}