aboutsummaryrefslogtreecommitdiff
path: root/src/resize.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/resize.c')
-rw-r--r--src/resize.c491
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);
+ }
+
+ }
+
+}
+