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; ifilename = 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; inValue = 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 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); }