diff options
Diffstat (limited to 'src/resize.c')
-rw-r--r-- | src/resize.c | 491 |
1 files changed, 491 insertions, 0 deletions
diff --git a/src/resize.c b/src/resize.c new file mode 100644 index 0000000..c7961f9 --- /dev/null +++ b/src/resize.c @@ -0,0 +1,491 @@ +/** + * @file resize.c + * @author Joe Wingbermuehle + * @date 2004-2006 + * + * @brief Functions to handle resizing client windows. + * + */ + +#include "jwm.h" +#include "resize.h" +#include "client.h" +#include "outline.h" +#include "main.h" +#include "cursor.h" +#include "misc.h" +#include "pager.h" +#include "status.h" +#include "key.h" +#include "event.h" +#include "border.h" + +static ResizeModeType resizeMode = RESIZE_OPAQUE; + +static int shouldStopResize; + +static void StopResize(ClientNode *np); +static void ResizeController(int wasDestroyed); +static void FixWidth(ClientNode *np); +static void FixHeight(ClientNode *np); + +/** Set the resize mode to use. */ +void SetResizeMode(ResizeModeType mode) { + resizeMode = mode; +} + +/** Callback to stop a resize. */ +void ResizeController(int wasDestroyed) { + if(resizeMode == RESIZE_OUTLINE) { + ClearOutline(); + } + JXUngrabPointer(display, CurrentTime); + JXUngrabKeyboard(display, CurrentTime); + DestroyResizeWindow(); + shouldStopResize = 1; +} + +/** Resize a client window (mouse initiated). */ +void ResizeClient(ClientNode *np, BorderActionType action, + int startx, int starty) { + + XEvent event; + int oldx, oldy; + int oldw, oldh; + int gwidth, gheight; + int lastgwidth, lastgheight; + int delta; + int north, south, east, west; + float ratio, minr, maxr; + + Assert(np); + + if(!(np->state.border & BORDER_RESIZE)) { + return; + } + + if(!GrabMouseForResize(action)) { + Debug("ResizeClient: could not grab mouse"); + return; + } + + if(np->state.status & STAT_SHADED) { + action &= ~(BA_RESIZE_N | BA_RESIZE_S); + } + + np->controller = ResizeController; + shouldStopResize = 0; + + oldx = np->x; + oldy = np->y; + oldw = np->width; + oldh = np->height; + + gwidth = (np->width - np->baseWidth) / np->xinc; + gheight = (np->height - np->baseHeight) / np->yinc; + + GetBorderSize(np, &north, &south, &east, &west); + + startx += np->x - west; + starty += np->y - north; + + CreateResizeWindow(np); + UpdateResizeWindow(np, gwidth, gheight); + + if(!(GetMouseMask() & Button1Mask)) { + StopResize(np); + return; + } + + for(;;) { + + WaitForEvent(&event); + + if(shouldStopResize) { + np->controller = NULL; + return; + } + + switch(event.type) { + case ButtonRelease: + if(event.xbutton.button == Button1) { + StopResize(np); + return; + } + break; + case MotionNotify: + + SetMousePosition(event.xmotion.x_root, event.xmotion.y_root); + DiscardMotionEvents(&event, np->window); + + if(action & BA_RESIZE_N) { + delta = (event.xmotion.y - starty) / np->yinc; + delta *= np->yinc; + if(oldh - delta >= np->minHeight + && (oldh - delta <= np->maxHeight || delta > 0)) { + np->height = oldh - delta; + np->y = oldy + delta; + } + if(!(action & (BA_RESIZE_E | BA_RESIZE_W))) { + FixWidth(np); + } + } + if(action & BA_RESIZE_S) { + delta = (event.xmotion.y - starty) / np->yinc; + delta *= np->yinc; + np->height = oldh + delta; + np->height = Max(np->height, np->minHeight); + np->height = Min(np->height, np->maxHeight); + if(!(action & (BA_RESIZE_E | BA_RESIZE_W))) { + FixWidth(np); + } + } + if(action & BA_RESIZE_E) { + delta = (event.xmotion.x - startx) / np->xinc; + delta *= np->xinc; + np->width = oldw + delta; + np->width = Max(np->width, np->minWidth); + np->width = Min(np->width, np->maxWidth); + if(!(action & (BA_RESIZE_N | BA_RESIZE_S))) { + FixHeight(np); + } + } + if(action & BA_RESIZE_W) { + delta = (event.xmotion.x - startx) / np->xinc; + delta *= np->xinc; + if(oldw - delta >= np->minWidth + && (oldw - delta <= np->maxWidth || delta > 0)) { + np->width = oldw - delta; + np->x = oldx + delta; + } + if(!(action & (BA_RESIZE_N | BA_RESIZE_S))) { + FixHeight(np); + } + } + + if(np->sizeFlags & PAspect) { + if((action & (BA_RESIZE_N | BA_RESIZE_S)) && + (action & (BA_RESIZE_E | BA_RESIZE_W))) { + + ratio = (float)np->width / np->height; + + minr = (float)np->aspect.minx / np->aspect.miny; + if(ratio < minr) { + delta = np->width; + np->width = (int)((float)np->height * minr); + if(action & BA_RESIZE_W) { + np->x -= np->width - delta; + } + } + + maxr = (float)np->aspect.maxx / np->aspect.maxy; + if(ratio > maxr) { + delta = np->height; + np->height = (int)((float)np->width / maxr); + if(action & BA_RESIZE_N) { + np->y -= np->height - delta; + } + } + + } + } + + lastgwidth = gwidth; + lastgheight = gheight; + + gwidth = (np->width - np->baseWidth) / np->xinc; + gheight = (np->height - np->baseHeight) / np->yinc; + + if(lastgheight != gheight || lastgwidth != gwidth) { + + if(np->state.status & STAT_MAXIMIZED) { + np->state.status &= ~STAT_MAXIMIZED; + WriteState(np); + SendConfigureEvent(np); + } + + UpdateResizeWindow(np, gwidth, gheight); + + if(resizeMode == RESIZE_OUTLINE) { + ClearOutline(); + if(np->state.status & STAT_SHADED) { + DrawOutline(np->x - west, np->y - north, + np->width + west + east, north + south); + } else { + DrawOutline(np->x - west, np->y - north, + np->width + west + east, + np->height + north + south); + } + } else { + if(np->state.status & STAT_SHADED) { + JXMoveResizeWindow(display, np->parent, + np->x - west, np->y - north, + np->width + west + east, north + south); + } else { + JXMoveResizeWindow(display, np->parent, + np->x - west, np->y - north, + np->width + west + east, + np->height + north + south); + } + JXMoveResizeWindow(display, np->window, west, + north, np->width, np->height); + SendConfigureEvent(np); + } + + UpdatePager(); + + } + + break; + default: + break; + } + } + +} + +/** Resize a client window (keyboard or menu initiated). */ +void ResizeClientKeyboard(ClientNode *np) { + + XEvent event; + int gwidth, gheight; + int lastgwidth, lastgheight; + int north, south, east, west; + int deltax, deltay; + float ratio, minr, maxr; + + Assert(np); + + if(!(np->state.border & BORDER_RESIZE)) { + return; + } + + if(JXGrabKeyboard(display, np->window, True, GrabModeAsync, + GrabModeAsync, CurrentTime) != GrabSuccess) { + Debug("ResizeClientKeyboard: could not grab keyboard"); + return; + } + GrabMouseForResize(BA_RESIZE_S | BA_RESIZE_E | BA_RESIZE); + + np->controller = ResizeController; + shouldStopResize = 0; + + gwidth = (np->width - np->baseWidth) / np->xinc; + gheight = (np->height - np->baseHeight) / np->yinc; + + GetBorderSize(np, &north, &south, &east, &west); + + CreateResizeWindow(np); + UpdateResizeWindow(np, gwidth, gheight); + + MoveMouse(rootWindow, np->x + np->width, np->y + np->height); + DiscardMotionEvents(&event, np->window); + + for(;;) { + + WaitForEvent(&event); + + if(shouldStopResize) { + np->controller = NULL; + return; + } + + deltax = 0; + deltay = 0; + + if(event.type == KeyPress) { + + while(JXCheckTypedWindowEvent(display, np->window, KeyPress, &event)); + + switch(GetKey(&event.xkey) & 0xFF) { + case KEY_UP: + deltay = Min(-np->yinc, -10); + break; + case KEY_DOWN: + deltay = Max(np->yinc, 10); + break; + case KEY_RIGHT: + deltax = Max(np->xinc, 10); + break; + case KEY_LEFT: + deltax = Min(-np->xinc, -10); + break; + default: + StopResize(np); + return; + } + + } else if(event.type == MotionNotify) { + + SetMousePosition(event.xmotion.x_root, event.xmotion.y_root); + DiscardMotionEvents(&event, np->window); + + deltax = event.xmotion.x - (np->x + np->width); + deltay = event.xmotion.y - (np->y + np->height); + + } else if(event.type == ButtonRelease) { + + StopResize(np); + return; + + } + + if(abs(deltax) < np->xinc && abs(deltay) < np->yinc) { + continue; + } + + deltay -= deltay % np->yinc; + np->height += deltay; + np->height = Max(np->height, np->minHeight); + np->height = Min(np->height, np->maxHeight); + deltax -= deltax % np->xinc; + np->width += deltax; + np->width = Max(np->width, np->minWidth); + np->width = Min(np->width, np->maxWidth); + + if(np->sizeFlags & PAspect) { + + ratio = (float)np->width / np->height; + + minr = (float)np->aspect.minx / np->aspect.miny; + if(ratio < minr) { + np->width = (int)((float)np->height * minr); + } + + maxr = (float)np->aspect.maxx / np->aspect.maxy; + if(ratio > maxr) { + np->height = (int)((float)np->width / maxr); + } + + } + + lastgwidth = gwidth; + lastgheight = gheight; + gwidth = (np->width - np->baseWidth) / np->xinc; + gheight = (np->height - np->baseHeight) / np->yinc; + + if(lastgwidth != gwidth || lastgheight != gheight) { + + if(np->state.status & STAT_MAXIMIZED) { + np->state.status &= ~STAT_MAXIMIZED; + WriteState(np); + SendConfigureEvent(np); + } + + UpdateResizeWindow(np, gwidth, gheight); + + if(resizeMode == RESIZE_OUTLINE) { + ClearOutline(); + if(np->state.status & STAT_SHADED) { + DrawOutline(np->x - west, np->y - north, + np->width + west + east, + north + south); + } else { + DrawOutline(np->x - west, np->y - north, + np->width + west + east, + np->height + north + south); + } + } else { + if(np->state.status & STAT_SHADED) { + JXResizeWindow(display, np->parent, + np->width + west + east, north + south); + } else { + JXResizeWindow(display, np->parent, + np->width + west + east, np->height + north + south); + } + JXResizeWindow(display, np->window, np->width, np->height); + SendConfigureEvent(np); + } + + UpdatePager(); + + } + + } + +} + +/** Stop a resize action. */ +void StopResize(ClientNode *np) { + + int north, south, east, west; + + np->controller = NULL; + + if(resizeMode == RESIZE_OUTLINE) { + ClearOutline(); + } + + JXUngrabPointer(display, CurrentTime); + JXUngrabKeyboard(display, CurrentTime); + + DestroyResizeWindow(); + + GetBorderSize(np, &north, &south, &east, &west); + + if(np->state.status & STAT_SHADED) { + JXMoveResizeWindow(display, np->parent, + np->x - west, np->y - north, + np->width + east + west, north + south); + } else { + JXMoveResizeWindow(display, np->parent, + np->x - west, np->y - north, + np->width + east + west, + np->height + north + south); + } + JXMoveResizeWindow(display, np->window, west, + north, np->width, np->height); + SendConfigureEvent(np); + +} + +/** Fix the width to match the aspect ratio. */ +void FixWidth(ClientNode *np) { + + float ratio, minr, maxr; + + Assert(np); + + if((np->sizeFlags & PAspect) && np->height > 0) { + + ratio = (float)np->width / np->height; + + minr = (float)np->aspect.minx / np->aspect.miny; + if(ratio < minr) { + np->width = (int)((float)np->height * minr); + } + + maxr = (float)np->aspect.maxx / np->aspect.maxy; + if(ratio > maxr) { + np->width = (int)((float)np->height * maxr); + } + + } + +} + +/** Fix the height to match the aspect ratio. */ +void FixHeight(ClientNode *np) { + + float ratio, minr, maxr; + + Assert(np); + + if((np->sizeFlags & PAspect) && np->height > 0) { + + ratio = (float)np->width / np->height; + + minr = (float)np->aspect.minx / np->aspect.miny; + if(ratio < minr) { + np->height = (int)((float)np->width / minr); + } + + maxr = (float)np->aspect.maxx / np->aspect.maxy; + if(ratio > maxr) { + np->height = (int)((float)np->width / maxr); + } + + } + +} + |