All pastes #440906 Raw Edit

Something

public text v1 · immutable
·published 2007-04-15 11:31 UTC
rendered paste body
diff --git a/plugins/ini.c b/plugins/ini.c
index c55d897..288079b 100644
--- a/plugins/ini.c
+++ b/plugins/ini.c
@@ -143,9 +143,11 @@ static IniFileData *
 iniGetFileDataFromFilename (CompDisplay *d,
 			    const char *filename)
 {
-    int len, i;
-    int pluginSep = 0, screenSep = 0;
-    char *pluginStr, *screenStr;
+    int fnLen, length;
+    char *pluginSep;
+    char *screenSep;
+    char *pluginStr;
+    char *screenStr;
     IniFileData *fd;
 
     INI_DISPLAY (d);
@@ -153,35 +155,27 @@ iniGetFileDataFromFilename (CompDisplay *d,
     if (!filename)
 	return NULL;
 
-    len = strlen (filename);
+    fnLen = strlen(filename);
 
-    if (len < (strlen(FILE_SUFFIX) + 2))
+    if (fnLen < (strlen(FILE_SUFFIX) + 2))
 	return NULL;
 
-    if ((filename[0]=='.') || (filename[len-1]=='~'))
+    if ((filename[0] == '.') || (filename[fnLen-1] == '~'))
 	return NULL;
 
     for (fd = id->fileData; fd; fd = fd->next)
 	if (strcmp (fd->filename, filename) == 0)
 	    return fd;
 
-    for (i=0; i<len; i++)
-    {
-	if (filename[i] == '-')
-	{
-	    if (!pluginSep)
-		pluginSep = i-1;
-	    else
-		return NULL; /*found a second dash */
-	}
-	else if (filename[i] == '.')
-	{
-	    if (!screenSep)
-		screenSep = i-1;
-	    else
-		return NULL; /*found a second dot */
-	}
-    }
+    /* the split point for the plugin name */
+    pluginSep = strrchr(filename, '-');
+    if (!pluginSep)
+	return NULL;
+
+    /* the split point for the screen name */
+    screenSep = strrchr(filename, '.');
+    if (!screenSep)
+	return NULL;
 
     if (!pluginSep || !screenSep)
 	return NULL;
@@ -202,17 +196,12 @@ iniGetFileDataFromFilename (CompDisplay *d,
 
     newFd->filename = strdup (filename);
 
-    pluginStr = malloc (sizeof (char) * pluginSep + 1);
-    screenStr = malloc (sizeof (char) * (screenSep - pluginSep) + 1);
-
-    if (!pluginStr || !screenStr)
-	return NULL;
-
-    strncpy (pluginStr, filename, pluginSep + 1);
-    pluginStr[pluginSep + 1] = '\0';
-
-    strncpy (screenStr, &filename[pluginSep+2], (screenSep - pluginSep) + 1);
-    screenStr[(screenSep - pluginSep) -1] = '\0';
+    /* get plugin and screen name */
+    length = strlen(filename) - strlen(pluginSep);
+    pluginStr = strndup(filename, length);
+    pluginSep++; /* skip the '-' */
+    length = strlen(pluginSep) - strlen(screenSep);
+    screenStr = strndup(pluginSep, length);
 
     if (strcmp (pluginStr, CORE_NAME) == 0)
 	newFd->plugin = NULL;
@@ -330,7 +319,7 @@ iniGetFilename (CompDisplay *d,
     if (fn)
     {
 	sprintf (fn, "%s-%s%s",
-		 plugin?plugin:CORE_NAME, screenStr, FILE_SUFFIX);
+		 plugin ? plugin : CORE_NAME, screenStr, FILE_SUFFIX);
 
 	*filename = strdup (fn);
 
@@ -348,48 +337,20 @@ iniGetFilename (CompDisplay *d,
 static Bool
 iniParseLine (char *line, char **optionName, char **optionValue)
 {
-    int  pos = 0;
-    int  splitPos = 0;
-    int  endPos = 0;
-    char tmpName[MAX_OPTION_LENGTH];
-    char tmpValue[MAX_OPTION_LENGTH];
+    char *splitPos;
+    int length;
 
     if (line[0] == '\0' || line[0] == '\n')
 	return FALSE;
 
-    while (pos < strlen(line))
-    {
-	if (!splitPos && line[pos] == '=')
-	    splitPos = pos;
-	if (line[pos] == '\n')
-	{
-	    endPos = pos;
-	    break;
-	}
-	pos++;
-    }
-
-    if (splitPos && endPos)
-    {
-	tmpName[0] = '\0';
-	tmpValue[0] = '\0';
-
-	int i;
-	for (i=0; i < splitPos; i++)
-	    tmpName[i] = line[i];
-	tmpName[splitPos] = '\0';
-
-	for (i=splitPos+1; i<endPos; i++)
-	    tmpValue[i - (splitPos+1)] = line[i];
-	tmpValue[endPos - (splitPos+1)] = '\0';
-
-	*optionName = strdup (tmpName);
-	*optionValue = strdup (tmpValue);
-    }
-    else
-    {
+    splitPos = strchr(line, '=');
+    if (!splitPos)
 	return FALSE;
-    }
+
+    length = strlen(line) - strlen(splitPos);
+    *optionName = strndup(line, length);
+    splitPos++;
+    *optionValue = strndup(splitPos, strlen(splitPos)-1);
 
     return TRUE;
 }
@@ -397,53 +358,48 @@ iniParseLine (char *line, char **optionName, char **optionValue)
 static Bool
 csvToList (char *csv, CompListValue *list, CompOptionType type)
 {
-    char *csvtmp, *split, *item = NULL;
-    int  count = 1, i, itemLength;
+    char *splitStart = NULL;
+    char *splitEnd = NULL;
+    char *item = NULL;
+    int itemLength;
+    int count;
+    int i;
 
     if (csv[0] == '\0')
     {
 	list->nValue = 0;
 	return FALSE;
     }
-
-    csvtmp = strdup (csv);
-    csvtmp = strchr (csv, ',');
-
-    while (csvtmp)
-    {
-	csvtmp++;  /* avoid the comma */
-	count++;
-	csvtmp = strchr (csvtmp, ',');
-    }
-
+ 
+    int length = strlen(csv);
+    count = 1;
+    for (i = 0; i < length; i++)
+	if (csv[i] == ',' && i != length-1)
+	    count++;
+
+    splitStart = csv;
     list->value = malloc (sizeof (CompOptionValue) * count);
     if (list->value)
     {
-	for (i=0; i<count; i++)
+	for (i = 0; i < count; i++)
 	{
-	    split = strchr (csv, ',');
-	    if (split)
+	    splitEnd = strchr(splitStart, ',');
+
+	    if (splitEnd)
 	    {
-		/* > 1 value */
-		itemLength = strlen(csv) - strlen(split);
-		item = realloc (item, sizeof (char) * (itemLength+1));
-		strncpy (item, csv, itemLength);
-		item[itemLength] = '\0';
-		csv += itemLength + 1;
+		itemLength = strlen(splitStart) - strlen(splitEnd);
+		item = strndup(splitStart, itemLength);
 	    }
-	    else
+	    else // last value
 	    {
-		/* 1 value only */
-		itemLength = strlen(csv);
-		item = realloc (item, sizeof (char) * (itemLength+1));
-		strncpy (item, csv, itemLength);
-		item[itemLength] = '\0';
+		item = strdup(splitStart);
 	    }
 
 	    switch (type)
 	    {
 		case CompOptionTypeString:
-		    list->value[i].s = strdup (item);
+		    if (item[0] != '\0')
+			list->value[i].s = strdup (item);
 		    break;
 		case CompOptionTypeBool:
 		    if (item[0] != '\0')
@@ -464,13 +420,14 @@ csvToList (char *csv, CompListValue *list, CompOptionType type)
 		default:
 		    break;
 	    }
+
+	    splitStart = ++splitEnd;
+	    if (item)
+		free(item);
 	}
 	list->nValue = count;
     }
 
-    if (item)
-	free (item);
-
     return TRUE;
 }
 
@@ -543,6 +500,7 @@ parseAction(CompDisplay *d, char *optionName, char *optionValue, IniAction *acti
 	action->a.bell = FALSE;
 	action->a.edgeMask = 0;
 	action->a.edgeButton = 0;
+	action->valueMasks = 0;
     }
     /* detect a new option (might happen when the options are incomplete) */
     else if (action->valueMasks != ACTION_VALUES_ALL)
@@ -639,7 +597,7 @@ iniLoadOptionsFromFile (CompDisplay *d,
     CompScreen *s = NULL;
     CompPlugin *p = NULL;
     Bool status = FALSE;
-    Bool hv = FALSE;
+    Bool hasValue = FALSE;
     CompOptionValue value;
 
     if (plugin)
@@ -688,12 +646,13 @@ iniLoadOptionsFromFile (CompDisplay *d,
 
     IniAction action;
     action.realOptionName = NULL;
-    Bool continueReading = FALSE;
-    while (fgets (&tmp[0], MAX_OPTION_LENGTH, optionFile) != NULL)
+    Bool continueReading;
+    while (fgets (tmp, MAX_OPTION_LENGTH, optionFile) != NULL)
     {
 	status = FALSE;
+	continueReading = FALSE;
 
-	if (!iniParseLine (&tmp[0], &optionName, &optionValue))
+	if (!iniParseLine (tmp, &optionName, &optionValue))
 	{
 	    fprintf(stderr,
 		    "Ignoring line '%s' in %s %i\n", tmp, plugin, screen);
@@ -710,29 +669,29 @@ iniLoadOptionsFromFile (CompDisplay *d,
 		switch (o->type)
 		{
 		case CompOptionTypeBool:
-		    hv = TRUE;
+		    hasValue = TRUE;
 		    value.b = (Bool) atoi (optionValue);
 			break;
 		case CompOptionTypeInt:
-		    hv = TRUE;
+		    hasValue = TRUE;
 		    value.i = atoi (optionValue);
 			break;
 		case CompOptionTypeFloat:
-		    hv = TRUE;
+		    hasValue = TRUE;
 		    value.f = atof (optionValue);
 			break;
 		case CompOptionTypeString:
-		    hv = TRUE;
+		    hasValue = TRUE;
 		    value.s = strdup (optionValue);
 			break;
 		case CompOptionTypeColor:
-		    hv = stringToColor (optionValue, value.c);
+		    hasValue = stringToColor (optionValue, value.c);
 			break;
 		case CompOptionTypeList:
-		    hv = csvToList (optionValue, &value.list, value.list.type);
+		    hasValue = csvToList (optionValue, &value.list, value.list.type);
 			break;
 		case CompOptionTypeMatch:
-		    hv = TRUE;
+		    hasValue = TRUE;
 		    matchInit (&value.match);
 		    matchAddFromString (&value.match, optionValue);
 			break;
@@ -740,7 +699,7 @@ iniLoadOptionsFromFile (CompDisplay *d,
 			break;
 		}
 
-		if (hv)
+		if (hasValue)
 		{
 		    if (plugin && p)
 		    {
@@ -780,10 +739,10 @@ iniLoadOptionsFromFile (CompDisplay *d,
 	    if (action.realOptionName &&
 		!continueReading)
 	    {
-		o = compFindOption (option, nOption, action.realOptionName, 0);
-		if (o)
+		CompOption *realOption = compFindOption (option, nOption, action.realOptionName, 0);
+		if (realOption)
 		{
-		    value = o->value;
+		    value = realOption->value;
 
 		    value.action.type = action.a.type;
 		    value.action.key = action.a.key;
@@ -811,16 +770,12 @@ iniLoadOptionsFromFile (CompDisplay *d,
 		    free(action.realOptionName);
 		    action.realOptionName = NULL;
 
-		    /* we missed the current line because we exited it in the first call */
-		    if (!o && action.valueMasks == ACTION_VALUES_ALL)
-		    {
-		        action.valueMasks = 0;
+		    /* we missed the current line because we exited it in the first call.
+		       we also need to check wether we have a incomplete options here,
+		       because other while parsing the last line again, would caus real
+		       trouble. ;-) */
+		    if (!o && action.valueMasks != ACTION_VALUES_ALL)
 		        parseAction(d, optionName, optionValue, &action);
-		    }
-		    else
-		    {
-		        action.valueMasks = 0;
-		    }
 		}
 	    }
 	}
@@ -830,7 +785,6 @@ iniLoadOptionsFromFile (CompDisplay *d,
 	    free (optionName);
 	if (optionValue)
 	    free (optionValue);
-	continueReading = FALSE;
     } 
 
     return TRUE;
diff --git a/plugins/resize.c b/plugins/resize.c
index b9eb42b..9bdf44c 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,16 +383,32 @@ 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);
 	    rs->grabIndex = 0;
 	}
 
-	rd->w		  = 0;
+	/* don't reset rd->w here if we are using the 'Stretch' mode
+	   and we really resized the window as we still want to apply
+	   the stretching effect until the server processed the resize
+	   request to avoid the window flashing back to the old size */
+	if (((rd->currentWidth == rd->w->attrib.width) &&
+	     (rd->currentHeight == rd->w->attrib.height)) ||
+	    (rd->resizeMode != ResizeModeStretch))
+	{
+	    rd->w = 0;
+	}
+
 	rd->releaseButton = 0;
     }
 
@@ -306,53 +417,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 +454,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 +778,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 +804,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,9 +998,159 @@ 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);
+
+	    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;
+
+	    /* reset rd->w if the window coordinates match and there is no
+               screen grab; which means that resizeTerminate was already 
+	       called and we left rd->w set only to avoid weird flashing */
+	    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 *
@@ -702,6 +1183,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 +1234,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 +1290,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 +1352,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 +1390,9 @@ resizeFiniScreen (CompPlugin *p,
     removeScreenAction (s, 
 			&rd->opt[RESIZE_DISPLAY_OPTION_INITIATE].value.action);
 
+    UNWRAP (rs, s, paintWindow);
+    UNWRAP (rs, s, paintScreen);
+
     free (rs);
 }