Hi,

I have ported various improvements of Beryl's resize to Compiz:

- multiple resize modes (aside to the standard "normal" mode those are
"Stretch", "Outline" and "Filled Outline")
- better aspect ratio constraining (you now also can resize aspect
constrained windows from other edges than the lower right)
- avoiding of mouse pointer desynchronization when the resizing hit
constraints.

While porting this, I cleaned up the code and fixed some performance
problems, so the code is supposed to work without problems.

If you want to use the new options and are using gconf, you have to do
'make compiz.schemas.in' in your plugin directory to update the schema
file.

Please tell me what you think of that patch and if you experience any
problems while using it.

Thanks for your feedback!

Regards,

Danny
diff --git a/plugins/resize.c b/plugins/resize.c
index b9eb42b..928fb23 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,31 @@ 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;
+
+    int               rightEdge;
+    int               bottomEdge;
+
+    ResizeMode        resizeMode;
+    
     KeyCode	      key[NUM_KEYS];
 } ResizeDisplay;
 
 typedef struct _ResizeScreen {
     int grabIndex;
 
+    PaintWindowProc paintWindow;
+    PaintScreenProc paintScreen;
+
     Cursor leftCursor;
     Cursor rightCursor;
     Cursor upCursor;
@@ -111,6 +156,38 @@ 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 Bool
 resizeInitiate (CompDisplay     *d,
 		CompAction      *action,
@@ -186,12 +263,19 @@ 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->rightEdge  = rd->currentX + rd->currentWidth;
+ 	rd->bottomEdge = rd->currentY + rd->currentHeight;
+
+ 	rd->xDelta = 0;
+	rd->yDelta = 0;
+
 	lastPointerX = x;
 	lastPointerY = y;
 
@@ -250,6 +334,17 @@ resizeInitiate (CompDisplay     *d,
 
 		warpPointer (d, 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)
+		damageScreen (w->screen);
 	}
     }
 
@@ -288,9 +383,15 @@ resizeTerminate (CompDisplay	 *d,
 	}
 	else
 	{
-	    syncWindowPosition (rd->w);
+ 	    if (rd->resizeMode != ResizeModeNormal)
+ 		resizeUpdateRealWindowSize (d);
+	    else
+		syncWindowPosition (rd->w);
 	}
 
+	if (rd->resizeMode != ResizeModeNormal)
+	    damageScreen (rd->w->screen);
+
 	if (rs->grabIndex)
 	{
 	    removeScreenGrab (rd->w->screen, rs->grabIndex, NULL);
@@ -306,53 +407,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 +444,283 @@ 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;
+
+    /* 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 (d, pointerAdjustX, pointerAdjustY);
+    }
+
+    dx -= newWidth - width;
+    dy -= newHeight - height;
+
+    /* If no resizing, drop out now. */
+    if (!dx && !dy)
+       return;
+
+    if (rd->resizeMode != ResizeModeNormal)
+ 	damageScreen(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->rightEdge - rd->currentWidth;
+
+    if (rd->mask & ResizeUpMask)
+ 	rd->currentY = rd->bottomEdge - rd->currentHeight;
+
+    if (rd->resizeMode == ResizeModeNormal)
+    {
+ 	resizeUpdateRealWindowSize(d);
+    }
+    else if (rd->resizeMode == ResizeModeStretch)
+    {
+ 	moveWindow(rd->w, 
+  		   rd->currentX - rd->w->attrib.x,
+  		   rd->currentY - rd->w->attrib.y, 
+  		   TRUE, TRUE);
+  	syncWindowPosition(rd->w);
+    }
+}
 
 static void
 resizeHandleKeyEvent (CompScreen *s,
@@ -448,8 +768,18 @@ resizeHandleKeyEvent (CompScreen *s,
 		x = left + width  * (rKeys[i].dx + 1) / 2;
 		y = top  + height * (rKeys[i].dy + 1) / 2;
 
+ 		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->display, x - pointerX, y - pointerY);
-		rd->mask = rKeys[i].resizeMask;
 		updateScreenGrab (s, rs->grabIndex, rs->cursor[i]);
 	    }
 	    break;
@@ -464,43 +794,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 +988,151 @@ 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 (rs->grabIndex && 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);
+
+	    matrixTranslate (&wTransform, w->attrib.x, w->attrib.y, 0.0f);
+	    matrixScale (&wTransform, xScale, yScale, 0.0f);
+	    matrixTranslate (&wTransform, -w->attrib.x, -w->attrib.y, 0.0f);
+
+	    mask |= PAINT_WINDOW_TRANSFORMED_MASK;
+	}
+
+	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 (rs->grabIndex && 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 +1163,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 +1214,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 +1270,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 +1332,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 +1370,9 @@ resizeFiniScreen (CompPlugin *p,
     removeScreenAction (s, 
 			&rd->opt[RESIZE_DISPLAY_OPTION_INITIATE].value.action);
 
+    UNWRAP (rs, s, paintWindow);
+    UNWRAP (rs, s, paintScreen);
+
     free (rs);
 }
 
_______________________________________________
compiz mailing list
[EMAIL PROTECTED]
http://lists.freedesktop.org/mailman/listinfo/compiz

Reply via email to