All pastes #457496 Raw Edit

Unnamed

public text v1 · immutable
#457496 ·published 2007-04-25 12:55 UTC
rendered paste body
diff --git a/plugins/resize.c b/plugins/resize.c
index 17bf464..8d21ee5 100644
--- a/plugins/resize.c
+++ b/plugins/resize.c
@@ -42,6 +42,16 @@
 #define RESIZE_INITIATE_KEY_DEFAULT           "F8"
 #define RESIZE_INITIATE_KEY_MODIFIERS_DEFAULT CompAltMask
 
+#define RESIZE_BORDER_COLOR_RED   0x2fff
+#define RESIZE_BORDER_COLOR_GREEN 0x2fff
+#define RESIZE_BORDER_COLOR_BLUE  0x4fff
+#define RESIZE_BORDER_COLOR_ALPHA 0x9fff
+
+#define RESIZE_FILL_COLOR_RED   0x2fff
+#define RESIZE_FILL_COLOR_GREEN 0x2fff
+#define RESIZE_FILL_COLOR_BLUE  0x4fff
+#define RESIZE_FILL_COLOR_ALPHA 0x4fff
+
 struct _ResizeKeys {
     char	 *name;
     int		 dx;
@@ -60,8 +70,28 @@ struct _ResizeKeys {
 #define MIN_KEY_WIDTH_INC  24
 #define MIN_KEY_HEIGHT_INC 24
 
-#define RESIZE_DISPLAY_OPTION_INITIATE 0
-#define RESIZE_DISPLAY_OPTION_NUM      1
+#define RESIZE_DISPLAY_OPTION_INITIATE     0
+#define RESIZE_DISPLAY_OPTION_MODE         1
+#define RESIZE_DISPLAY_OPTION_BORDER_COLOR 2
+#define RESIZE_DISPLAY_OPTION_FILL_COLOR   3
+#define RESIZE_DISPLAY_OPTION_NUM          4
+
+typedef enum _ResizeMode {
+    ResizeModeNormal = 0,
+    ResizeModeStretch,
+    ResizeModeOutline,
+    ResizeModeFilledOutline
+} ResizeMode;
+
+char * resizeModes[] = {
+    N_("Normal"),
+    N_("Stretch"),
+    N_("Outline"),
+    N_("Filled Outline")
+};
+
+#define RESIZE_MODE_DEFAULT ResizeModeNormal
+#define NUM_RESIZE_MODES    (sizeof (resizeModes) / sizeof (resizeModes[0]))
 
 static int displayPrivateIndex;
 
@@ -75,16 +105,28 @@ typedef struct _ResizeDisplay {
     XWindowAttributes savedAttrib;
     int		      releaseButton;
     unsigned int      mask;
-    int		      width;
-    int		      height;
-    int		      ucWidth;	/* unconstrained width */
-    int		      ucHeight;	/* unconstrained height */
+
+    int               currentX;
+    int               currentY;
+    int               currentWidth;
+    int               currentHeight;
+
+    /* offsets between pointer and upper left 
+       window edge on resize start */
+    int               xDelta;
+    int               yDelta;
+
+    ResizeMode        resizeMode;
+    
     KeyCode	      key[NUM_KEYS];
 } ResizeDisplay;
 
 typedef struct _ResizeScreen {
     int grabIndex;
 
+    PaintWindowProc paintWindow;
+    PaintScreenProc paintScreen;
+
     Cursor leftCursor;
     Cursor rightCursor;
     Cursor upCursor;
@@ -111,6 +153,59 @@ typedef struct _ResizeScreen {
 
 #define NUM_OPTIONS(d) (sizeof ((d)->opt) / sizeof (CompOption))
 
+static void
+resizeUpdateRealWindowSize (CompDisplay *d)
+{
+    RESIZE_DISPLAY (d);
+    XWindowChanges xwc;
+
+    if (!rd->w)
+	return;
+
+    if (rd->w->state & CompWindowStateMaximizedVertMask)
+	rd->currentHeight = rd->w->serverHeight;
+
+    if (rd->w->state & CompWindowStateMaximizedHorzMask)
+	rd->currentWidth = rd->w->serverWidth;
+
+    if (rd->currentWidth  == rd->w->serverWidth &&
+	rd->currentHeight == rd->w->serverHeight)
+	return;
+
+    if (rd->w->syncWait)
+	return;
+
+    xwc.x = rd->currentX;
+    xwc.y = rd->currentY;
+    xwc.width = rd->currentWidth;
+    xwc.height = rd->currentHeight;
+
+    sendSyncRequest (rd->w);
+
+    configureXWindow (rd->w, CWX | CWY | CWWidth | CWHeight, &xwc);
+}
+
+static void
+resizeDamagePaintRectangle (CompScreen *s)
+{
+    REGION reg;
+
+    RESIZE_DISPLAY (s->display);
+
+    reg.rects    = &reg.extents;
+    reg.numRects = 1;
+
+    reg.extents.x1 = rd->currentX - rd->w->output.left - 1;
+    reg.extents.y1 = rd->currentY - rd->w->output.top - 1;
+    reg.extents.x2 = rd->currentX + rd->currentWidth + 
+	             rd->w->output.right + 1;
+    reg.extents.y2 = rd->currentY + rd->currentHeight + 
+	             rd->w->output.bottom + 1;
+
+//    damageScreenRegion (s, &reg);
+    damageScreen(s);
+}
+
 static Bool
 resizeInitiate (CompDisplay     *d,
 		CompAction      *action,
@@ -186,12 +281,16 @@ resizeInitiate (CompDisplay     *d,
 
 	rd->w	        = w;
 	rd->mask        = mask;
-	rd->ucWidth     = w->attrib.width;
-	rd->ucHeight    = w->attrib.height;
-	rd->width       = w->attrib.width;
-	rd->height      = w->attrib.height;
 	rd->savedAttrib = w->attrib;
 
+ 	rd->currentX      = w->attrib.x;
+ 	rd->currentY      = w->attrib.y;
+  	rd->currentWidth  = w->attrib.width;
+ 	rd->currentHeight = w->attrib.height;
+
+ 	rd->xDelta = 0;
+	rd->yDelta = 0;
+
 	lastPointerX = x;
 	lastPointerY = y;
 
@@ -250,6 +349,17 @@ resizeInitiate (CompDisplay     *d,
 
 		warpPointer (w->screen, xRoot - pointerX, yRoot - pointerY);
 	    }
+
+ 	    rd->xDelta = (x - rd->currentX);
+ 	    if (rd->mask & ResizeRightMask)
+ 		rd->xDelta = rd->w->serverWidth - rd->xDelta;
+
+ 	    rd->yDelta = (y - rd->currentY);
+ 	    if (rd->mask & ResizeDownMask)
+ 		rd->yDelta = rd->w->serverHeight - rd->yDelta;
+
+	    if (rd->resizeMode != ResizeModeNormal)
+		resizeDamagePaintRectangle (w->screen);
 	}
     }
 
@@ -288,16 +398,32 @@ resizeTerminate (CompDisplay	 *d,
 	}
 	else
 	{
-	    syncWindowPosition (rd->w);
+ 	    if (rd->resizeMode != ResizeModeNormal)
+ 		resizeUpdateRealWindowSize (d);
+	    else
+		syncWindowPosition (rd->w);
 	}
 
+	if (rd->resizeMode != ResizeModeNormal)
+	    resizeDamagePaintRectangle (rd->w->screen);
+
 	if (rs->grabIndex)
 	{
 	    removeScreenGrab (rd->w->screen, rs->grabIndex, NULL);
 	    rs->grabIndex = 0;
 	}
 
-	rd->w		  = 0;
+	/* keep rd->w if we are using the stretch mode and there
+	   was actual resize until the resizing is finished to
+	   avoid the window flashing back to the old size for a
+	   short moment */
+	if ((rd->resizeMode != ResizeModeStretch) ||
+	    ((rd->currentWidth == rd->w->serverWidth) &&
+	     (rd->currentHeight == rd->w->serverHeight)))
+	{
+	    rd->w = 0;
+	}
+
 	rd->releaseButton = 0;
     }
 
@@ -306,53 +432,7 @@ resizeTerminate (CompDisplay	 *d,
     return FALSE;
 }
 
-static void
-resizeUpdateWindowSize (CompDisplay *d)
-{
-    int width, height;
-
-    RESIZE_DISPLAY (d);
-
-    if (!rd->w)
-	return;
-
-    if (rd->w->state & CompWindowStateMaximizedVertMask)
-	rd->height = rd->w->serverHeight;
-
-    if (rd->w->state & CompWindowStateMaximizedHorzMask)
-	rd->width = rd->w->serverWidth;
-
-    if (rd->width  == rd->w->serverWidth &&
-	rd->height == rd->w->serverHeight)
-	return;
-
-    if (rd->w->syncWait)
-	return;
-
-    if (constrainNewWindowSize (rd->w,
-				rd->width, rd->height,
-				&width, &height))
-    {
-	XWindowChanges xwc;
-
-	xwc.x = rd->w->serverX;
-	if (rd->mask & ResizeLeftMask)
-	    xwc.x -= width - rd->w->serverWidth;
-
-	xwc.y = rd->w->serverY;
-	if (rd->mask & ResizeUpMask)
-	    xwc.y -= height - rd->w->serverHeight;
-
-	xwc.width  = width;
-	xwc.height = height;
-
-	sendSyncRequest (rd->w);
-
-	configureXWindow (rd->w,
-			  CWX | CWY | CWWidth | CWHeight,
-			  &xwc);
-    }
-}
+#define CLAMP(v, min, max) ((v) <= (min) ? (min) : (v) >= (max) ? (max) : (v))
 
 static void
 resizeConstrainMinMax (CompWindow *w,
@@ -389,18 +469,281 @@ resizeConstrainMinMax (CompWindow *w,
 	max_height = hints->max_height;
     }
 
-#define CLAMP(v, min, max) ((v) <= (min) ? (min) : (v) >= (max) ? (max) : (v))
-
     /* clamp width and height to min and max values */
     width  = CLAMP (width, min_width, max_width);
     height = CLAMP (height, min_height, max_height);
 
-#undef CLAMP
-
     *newWidth  = width;
     *newHeight = height;
 }
 
+static void
+resizeConstrainResizeIncrement (CompWindow * w, 
+				int        width, 
+				int        height, 
+				int        *newWidth, 
+				int        *newHeight)
+{
+    int baseWidth, baseHeight;
+    const XSizeHints *hints = &w->sizeHints;
+
+    if (hints->flags & PResizeInc) 
+    {
+	if (hints->flags & PBaseSize) 
+	{
+	    baseWidth = hints->base_width;
+	    baseHeight = hints->base_height;
+	} 
+	else 
+	{
+	    baseWidth = 0;
+	    baseHeight = 0;
+	}
+
+	if ((width - baseWidth) % hints->width_inc) 
+	    width = baseWidth + (((width - baseWidth) / 
+				  hints->width_inc) * hints->width_inc);
+
+	if ((height - baseHeight) % hints->height_inc) 
+	    height = baseHeight + (((height - baseHeight) / 
+				    hints->height_inc) * hints->height_inc);
+    }
+
+    *newWidth = width;
+    *newHeight = height;
+}
+
+/* this code has its origin in metacity's boxes.c */
+static void
+resizeFindLinePointClosestToPoint (double x1, double y1, 
+		   		   double x2, double y2, 
+				   double px, double py, 
+				   double *valx, double *valy)
+{
+    /* I'll use the shorthand rx, ry for the return values, valx & valy.
+     * Now, we need (rx,ry) to be on the line between (x1,y1) and (x2,y2).
+     * For that to happen, we first need the slope of the line from (x1,y1)
+     * to (rx,ry) must match the slope of (x1,y1) to (x2,y2), i.e.:
+     *   (ry-y1)   (y2-y1)
+     *   ------- = -------
+     *   (rx-x1)   (x2-x1)
+     * If x1==x2, though, this gives divide by zero errors, so we want to
+     * rewrite the equation by multiplying both sides by (rx-x1)*(x2-x1):
+     *   (ry-y1)(x2-x1) = (y2-y1)(rx-x1)
+     * This is a valid requirement even when x1==x2 (when x1==x2, this latter
+     * equation will basically just mean that rx must be equal to both x1 and
+     * x2)
+     *
+     * The other requirement that we have is that the line from (rx,ry) to
+     * (px,py) must be perpendicular to the line from (x1,y1) to (x2,y2).  So
+     * we just need to get a vector in the direction of each line, take the
+     * dot product of the two, and ensure that the result is 0:
+     *   (rx-px)*(x2-x1) + (ry-py)*(y2-y1) = 0.
+     *
+     * This gives us two equations and two unknowns:
+     *
+     *   (ry-y1)(x2-x1) = (y2-y1)(rx-x1)
+     *   (rx-px)*(x2-x1) + (ry-py)*(y2-y1) = 0.
+     *
+     * This particular pair of equations is always solvable so long as
+     * (x1,y1) and (x2,y2) are not the same point (and note that anyone who
+     * calls this function that way is braindead because it means that they
+     * really didn't specify a line after all).  However, the caller should
+     * be careful to avoid making (x1,y1) and (x2,y2) too close (e.g. like
+     * 10^{-8} apart in each coordinate), otherwise roundoff error could
+     * cause issues.  Solving these equations by hand (or using Maple(TM) or
+     * Mathematica(TM) or whatever) results in slightly messy expressions,
+     * but that's all the below few lines do.
+     */
+
+    double diffx, diffy, den;
+    diffx = x2 - x1;
+    diffy = y2 - y1;
+    den = diffx * diffx + diffy * diffy;
+
+    *valx = (py * diffx * diffy + px * diffx * diffx +
+	     y2 * x1 * diffy - y1 * x2 * diffy) / den;
+    *valy = (px * diffx * diffy + py * diffy * diffy +
+	     x2 * y1 * diffx - x1 * y2 * diffx) / den;
+}
+
+/* this function is heavily inspired by metacity's constrain_aspect_ratio */
+static Bool
+resizeConstrainAspectRatio(CompWindow * w, 
+			   int        width, 
+			   int        height, 
+			   int        *retWidth, 
+			   int        *retHeight)
+{
+    const XSizeHints *hints = &w->sizeHints;
+    double minRatio, maxRatio;
+    int newWidth, newHeight;
+    double altWidth, altHeight;
+    double bestWidth, bestHeight;
+    int tolerance = 1;
+    Bool resizeLeftRight = FALSE;
+    Bool resizeUpDown = FALSE;
+
+    RESIZE_DISPLAY(w->screen->display);
+
+    newWidth = width;
+    newHeight = height;
+
+    if (hints->flags & PAspect) 
+    {
+	minRatio = hints->min_aspect.x / (double) hints->min_aspect.y;
+	maxRatio = hints->max_aspect.x / (double) hints->max_aspect.y;
+
+	if (minRatio > maxRatio)
+	    return FALSE;
+
+	resizeLeftRight = (rd->mask == (rd->mask & ResizeLeftMask)) ||
+	                  (rd->mask == (rd->mask & ResizeRightMask));
+	resizeUpDown = (rd->mask == (rd->mask & ResizeUpMask)) ||
+	               (rd->mask == (rd->mask & ResizeDownMask));
+
+	if (resizeLeftRight || resizeUpDown)
+	    tolerance = 2;
+
+	/* return if constraint already is satisfied */
+	if (((width - (height * minRatio)) > (-minRatio * tolerance)) &&
+	    ((width - (height * maxRatio)) < (maxRatio * tolerance)))
+	{
+	    return FALSE;
+	}
+
+	if (resizeLeftRight)
+	    newHeight = CLAMP (newHeight, newWidth / maxRatio, newWidth / minRatio);
+	else if (resizeUpDown)
+	    newWidth = CLAMP (newWidth, newHeight * minRatio, newHeight * maxRatio);
+	else 
+	{
+	    altWidth = CLAMP (newWidth, newHeight * minRatio, newHeight * maxRatio);
+	    altHeight = CLAMP (newHeight, newWidth / maxRatio, newWidth / minRatio);
+
+	    resizeFindLinePointClosestToPoint(altWidth, newHeight, 
+					      newWidth, altHeight,
+      					      newWidth, newHeight, 
+					      &bestWidth, &bestHeight);
+
+	    newWidth = bestWidth;
+	    newHeight = bestHeight;
+	}
+    }
+
+    *retWidth = newWidth;
+    *retHeight = newHeight;
+
+    return TRUE;
+}
+
+#undef CLAMP
+
+static void
+resizeUpdateWindowSize (CompDisplay *d, int dx, int dy)
+{
+    int width, height;
+    int newHeight, newWidth;
+
+    RESIZE_DISPLAY (d);
+
+    if (!rd->w)
+       return;
+
+    /* don't apply resizing in the direction 
+       windows are maximized to */
+    if (rd->w->state & CompWindowStateMaximizedVertMask)
+  	dy = 0;
+
+    if (rd->w->state & CompWindowStateMaximizedHorzMask)
+ 	dx = 0;
+
+    width = rd->currentWidth;
+    height = rd->currentHeight;
+
+    /* Ensure we don't push the window if constraints stop 
+       it from being resized. */
+    if (!(rd->mask & (ResizeLeftMask | ResizeRightMask)))
+ 	dx = 0;
+
+    if (!(rd->mask & (ResizeUpMask | ResizeDownMask)))
+ 	dy = 0;
+
+    /* Apply the width/height modifications */
+    if (rd->mask & ResizeLeftMask)
+ 	width -= dx;
+    else if (rd->mask & ResizeRightMask)
+ 	width += dx;
+
+    if (rd->mask & ResizeUpMask)
+ 	height -= dy;
+    else if (rd->mask & ResizeDownMask)
+ 	height += dy;
+
+    /* Prevent window being resized to a
+       smaller size than 1x1 */
+    width = MAX (1, width);
+    height = MAX (1, height);
+
+    /* Apply constraints */
+    resizeConstrainResizeIncrement (rd->w, width, height, &width, &height);
+
+    newWidth = width;
+    newHeight = height;
+    resizeConstrainAspectRatio (rd->w, width, height, &newWidth, &newHeight);
+    resizeConstrainMinMax (rd->w, newWidth, newHeight, &newWidth, &newHeight);
+
+    if ((width != newWidth) || (height != newHeight))
+    {
+	/* if the resizing hit constraints, move the mouse
+	   pointer to the new border to avoid desynchronization */
+	int pointerAdjustX = 0, pointerAdjustY = 0;
+
+	if (rd->mask & ResizeRightMask)
+	    pointerAdjustX = newWidth - width;
+	else if (rd->mask & ResizeLeftMask)
+	    pointerAdjustX = width - newWidth;
+
+	if (rd->mask & ResizeDownMask)
+	    pointerAdjustY = newHeight - height;
+	else if (rd->mask & ResizeUpMask)
+	    pointerAdjustY = height - newHeight;
+
+	warpPointer (rd->w->screen, pointerAdjustX, pointerAdjustY);
+    }
+
+    dx -= newWidth - width;
+    dy -= newHeight - height;
+
+    /* If no resizing, drop out now. */
+    if (!dx && !dy)
+       return;
+
+    /* damage old paint region */
+    if (rd->resizeMode != ResizeModeNormal)
+	resizeDamagePaintRectangle (rd->w->screen);
+
+    /* Move window by delta if resizing from left/top */
+    if (rd->mask & ResizeLeftMask && newWidth != rd->currentWidth)
+ 	rd->currentX += dx;
+
+    if (rd->mask & ResizeUpMask && newHeight != rd->currentHeight)
+ 	rd->currentY += dy;
+
+    rd->currentWidth = newWidth;
+    rd->currentHeight = newHeight;
+
+    if (rd->mask & ResizeLeftMask)
+ 	rd->currentX = rd->w->serverX + rd->w->serverWidth - rd->currentWidth;
+
+    if (rd->mask & ResizeUpMask)
+ 	rd->currentY = rd->w->serverY + rd->w->serverHeight - rd->currentHeight;
+
+    if (rd->resizeMode == ResizeModeNormal)
+	resizeUpdateRealWindowSize(d);
+    else
+	resizeDamagePaintRectangle (rd->w->screen);
+}
 
 static void
 resizeHandleKeyEvent (CompScreen *s,
@@ -448,8 +791,18 @@ resizeHandleKeyEvent (CompScreen *s,
 		x = left + width  * (rKeys[i].dx + 1) / 2;
 		y = top  + height * (rKeys[i].dy + 1) / 2;
 
-		warpPointer (s, x - pointerX, y - pointerY);
 		rd->mask = rKeys[i].resizeMask;
+ 
+  		/* recalculate delta */
+  		rd->xDelta = (x - rd->currentX);
+  		if (rd->mask & ResizeRightMask)
+  		    rd->xDelta = rd->w->attrib.width - rd->xDelta;
+ 
+  		rd->yDelta = (y - rd->currentY);
+  		if (rd->mask & ResizeDownMask)
+  		    rd->yDelta = rd->w->attrib.height - rd->yDelta;
+ 
+		warpPointer (s, x - pointerX, y - pointerY);
 		updateScreenGrab (s, rs->grabIndex, rs->cursor[i]);
 	    }
 	    break;
@@ -464,43 +817,34 @@ resizeHandleMotionEvent (CompScreen *s,
 {
     RESIZE_SCREEN (s);
 
-    if (rs->grabIndex)
-    {
-	int pointerDx, pointerDy;
-
-	RESIZE_DISPLAY (s->display);
-
-	pointerDx = xRoot - lastPointerX;
-	pointerDy = yRoot - lastPointerY;
-
-	if (pointerDx || pointerDy)
-	{
-	    int w, h;
-
-	    w = rd->ucWidth;
-	    h = rd->ucHeight;
-
-	    if (rd->mask & ResizeLeftMask)
-		w -= pointerDx;
-	    else if (rd->mask & ResizeRightMask)
-		w += pointerDx;
-
-	    if (rd->mask & ResizeUpMask)
-		h -= pointerDy;
-	    else if (rd->mask & ResizeDownMask)
-		h += pointerDy;
-
-	    rd->ucWidth  = w;
-	    rd->ucHeight = h;
-
-	    resizeConstrainMinMax (rd->w, w, h, &w, &h);
+    if (!rs->grabIndex)
+	return;
 
-	    rd->width  = w;
-	    rd->height = h;
+    RESIZE_DISPLAY (s->display);
 
-	    resizeUpdateWindowSize (s->display);
-	}
-    }
+    int pointerDx, pointerDy;
+
+    pointerDx = xRoot - rd->currentX;
+    pointerDy = yRoot - rd->currentY;
+
+    if (rd->mask & ResizeRightMask)
+ 	pointerDx -= (rd->currentWidth - rd->xDelta);
+ 
+    if (rd->mask & ResizeLeftMask)
+ 	pointerDx -= rd->xDelta;
+ 
+    if (rd->mask & ResizeDownMask)
+ 	pointerDy -= (rd->currentHeight - rd->yDelta);
+ 
+    if (rd->mask & ResizeUpMask)
+ 	pointerDy -= rd->yDelta;
+ 
+    if (!pointerDx && !pointerDy)
+ 	return;
+ 
+    resizeUpdateWindowSize (s->display, 
+ 			    pointerDx,
+ 			    pointerDy);
 }
 
 static void
@@ -667,11 +1011,165 @@ resizeHandleEvent (CompDisplay *d,
 	    sa = (XSyncAlarmNotifyEvent *) event;
 
 	    if (rd->w->syncAlarm == sa->alarm)
-		resizeUpdateWindowSize (d);
+		resizeUpdateRealWindowSize (d);
 	}
     }
 }
 
+static Bool
+resizePaintWindow(CompWindow              *w,
+		  const WindowPaintAttrib *attrib,
+		  const CompTransform     *transform,
+		  Region                  region, 
+		  unsigned int            mask)
+{
+    CompScreen *s = w->screen;
+    Bool status;
+
+    RESIZE_SCREEN (s);
+    RESIZE_DISPLAY (s->display);
+
+    if (rd->w && (rd->w->id == w->id))
+    {
+	CompTransform wTransform = *transform;
+
+	if (rd->resizeMode == ResizeModeStretch)
+	{
+	    float xScale = (float)(rd->currentWidth) /
+		           (float)(rd->w->attrib.width);
+	    float yScale = (float)(rd->currentHeight) /
+	                   (float)(rd->w->attrib.height);
+	    int xTranslate = rd->currentX - w->attrib.x;
+	    int yTranslate = rd->currentY - w->attrib.y;
+
+	    matrixTranslate (&wTransform, w->attrib.x, w->attrib.y, 0.0f);
+	    matrixScale (&wTransform, xScale, yScale, 0.0f);
+	    matrixTranslate (&wTransform, 
+			     xTranslate / xScale - w->attrib.x, 
+			     yTranslate / yScale - w->attrib.y, 
+			     0.0f);
+
+	    mask |= PAINT_WINDOW_TRANSFORMED_MASK;
+
+	    /* reset rd->w if it was kept intact only to avoid 
+	       flashing back to the old size */
+	    if (!rs->grabIndex &&
+		(rd->currentWidth == w->attrib.width) &&
+		(rd->currentHeight == w->attrib.height))
+	    {
+		rd->w = 0;
+	    }
+	}
+
+	UNWRAP(rs, s, paintWindow);
+	status = (*s->paintWindow) (w, attrib, &wTransform, region, mask);
+	WRAP(rs, s, paintWindow, resizePaintWindow);
+    }
+    else
+    {
+	UNWRAP(rs, s, paintWindow);
+	status = (*s->paintWindow) (w, attrib, transform, region, mask);
+	WRAP(rs, s, paintWindow, resizePaintWindow);
+    }
+
+    return status;
+}
+
+static void
+resizePaintOutline(CompScreen              *s, 
+		   const ScreenPaintAttrib *sa,
+		   const CompTransform     *transform, 
+		   int                     output,
+		   Bool                    transformed)
+{
+    int           x1, x2, y1, y2;
+    CompTransform sTransform;
+ 
+    RESIZE_SCREEN(s);
+
+    if (!rs->grabIndex)
+	return;
+    
+    RESIZE_DISPLAY(s->display);
+
+    if ((rd->resizeMode != ResizeModeOutline) &&
+	(rd->resizeMode != ResizeModeFilledOutline))
+	return;
+
+    if (!rd->w || (rd->w->state & MAXIMIZE_STATE))
+	return;
+
+    x1 = rd->currentX - rd->w->input.left;
+    x2 = rd->currentX + rd->currentWidth + rd->w->input.right;
+    y1 = rd->currentY - rd->w->input.top;
+    y2 = rd->currentY + rd->w->input.bottom +
+	 (rd->w->shaded ? rd->w->height : rd->currentHeight);
+
+    sTransform = *transform;
+
+    if (transformed)
+    {
+	(s->applyScreenTransform) (s, sa, output, &sTransform);
+	transformToScreenSpace (s, output, -sa->zTranslate, &sTransform);
+    }
+    else
+	transformToScreenSpace (s, output, -DEFAULT_Z_CAMERA, &sTransform);
+
+    glPushMatrix ();
+    glLoadMatrixf (sTransform.m);
+ 
+    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+    glEnable (GL_BLEND);
+ 
+    if (rd->resizeMode == ResizeModeFilledOutline)
+    {
+	glColor4usv (rd->opt[RESIZE_DISPLAY_OPTION_FILL_COLOR].value.c);
+	glRecti (x1, y2, x2, y1);
+    }
+
+    /* This section draws the outline */
+    glColor4usv (rd->opt[RESIZE_DISPLAY_OPTION_BORDER_COLOR].value.c);
+    glLineWidth (2.0);
+    glBegin (GL_LINE_LOOP);
+    glVertex2i (x1, y1);
+    glVertex2i (x2, y1);
+    glVertex2i (x2, y2);
+    glVertex2i (x1, y2);
+    glEnd ();
+
+    /* Clean up */
+    glColor4usv (defaultColor);
+    glDisable (GL_BLEND);
+    glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+    glPopMatrix ();
+}
+
+static Bool
+resizePaintScreen(CompScreen              *s,
+		  const ScreenPaintAttrib *sAttrib,
+		  const CompTransform     *transform,
+		  Region                  region, 
+		  int                     output, 
+		  unsigned int            mask)
+{
+    Bool status = FALSE;
+
+    RESIZE_SCREEN(s);
+    RESIZE_DISPLAY(s->display);
+
+    if (rd->w && rd->resizeMode == ResizeModeStretch)
+	mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
+
+    UNWRAP(rs, s, paintScreen);
+    status = (*s->paintScreen) (s, sAttrib, transform, region, output, mask);
+    WRAP(rs, s, paintScreen, resizePaintScreen);
+
+    if (status)
+	resizePaintOutline(s, sAttrib, transform, output, FALSE);
+
+    return status;
+}
+
 static CompOption *
 resizeGetDisplayOptions (CompPlugin  *plugin,
 			 CompDisplay *display,
@@ -702,6 +1200,25 @@ resizeSetDisplayOption (CompPlugin      *plugin,
     case RESIZE_DISPLAY_OPTION_INITIATE:
 	if (setDisplayAction (display, o, value))
 	    return TRUE;
+	break;
+    case RESIZE_DISPLAY_OPTION_MODE:
+	if (compSetStringOption (o, value))
+	{
+	    int i;
+
+	    rd->resizeMode = RESIZE_MODE_DEFAULT;
+	    for (i = 0; i < o->rest.s.nString; i++)
+		if (strcmp (resizeModes[i], o->value.s) == 0)
+		    rd->resizeMode = (ResizeMode) i;
+
+	    return TRUE;
+	}
+	break;
+    case RESIZE_DISPLAY_OPTION_BORDER_COLOR:
+    case RESIZE_DISPLAY_OPTION_FILL_COLOR:
+	if (compSetColorOption (o, value))
+	    return TRUE;
+	break;
     default:
 	break;
     }
@@ -734,6 +1251,36 @@ resizeDisplayInitOptions (ResizeDisplay *rd,
     o->value.action.key.keycode      =
 	XKeysymToKeycode (display,
 			  XStringToKeysym (RESIZE_INITIATE_KEY_DEFAULT));
+    
+    o = &rd->opt[RESIZE_DISPLAY_OPTION_MODE];
+    o->name           = "resize_mode";
+    o->shortDesc      = N_("Resize Display Mode");
+    o->longDesc       = N_("Select between 'Normal', 'Stretched Texture', "
+			   "'Outline and Filled' outline modes.");
+    o->type           = CompOptionTypeString;
+    o->value.s        = strdup(resizeModes[RESIZE_MODE_DEFAULT]);
+    o->rest.s.string  = resizeModes;
+    o->rest.s.nString = NUM_RESIZE_MODES;
+
+    o = &rd->opt[RESIZE_DISPLAY_OPTION_BORDER_COLOR];
+    o->name       = "border_color";
+    o->shortDesc  = N_("Outline Color");
+    o->longDesc   = N_("Outline Color for Outline and Filled Outline modes.");
+    o->type       = CompOptionTypeColor;
+    o->value.c[0] = RESIZE_BORDER_COLOR_RED;
+    o->value.c[1] = RESIZE_BORDER_COLOR_GREEN;
+    o->value.c[2] = RESIZE_BORDER_COLOR_BLUE;
+    o->value.c[3] = RESIZE_BORDER_COLOR_ALPHA;
+
+    o = &rd->opt[RESIZE_DISPLAY_OPTION_FILL_COLOR];
+    o->name       = "fill_color";
+    o->shortDesc  = N_("Fill Color");
+    o->longDesc   = N_("Fill Color for Filled Outline mode.");
+    o->type       = CompOptionTypeColor;
+    o->value.c[0] = RESIZE_FILL_COLOR_RED;
+    o->value.c[1] = RESIZE_FILL_COLOR_GREEN;
+    o->value.c[2] = RESIZE_FILL_COLOR_BLUE;
+    o->value.c[3] = RESIZE_FILL_COLOR_ALPHA;
 }
 
 static Bool
@@ -760,6 +1307,8 @@ resizeInitDisplay (CompPlugin  *p,
 
     rd->releaseButton = 0;
 
+    rd->resizeMode = RESIZE_MODE_DEFAULT;
+
     for (i = 0; i < NUM_KEYS; i++)
 	rd->key[i] = XKeysymToKeycode (d->display,
 				       XStringToKeysym (rKeys[i].name));
@@ -820,6 +1369,9 @@ resizeInitScreen (CompPlugin *p,
     rs->cursor[3] = rs->downCursor;
 
     addScreenAction (s, &rd->opt[RESIZE_DISPLAY_OPTION_INITIATE].value.action);
+ 
+    WRAP (rs, s, paintWindow, resizePaintWindow);
+    WRAP (rs, s, paintScreen, resizePaintScreen);
 
     s->privates[rd->screenPrivateIndex].ptr = rs;
 
@@ -855,6 +1407,9 @@ resizeFiniScreen (CompPlugin *p,
     removeScreenAction (s, 
 			&rd->opt[RESIZE_DISPLAY_OPTION_INITIATE].value.action);
 
+    UNWRAP (rs, s, paintWindow);
+    UNWRAP (rs, s, paintScreen);
+
     free (rs);
 }