10bbfda8aSnia/*
20bbfda8aSnia * Functions related to moving/resizing windows.
30bbfda8aSnia */
40bbfda8aSnia
50bbfda8aSnia#include "ctwm.h"
60bbfda8aSnia
70bbfda8aSnia#include <stdio.h>
80bbfda8aSnia#include <stdlib.h>
90bbfda8aSnia
100bbfda8aSnia#include "colormaps.h"
110bbfda8aSnia#include "events.h"
120bbfda8aSnia#include "event_handlers.h"
130bbfda8aSnia#include "functions.h"
140bbfda8aSnia#include "functions_defs.h"
150bbfda8aSnia#include "functions_internal.h"
160bbfda8aSnia#include "icons.h"
170bbfda8aSnia#include "otp.h"
180bbfda8aSnia#include "parse.h"
19b18c2d1eSnia#include "r_area.h"
20b18c2d1eSnia#include "r_layout.h"
210bbfda8aSnia#include "screen.h"
220bbfda8aSnia#include "util.h"
230bbfda8aSnia#include "vscreen.h"
240bbfda8aSnia#include "win_decorations.h"
250bbfda8aSnia#include "win_ops.h"
260bbfda8aSnia#include "win_resize.h"
270bbfda8aSnia#include "win_utils.h"
280bbfda8aSnia#include "workspace_manager.h"
29b18c2d1eSnia#include "xparsegeometry.h"
300bbfda8aSnia
310bbfda8aSnia
320bbfda8aSnia/*
330bbfda8aSnia * MoveFillDir-ectional specifiers, used in jump/pack/fill
340bbfda8aSnia */
350bbfda8aSniatypedef enum {
360bbfda8aSnia	MFD_BOTTOM,
370bbfda8aSnia	MFD_LEFT,
380bbfda8aSnia	MFD_RIGHT,
390bbfda8aSnia	MFD_TOP,
400bbfda8aSnia} MoveFillDir;
410bbfda8aSniastatic int FindConstraint(TwmWindow *tmp_win, MoveFillDir direction);
420bbfda8aSnia
430bbfda8aSnia/* Internal util */
440bbfda8aSniastatic bool belongs_to_twm_window(TwmWindow *t, Window w);
450bbfda8aSnia
460bbfda8aSnia
470bbfda8aSnia/*
480bbfda8aSnia * Constrained move variables
490bbfda8aSnia *
500bbfda8aSnia * Used in the resize handling, but needed over in event code for
510bbfda8aSnia * ButtonRelease as well.
520bbfda8aSnia */
530bbfda8aSniabool ConstMove = false;
540bbfda8aSniaCMoveDir ConstMoveDir;
550bbfda8aSniaint ConstMoveX;
560bbfda8aSniaint ConstMoveY;
570bbfda8aSniaint ConstMoveXL;
580bbfda8aSniaint ConstMoveXR;
590bbfda8aSniaint ConstMoveYT;
600bbfda8aSniaint ConstMoveYB;
610bbfda8aSnia
620bbfda8aSnia/*
630bbfda8aSnia * Which move-ish function is in progress.  This is _almost_ really a
640bbfda8aSnia * local var in the movewindow() function, but we also reference it in
650bbfda8aSnia * the HandleButtonRelease() event handler because that has to know
660bbfda8aSnia * which move variant we're doing to figure out whether it has to
670bbfda8aSnia * constrain the final coordinates in various ways.
680bbfda8aSnia */
690bbfda8aSniaint MoveFunction;
700bbfda8aSnia
710bbfda8aSnia/*
720bbfda8aSnia * Globals used to keep track of whether the mouse has moved during a
730bbfda8aSnia * resize function.
740bbfda8aSnia */
750bbfda8aSniaint ResizeOrigX;
760bbfda8aSniaint ResizeOrigY;
770bbfda8aSnia
780bbfda8aSnia
790bbfda8aSnia
800bbfda8aSnia/*
810bbfda8aSnia * Now, on to the actual handlers.
820bbfda8aSnia */
830bbfda8aSnia
840bbfda8aSnia
850bbfda8aSnia/*
860bbfda8aSnia *********************************************************
870bbfda8aSnia *
880bbfda8aSnia * First, the various methods of moving windows around.
890bbfda8aSnia *
900bbfda8aSnia *********************************************************
910bbfda8aSnia */
920bbfda8aSnia
930bbfda8aSnia/*
940bbfda8aSnia * Simple f.move and related
950bbfda8aSnia */
960bbfda8aSniastatic void movewindow(EF_FULLPROTO);
970bbfda8aSniaDFHANDLER(move)
980bbfda8aSnia{
990bbfda8aSnia	movewindow(EF_ARGS);
1000bbfda8aSnia}
1010bbfda8aSniaDFHANDLER(forcemove)
1020bbfda8aSnia{
1030bbfda8aSnia	movewindow(EF_ARGS);
1040bbfda8aSnia}
1050bbfda8aSniaDFHANDLER(movepack)
1060bbfda8aSnia{
1070bbfda8aSnia	movewindow(EF_ARGS);
1080bbfda8aSnia}
1090bbfda8aSniaDFHANDLER(movepush)
1100bbfda8aSnia{
1110bbfda8aSnia	movewindow(EF_ARGS);
1120bbfda8aSnia}
1130bbfda8aSnia
1140bbfda8aSnia/* f.move and friends backend */
1150bbfda8aSniastatic void
1160bbfda8aSniamovewindow(EF_FULLPROTO)
1170bbfda8aSnia{
1180bbfda8aSnia	int origX, origY;
1190bbfda8aSnia	bool moving_icon;
1200bbfda8aSnia	bool fromtitlebar;
1210bbfda8aSnia	const Window dragroot = Scr->XineramaRoot;
1220bbfda8aSnia	const Window rootw = eventp->xbutton.root;
1230bbfda8aSnia
1240bbfda8aSnia	/* Better not be a menu open */
1250bbfda8aSnia	PopDownMenu();
1260bbfda8aSnia
1270bbfda8aSnia	/* Stash up just which f.move* variant we are */
1280bbfda8aSnia	MoveFunction = func;
1290bbfda8aSnia
1300bbfda8aSnia	/*
1310bbfda8aSnia	 * Figure whether we're moving opaquely.
1320bbfda8aSnia	 */
1330bbfda8aSnia	if(tmp_win->OpaqueMove) {
1340bbfda8aSnia		if(Scr->OpaqueMoveThreshold >= 200) {
1350bbfda8aSnia			Scr->OpaqueMove = true;
1360bbfda8aSnia		}
1370bbfda8aSnia		else {
1380bbfda8aSnia			const unsigned long sw = tmp_win->frame_width
1390bbfda8aSnia			                         * tmp_win->frame_height;
1400bbfda8aSnia			const unsigned long ss = Scr->rootw  * Scr->rooth;
1410bbfda8aSnia			const float sf = Scr->OpaqueMoveThreshold / 100.0;
1420bbfda8aSnia
1430bbfda8aSnia			if(sw > (ss * sf)) {
1440bbfda8aSnia				Scr->OpaqueMove = false;
1450bbfda8aSnia			}
1460bbfda8aSnia			else {
1470bbfda8aSnia				Scr->OpaqueMove = true;
1480bbfda8aSnia			}
1490bbfda8aSnia		}
1500bbfda8aSnia	}
1510bbfda8aSnia	else {
1520bbfda8aSnia		Scr->OpaqueMove = false;
1530bbfda8aSnia	}
1540bbfda8aSnia
155b18c2d1eSnia#ifdef WINBOX
1560bbfda8aSnia	/* If it's in a WindowBox, adjust coordinates as necessary */
1570bbfda8aSnia	if(tmp_win->winbox) {
1580bbfda8aSnia		XTranslateCoordinates(dpy, dragroot, tmp_win->winbox->window,
1590bbfda8aSnia		                      eventp->xbutton.x_root, eventp->xbutton.y_root,
1600bbfda8aSnia		                      &(eventp->xbutton.x_root), &(eventp->xbutton.y_root), &JunkChild);
1610bbfda8aSnia	}
162b18c2d1eSnia#endif
1630bbfda8aSnia
1640bbfda8aSnia	/*
1650bbfda8aSnia	 * XXX pulldown=true only when we're triggering from a ButtonRelease
1660bbfda8aSnia	 * in a menu, and this warp should only be going somewhere if we hit
1670bbfda8aSnia	 * the winbox case above and had to translate the coordinates?  But,
1680bbfda8aSnia	 * in that case, the coordinates would be changed to be relative to
1690bbfda8aSnia	 * the winbox window, and here we're positioning relative to Root?
1700bbfda8aSnia	 */
1710bbfda8aSnia	if(pulldown)
1720bbfda8aSnia		XWarpPointer(dpy, None, Scr->Root,
1730bbfda8aSnia		             0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
1740bbfda8aSnia
1750bbfda8aSnia	/*
1760bbfda8aSnia	 * Stub out handlers for enter/leave notifications while we do stuff.
1770bbfda8aSnia	 * They get reset toward the end of the ButtonRelease handler.
1780bbfda8aSnia	 */
1790bbfda8aSnia	EventHandler[EnterNotify] = HandleUnknown;
1800bbfda8aSnia	EventHandler[LeaveNotify] = HandleUnknown;
1810bbfda8aSnia
1820bbfda8aSnia	if(!Scr->NoGrabServer || !Scr->OpaqueMove) {
1830bbfda8aSnia		XGrabServer(dpy);
1840bbfda8aSnia	}
1850bbfda8aSnia
1860bbfda8aSnia	/*
1870bbfda8aSnia	 * Setup size for the window showing current location as we move it.
1880bbfda8aSnia	 * The same window is used for resize ops too, where it might be a
1890bbfda8aSnia	 * different size.
1900bbfda8aSnia	 */
1910bbfda8aSnia	Scr->SizeStringOffset = SIZE_HINDENT;
192b18c2d1eSnia	MoveResizeSizeWindow(eventp->xbutton.x_root, eventp->xbutton.y_root,
193b18c2d1eSnia	                     Scr->SizeStringWidth + SIZE_HINDENT * 2,
194b18c2d1eSnia	                     Scr->SizeFont.height + SIZE_VINDENT * 2);
1950bbfda8aSnia	XMapRaised(dpy, Scr->SizeWindow);
1960bbfda8aSnia
1970bbfda8aSnia	/*
1980bbfda8aSnia	 * Use XGrabPointer() to configure how we get events locations
1990bbfda8aSnia	 * reported relative to what root.
2000bbfda8aSnia	 */
2010bbfda8aSnia	{
202b18c2d1eSnia#ifdef WINBOX
2030bbfda8aSnia		const Window grabwin = (tmp_win->winbox ? tmp_win->winbox->window
2040bbfda8aSnia		                        : Scr->XineramaRoot);
205b18c2d1eSnia#else
206b18c2d1eSnia		const Window grabwin = Scr->XineramaRoot;
207b18c2d1eSnia#endif
2080bbfda8aSnia
2090bbfda8aSnia		XGrabPointer(dpy, grabwin, True,
2100bbfda8aSnia		             ButtonPressMask | ButtonReleaseMask |
2110bbfda8aSnia		             ButtonMotionMask | PointerMotionMask,
2120bbfda8aSnia		             GrabModeAsync, GrabModeAsync, grabwin, Scr->MoveCursor,
2130bbfda8aSnia		             CurrentTime);
2140bbfda8aSnia	}
2150bbfda8aSnia
2160bbfda8aSnia	/*
2170bbfda8aSnia	 * Set w to what we're actually moving.  If it's an icon, we always
2180bbfda8aSnia	 * move it opaquely anyway.  If it's a window (that's not iconofied),
2190bbfda8aSnia	 * we move the frame.
2200bbfda8aSnia	 */
2210bbfda8aSnia	moving_icon = false;
2220bbfda8aSnia	if(context == C_ICON && tmp_win->icon && tmp_win->icon->w) {
2230bbfda8aSnia		w = tmp_win->icon->w;
2240bbfda8aSnia		DragX = eventp->xbutton.x;
2250bbfda8aSnia		DragY = eventp->xbutton.y;
2260bbfda8aSnia		moving_icon = true;
2270bbfda8aSnia		if(tmp_win->OpaqueMove) {
2280bbfda8aSnia			Scr->OpaqueMove = true;
2290bbfda8aSnia		}
2300bbfda8aSnia	}
2310bbfda8aSnia	else if(! tmp_win->icon || w != tmp_win->icon->w) {
2320bbfda8aSnia		XTranslateCoordinates(dpy, w, tmp_win->frame,
2330bbfda8aSnia		                      eventp->xbutton.x,
2340bbfda8aSnia		                      eventp->xbutton.y,
2350bbfda8aSnia		                      &DragX, &DragY, &JunkChild);
2360bbfda8aSnia
2370bbfda8aSnia		w = tmp_win->frame;
2380bbfda8aSnia	}
2390bbfda8aSnia
2400bbfda8aSnia	DragWindow = None;
2410bbfda8aSnia
2420bbfda8aSnia	/* Get x/y relative to parent window, i.e. the virtual screen, Root.
2430bbfda8aSnia	 * XMoveWindow() moves are relative to this.
2440bbfda8aSnia	 * MoveOutline()s however are drawn from the XineramaRoot since they
2450bbfda8aSnia	 * may cross virtual screens.
2460bbfda8aSnia	 */
2470bbfda8aSnia	XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
2480bbfda8aSnia	             &DragWidth, &DragHeight, &DragBW,
2490bbfda8aSnia	             &JunkDepth);
2500bbfda8aSnia
2510bbfda8aSnia	origX = eventp->xbutton.x_root;
2520bbfda8aSnia	origY = eventp->xbutton.y_root;
2530bbfda8aSnia	CurrentDragX = origDragX;
2540bbfda8aSnia	CurrentDragY = origDragY;
2550bbfda8aSnia
2560bbfda8aSnia	/*
2570bbfda8aSnia	 * Setup ConstrainedMove if this is a double-click.  That means
2580bbfda8aSnia	 * setting the flags, and moving the pointer off to the middle of the
2590bbfda8aSnia	 * window.
2600bbfda8aSnia	 *
2610bbfda8aSnia	 * Only do the constrained move if timer is set; need to check it
2620bbfda8aSnia	 * in case of stupid or wicked fast servers
2630bbfda8aSnia	 */
2640bbfda8aSnia	if(ConstrainedMoveTime &&
2650bbfda8aSnia	                (eventp->xbutton.time - last_time) < ConstrainedMoveTime) {
2660bbfda8aSnia		int width, height;
2670bbfda8aSnia
2680bbfda8aSnia		ConstMove = true;
2690bbfda8aSnia		ConstMoveDir = MOVE_NONE;
2700bbfda8aSnia		ConstMoveX = eventp->xbutton.x_root - DragX - DragBW;
2710bbfda8aSnia		ConstMoveY = eventp->xbutton.y_root - DragY - DragBW;
2720bbfda8aSnia		width = DragWidth + 2 * DragBW;
2730bbfda8aSnia		height = DragHeight + 2 * DragBW;
2740bbfda8aSnia		ConstMoveXL = ConstMoveX + width / 3;
2750bbfda8aSnia		ConstMoveXR = ConstMoveX + 2 * (width / 3);
2760bbfda8aSnia		ConstMoveYT = ConstMoveY + height / 3;
2770bbfda8aSnia		ConstMoveYB = ConstMoveY + 2 * (height / 3);
2780bbfda8aSnia
2790bbfda8aSnia		XWarpPointer(dpy, None, w,
2800bbfda8aSnia		             0, 0, 0, 0, DragWidth / 2, DragHeight / 2);
2810bbfda8aSnia
2820bbfda8aSnia		XQueryPointer(dpy, w, &JunkRoot, &JunkChild,
2830bbfda8aSnia		              &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
2840bbfda8aSnia	}
2850bbfda8aSnia	last_time = eventp->xbutton.time;
2860bbfda8aSnia
2870bbfda8aSnia	/* If not moving opaquely, setup the outline bits */
2880bbfda8aSnia	if(!Scr->OpaqueMove) {
2890bbfda8aSnia		InstallRootColormap();
2900bbfda8aSnia		if(!Scr->MoveDelta) {
2910bbfda8aSnia			/*
2920bbfda8aSnia			 * Draw initial outline.  This was previously done the
2930bbfda8aSnia			 * first time though the outer loop by dropping out of
2940bbfda8aSnia			 * the XCheckMaskEvent inner loop down to one of the
2950bbfda8aSnia			 * MoveOutline's below.
2960bbfda8aSnia			 */
2970bbfda8aSnia			MoveOutline(dragroot,
2980bbfda8aSnia			            origDragX - DragBW + Scr->currentvs->x,
2990bbfda8aSnia			            origDragY - DragBW + Scr->currentvs->y,
3000bbfda8aSnia			            DragWidth + 2 * DragBW, DragHeight + 2 * DragBW,
3010bbfda8aSnia			            tmp_win->frame_bw,
3020bbfda8aSnia			            moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
3030bbfda8aSnia			/*
3040bbfda8aSnia			 * This next line causes HandleReleaseNotify to call
3050bbfda8aSnia			 * XRaiseWindow().  This is solely to preserve the
3060bbfda8aSnia			 * previous behaviour that raises a window being moved
3070bbfda8aSnia			 * on button release even if you never actually moved
3080bbfda8aSnia			 * any distance (unless you move less than MoveDelta or
3090bbfda8aSnia			 * NoRaiseMove is set or OpaqueMove is set).
3100bbfda8aSnia			 */
3110bbfda8aSnia			DragWindow = w;
3120bbfda8aSnia		}
3130bbfda8aSnia	}
3140bbfda8aSnia
3150bbfda8aSnia	/*
3160bbfda8aSnia	 * Init whether triggered from something on the titlebar (e.g., a
3170bbfda8aSnia	 * TitleButton bound to f.move).  We need to keep this var in a scope
3180bbfda8aSnia	 * outside the event loop below because the resetting of it in there
3190bbfda8aSnia	 * is supposed to have effect on future loops.
3200bbfda8aSnia	 */
3210bbfda8aSnia	fromtitlebar = belongs_to_twm_window(tmp_win, eventp->xbutton.window);
3220bbfda8aSnia
3230bbfda8aSnia	if(menuFromFrameOrWindowOrTitlebar) {
3240bbfda8aSnia		/* warp the pointer to the middle of the window */
3250bbfda8aSnia		XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
3260bbfda8aSnia		             origDragX + DragWidth / 2,
3270bbfda8aSnia		             origDragY + DragHeight / 2);
3280bbfda8aSnia		XFlush(dpy);
3290bbfda8aSnia	}
3300bbfda8aSnia
3310bbfda8aSnia	/* Fill in the position window with where we're starting */
3320bbfda8aSnia	DisplayPosition(tmp_win, CurrentDragX, CurrentDragY);
3330bbfda8aSnia
3340bbfda8aSnia	/*
3350bbfda8aSnia	 * Internal event loop for doing the moving.
3360bbfda8aSnia	 */
3370bbfda8aSnia	while(1) {
3380bbfda8aSnia		const long releaseEvent = menuFromFrameOrWindowOrTitlebar ?
3390bbfda8aSnia		                          ButtonPress : ButtonRelease;
3400bbfda8aSnia		const long movementMask = menuFromFrameOrWindowOrTitlebar ?
3410bbfda8aSnia		                          PointerMotionMask : ButtonMotionMask;
3420bbfda8aSnia
3430bbfda8aSnia		/* block until there is an interesting event */
3440bbfda8aSnia		XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
3450bbfda8aSnia		           EnterWindowMask | LeaveWindowMask |
3460bbfda8aSnia		           ExposureMask | movementMask |
3470bbfda8aSnia		           VisibilityChangeMask, &Event);
3480bbfda8aSnia
3490bbfda8aSnia		/* throw away enter and leave events until release */
3500bbfda8aSnia		if(Event.xany.type == EnterNotify ||
3510bbfda8aSnia		                Event.xany.type == LeaveNotify) {
3520bbfda8aSnia			continue;
3530bbfda8aSnia		}
3540bbfda8aSnia
3550bbfda8aSnia		/* discard any extra motion events before a logical release */
3560bbfda8aSnia		if(Event.type == MotionNotify) {
3570bbfda8aSnia			while(XCheckMaskEvent(dpy, movementMask | releaseEvent, &Event))
3580bbfda8aSnia				if(Event.type == releaseEvent) {
3590bbfda8aSnia					break;
3600bbfda8aSnia				}
3610bbfda8aSnia		}
3620bbfda8aSnia
3630bbfda8aSnia		/* test to see if we have a second button press to abort move */
3640bbfda8aSnia		if(!menuFromFrameOrWindowOrTitlebar) {
3650bbfda8aSnia			if(Event.type == ButtonPress && DragWindow != None) {
3660bbfda8aSnia				Cursor cur;
3670bbfda8aSnia				if(Scr->OpaqueMove) {
3680bbfda8aSnia					XMoveWindow(dpy, DragWindow, origDragX, origDragY);
3690bbfda8aSnia					if(moving_icon) {
3700bbfda8aSnia						tmp_win->icon->w_x = origDragX;
3710bbfda8aSnia						tmp_win->icon->w_y = origDragY;
3720bbfda8aSnia					}
3730bbfda8aSnia				}
3740bbfda8aSnia				else {
3750bbfda8aSnia					MoveOutline(dragroot, 0, 0, 0, 0, 0, 0);
3760bbfda8aSnia				}
3770bbfda8aSnia				DragWindow = None;
3780bbfda8aSnia
3790bbfda8aSnia				XUnmapWindow(dpy, Scr->SizeWindow);
3800bbfda8aSnia				cur = LeftButt;
3810bbfda8aSnia				if(Event.xbutton.button == Button2) {
3820bbfda8aSnia					cur = MiddleButt;
3830bbfda8aSnia				}
3840bbfda8aSnia				else if(Event.xbutton.button >= Button3) {
3850bbfda8aSnia					cur = RightButt;
3860bbfda8aSnia				}
3870bbfda8aSnia
3880bbfda8aSnia				XGrabPointer(dpy, Scr->Root, True,
3890bbfda8aSnia				             ButtonReleaseMask | ButtonPressMask,
3900bbfda8aSnia				             GrabModeAsync, GrabModeAsync,
3910bbfda8aSnia				             Scr->Root, cur, CurrentTime);
3920bbfda8aSnia				func_reset_cursor = false;  // Leave cursor alone
3930bbfda8aSnia				return;
3940bbfda8aSnia			}
3950bbfda8aSnia		}
3960bbfda8aSnia
3970bbfda8aSnia		if(fromtitlebar && Event.type == ButtonPress) {
3980bbfda8aSnia			fromtitlebar = false;
3990bbfda8aSnia			CurrentDragX = origX = Event.xbutton.x_root;
4000bbfda8aSnia			CurrentDragY = origY = Event.xbutton.y_root;
4010bbfda8aSnia			XTranslateCoordinates(dpy, rootw, tmp_win->frame,
4020bbfda8aSnia			                      origX, origY,
4030bbfda8aSnia			                      &DragX, &DragY, &JunkChild);
4040bbfda8aSnia			continue;
4050bbfda8aSnia		}
4060bbfda8aSnia
4070bbfda8aSnia		if(!DispatchEvent2()) {
4080bbfda8aSnia			continue;
4090bbfda8aSnia		}
4100bbfda8aSnia
4110bbfda8aSnia		if(Cancel) {
4120bbfda8aSnia			WindowMoved = false;
4130bbfda8aSnia			if(!Scr->OpaqueMove) {
4140bbfda8aSnia				UninstallRootColormap();
4150bbfda8aSnia			}
4160bbfda8aSnia			func_reset_cursor = false;  // Leave cursor alone
4170bbfda8aSnia			return;
4180bbfda8aSnia		}
4190bbfda8aSnia		if(Event.type == releaseEvent) {
4200bbfda8aSnia			MoveOutline(dragroot, 0, 0, 0, 0, 0, 0);
4210bbfda8aSnia			if(moving_icon &&
4220bbfda8aSnia			                ((CurrentDragX != origDragX ||
4230bbfda8aSnia			                  CurrentDragY != origDragY))) {
4240bbfda8aSnia				tmp_win->icon_moved = true;
4250bbfda8aSnia			}
4260bbfda8aSnia			if(!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar) {
4270bbfda8aSnia				int xl = Event.xbutton.x_root - (DragWidth  / 2),
4280bbfda8aSnia				    yt = Event.xbutton.y_root - (DragHeight / 2);
4290bbfda8aSnia				if(!moving_icon &&
4300bbfda8aSnia				                (MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH)) {
4310bbfda8aSnia					TryToPack(tmp_win, &xl, &yt);
4320bbfda8aSnia				}
4330bbfda8aSnia				XMoveWindow(dpy, DragWindow, xl, yt);
4340bbfda8aSnia			}
4350bbfda8aSnia			if(menuFromFrameOrWindowOrTitlebar) {
4360bbfda8aSnia				DragWindow = None;
4370bbfda8aSnia			}
4380bbfda8aSnia			break;
4390bbfda8aSnia		}
4400bbfda8aSnia
4410bbfda8aSnia		/* something left to do only if the pointer moved */
4420bbfda8aSnia		if(Event.type != MotionNotify) {
4430bbfda8aSnia			continue;
4440bbfda8aSnia		}
4450bbfda8aSnia
4460bbfda8aSnia		/* Get info about where the pointer is */
4470bbfda8aSnia		XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
4480bbfda8aSnia		              &(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
4490bbfda8aSnia		              &JunkX, &JunkY, &JunkMask);
4500bbfda8aSnia
4510bbfda8aSnia		/*
4520bbfda8aSnia		 * Tweak up for root.  XXX Is this even right?  There are too
4530bbfda8aSnia		 * many Root's, and this corrects for a specific one, but I'm not
4540bbfda8aSnia		 * sure it's the right one...
4550bbfda8aSnia		 */
4560bbfda8aSnia		FixRootEvent(eventp);
4570bbfda8aSnia
4580bbfda8aSnia		/* Tweak for window box, if this is in one */
459b18c2d1eSnia#ifdef WINBOX
4600bbfda8aSnia		if(tmp_win->winbox) {
4610bbfda8aSnia			XTranslateCoordinates(dpy, dragroot, tmp_win->winbox->window,
4620bbfda8aSnia			                      eventp->xmotion.x_root, eventp->xmotion.y_root,
4630bbfda8aSnia			                      &(eventp->xmotion.x_root), &(eventp->xmotion.y_root), &JunkChild);
4640bbfda8aSnia		}
465b18c2d1eSnia#endif
4660bbfda8aSnia
4670bbfda8aSnia		/*
4680bbfda8aSnia		 * If we haven't moved MoveDelta yet, we're not yet sure we're
4690bbfda8aSnia		 * doing anything, so just loop back around.
4700bbfda8aSnia		 */
4710bbfda8aSnia		if(DragWindow == None &&
4720bbfda8aSnia		                abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
4730bbfda8aSnia		                abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta) {
4740bbfda8aSnia			continue;
4750bbfda8aSnia		}
4760bbfda8aSnia
4770bbfda8aSnia		/*
4780bbfda8aSnia		 * Now we know we're moving whatever the window is.
4790bbfda8aSnia		 */
4800bbfda8aSnia		DragWindow = w;
4810bbfda8aSnia
4820bbfda8aSnia		/* Raise when the move starts if we should */
4830bbfda8aSnia		if(!Scr->NoRaiseMove && Scr->OpaqueMove && !WindowMoved) {
4840bbfda8aSnia			TwmWindow *t;
4850bbfda8aSnia
4860bbfda8aSnia			/*
4870bbfda8aSnia			 * XXX In several of the error cases listed in here, it's
4880bbfda8aSnia			 * seems almost that we should just abort the whole move
4890bbfda8aSnia			 * process immediately if any of them are hit, because things
4900bbfda8aSnia			 * get nonsensical.
4910bbfda8aSnia			 */
4920bbfda8aSnia
4930bbfda8aSnia			/* Find TwmWindow bits related to what we're dragging */
4940bbfda8aSnia			if(XFindContext(dpy, DragWindow, TwmContext, (XPointer *) &t) == XCNOENT) {
4950bbfda8aSnia				fprintf(stderr, "%s(): Can't find TwmWindow.\n", __func__);
4960bbfda8aSnia				/* XXX abort? */
4970bbfda8aSnia				t = NULL;
4980bbfda8aSnia			}
4990bbfda8aSnia
5000bbfda8aSnia			if(t != tmp_win) {
5010bbfda8aSnia				fprintf(stderr, "%s(): DragWindow isn't tmp_win!\n", __func__);
5020bbfda8aSnia				/* XXX abort? */
5030bbfda8aSnia			}
5040bbfda8aSnia
5050bbfda8aSnia			if(t == NULL) {
5060bbfda8aSnia				/* Don't try doing this stuff... */
5070bbfda8aSnia			}
5080bbfda8aSnia			else if(DragWindow == t->frame) {
5090bbfda8aSnia				if(moving_icon) {
5100bbfda8aSnia					fprintf(stderr, "%s(): moving_icon is true incorrectly!\n",
5110bbfda8aSnia					        __func__);
5120bbfda8aSnia				}
5130bbfda8aSnia				OtpRaise(t, WinWin);
5140bbfda8aSnia			}
5150bbfda8aSnia			else if(t->icon && DragWindow == t->icon->w) {
5160bbfda8aSnia				if(!moving_icon) {
5170bbfda8aSnia					fprintf(stderr, "%s(): moving_icon is false incorrectly!\n",
5180bbfda8aSnia					        __func__);
5190bbfda8aSnia				}
5200bbfda8aSnia				OtpRaise(t, IconWin);
5210bbfda8aSnia			}
5220bbfda8aSnia			else {
5230bbfda8aSnia				fprintf(stderr, "%s(): Couldn't figure what to raise.\n",
5240bbfda8aSnia				        __func__);
5250bbfda8aSnia			}
5260bbfda8aSnia		}
5270bbfda8aSnia
5280bbfda8aSnia		WindowMoved = true;
5290bbfda8aSnia
5300bbfda8aSnia		/*
5310bbfda8aSnia		 * Handle moving the step
5320bbfda8aSnia		 */
5330bbfda8aSnia		if(ConstMove) {
5340bbfda8aSnia			/* Did we already decide it's constrained?  Do that. */
5350bbfda8aSnia			switch(ConstMoveDir) {
5360bbfda8aSnia				case MOVE_NONE: {
5370bbfda8aSnia					/* Haven't figured direction yet, so do so */
5380bbfda8aSnia					if(eventp->xmotion.x_root < ConstMoveXL ||
5390bbfda8aSnia					                eventp->xmotion.x_root > ConstMoveXR) {
5400bbfda8aSnia						ConstMoveDir = MOVE_HORIZ;
5410bbfda8aSnia					}
5420bbfda8aSnia
5430bbfda8aSnia					if(eventp->xmotion.y_root < ConstMoveYT ||
5440bbfda8aSnia					                eventp->xmotion.y_root > ConstMoveYB) {
5450bbfda8aSnia						ConstMoveDir = MOVE_VERT;
5460bbfda8aSnia					}
5470bbfda8aSnia
5480bbfda8aSnia					XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild,
5490bbfda8aSnia					              &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
5500bbfda8aSnia					break;
5510bbfda8aSnia				}
5520bbfda8aSnia
5530bbfda8aSnia				/* We know which dir it's contrained to, so figure amount */
5540bbfda8aSnia				case MOVE_VERT:
5550bbfda8aSnia					ConstMoveY = eventp->xmotion.y_root - DragY - DragBW;
5560bbfda8aSnia					break;
5570bbfda8aSnia
5580bbfda8aSnia				case MOVE_HORIZ:
5590bbfda8aSnia					ConstMoveX = eventp->xmotion.x_root - DragX - DragBW;
5600bbfda8aSnia					break;
5610bbfda8aSnia			}
5620bbfda8aSnia
5630bbfda8aSnia			/* We've got a move to do, so do it */
5640bbfda8aSnia			if(ConstMoveDir != MOVE_NONE) {
5650bbfda8aSnia				int xl, yt, width, height;
5660bbfda8aSnia
5670bbfda8aSnia				xl = ConstMoveX;
5680bbfda8aSnia				yt = ConstMoveY;
5690bbfda8aSnia				width = DragWidth + 2 * DragBW;
5700bbfda8aSnia				height = DragHeight + 2 * DragBW;
5710bbfda8aSnia
5720bbfda8aSnia				if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
5730bbfda8aSnia					TryToGrid(tmp_win, &xl, &yt);
5740bbfda8aSnia				}
5750bbfda8aSnia				if(!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove) {
5760bbfda8aSnia					TryToPush(tmp_win, xl, yt);
5770bbfda8aSnia				}
5780bbfda8aSnia
5790bbfda8aSnia				if(!moving_icon &&
5800bbfda8aSnia				                (MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH)) {
5810bbfda8aSnia					TryToPack(tmp_win, &xl, &yt);
5820bbfda8aSnia				}
5830bbfda8aSnia
5840bbfda8aSnia				if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
5850bbfda8aSnia					ConstrainByBorders(tmp_win, &xl, width, &yt, height);
5860bbfda8aSnia				}
5870bbfda8aSnia				CurrentDragX = xl;
5880bbfda8aSnia				CurrentDragY = yt;
5890bbfda8aSnia				if(Scr->OpaqueMove) {
5900bbfda8aSnia					if(MoveFunction == F_MOVEPUSH && !moving_icon) {
5910bbfda8aSnia						SetupWindow(tmp_win, xl, yt,
5920bbfda8aSnia						            tmp_win->frame_width, tmp_win->frame_height, -1);
5930bbfda8aSnia					}
5940bbfda8aSnia					else {
5950bbfda8aSnia						XMoveWindow(dpy, DragWindow, xl, yt);
5960bbfda8aSnia						if(moving_icon) {
5970bbfda8aSnia							tmp_win->icon->w_x = xl;
5980bbfda8aSnia							tmp_win->icon->w_y = yt;
5990bbfda8aSnia						}
6000bbfda8aSnia					}
6010bbfda8aSnia					WMapSetupWindow(tmp_win, xl, yt, -1, -1);
6020bbfda8aSnia				}
6030bbfda8aSnia				else {
6040bbfda8aSnia					MoveOutline(dragroot, xl + Scr->currentvs->x,
6050bbfda8aSnia					            yt + Scr->currentvs->y, width, height,
6060bbfda8aSnia					            tmp_win->frame_bw,
6070bbfda8aSnia					            moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
6080bbfda8aSnia				}
6090bbfda8aSnia			}
6100bbfda8aSnia		}
6110bbfda8aSnia		else if(DragWindow != None) {
6120bbfda8aSnia			/*
6130bbfda8aSnia			 * There's a non-constrained move to process
6140bbfda8aSnia			 *
6150bbfda8aSnia			 * This is split out for virtual screens.  In that case, it's
6160bbfda8aSnia			 * possible to drag windows from one workspace to another, and
6170bbfda8aSnia			 * as such, these need to be adjusted to the root, rather
6180bbfda8aSnia			 * than this virtual screen...
6190bbfda8aSnia			 */
6200bbfda8aSnia			const int xroot = eventp->xmotion.x_root;
6210bbfda8aSnia			const int yroot = eventp->xmotion.y_root;
6220bbfda8aSnia			const int width  = DragWidth + 2 * DragBW;
6230bbfda8aSnia			const int height = DragHeight + 2 * DragBW;
6240bbfda8aSnia			int xl, yt;
6250bbfda8aSnia
6260bbfda8aSnia			if(!menuFromFrameOrWindowOrTitlebar) {
6270bbfda8aSnia				xl = xroot - DragX - DragBW;
6280bbfda8aSnia				yt = yroot - DragY - DragBW;
6290bbfda8aSnia			}
6300bbfda8aSnia			else {
6310bbfda8aSnia				xl = xroot - (DragWidth / 2);
6320bbfda8aSnia				yt = yroot - (DragHeight / 2);
6330bbfda8aSnia			}
6340bbfda8aSnia
6350bbfda8aSnia			if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
6360bbfda8aSnia				TryToGrid(tmp_win, &xl, &yt);
6370bbfda8aSnia			}
6380bbfda8aSnia			if(!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove) {
6390bbfda8aSnia				TryToPush(tmp_win, xl, yt);
6400bbfda8aSnia			}
6410bbfda8aSnia
6420bbfda8aSnia			if(!moving_icon &&
6430bbfda8aSnia			                (MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH)) {
6440bbfda8aSnia				TryToPack(tmp_win, &xl, &yt);
6450bbfda8aSnia			}
6460bbfda8aSnia
6470bbfda8aSnia			if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
6480bbfda8aSnia				ConstrainByBorders(tmp_win, &xl, width, &yt, height);
6490bbfda8aSnia			}
6500bbfda8aSnia
6510bbfda8aSnia			CurrentDragX = xl;
6520bbfda8aSnia			CurrentDragY = yt;
6530bbfda8aSnia			if(Scr->OpaqueMove) {
6540bbfda8aSnia				if(MoveFunction == F_MOVEPUSH && !moving_icon) {
6550bbfda8aSnia					SetupWindow(tmp_win, xl, yt,
6560bbfda8aSnia					            tmp_win->frame_width, tmp_win->frame_height, -1);
6570bbfda8aSnia				}
6580bbfda8aSnia				else {
6590bbfda8aSnia					XMoveWindow(dpy, DragWindow, xl, yt);
6600bbfda8aSnia					if(moving_icon) {
6610bbfda8aSnia						tmp_win->icon->w_x = xl;
6620bbfda8aSnia						tmp_win->icon->w_y = yt;
6630bbfda8aSnia					}
6640bbfda8aSnia				}
6650bbfda8aSnia				if(! moving_icon) {
6660bbfda8aSnia					WMapSetupWindow(tmp_win, xl, yt, -1, -1);
6670bbfda8aSnia				}
6680bbfda8aSnia			}
6690bbfda8aSnia			else {
6700bbfda8aSnia				MoveOutline(dragroot, xl + Scr->currentvs->x,
6710bbfda8aSnia				            yt + Scr->currentvs->y, width, height,
6720bbfda8aSnia				            tmp_win->frame_bw,
6730bbfda8aSnia				            moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
6740bbfda8aSnia			}
6750bbfda8aSnia		}
6760bbfda8aSnia
6770bbfda8aSnia		/* We've moved a step, so update the displayed position */
6780bbfda8aSnia		DisplayPosition(tmp_win, CurrentDragX, CurrentDragY);
6790bbfda8aSnia	}
6800bbfda8aSnia
6810bbfda8aSnia	/* Done, so hide away the position display window */
6820bbfda8aSnia	XUnmapWindow(dpy, Scr->SizeWindow);
6830bbfda8aSnia
6840bbfda8aSnia	/* Restore colormap if we replaced it */
6850bbfda8aSnia	if(!Scr->OpaqueMove && DragWindow == None) {
6860bbfda8aSnia		UninstallRootColormap();
6870bbfda8aSnia	}
6880bbfda8aSnia
6890bbfda8aSnia	return;
6900bbfda8aSnia}
6910bbfda8aSnia
6920bbfda8aSnia
6930bbfda8aSnia/*
6940bbfda8aSnia * f.pack -- moving until collision
6950bbfda8aSnia *
6960bbfda8aSnia * XXX Collapse this down; no need for an extra level of indirection on
6970bbfda8aSnia * the function calling.
6980bbfda8aSnia */
6990bbfda8aSniastatic void packwindow(TwmWindow *tmp_win, const char *direction);
7000bbfda8aSniaDFHANDLER(pack)
7010bbfda8aSnia{
7020bbfda8aSnia	if(tmp_win->squeezed) {
7030bbfda8aSnia		XBell(dpy, 0);
7040bbfda8aSnia		return;
7050bbfda8aSnia	}
7060bbfda8aSnia	packwindow(tmp_win, action);
7070bbfda8aSnia}
7080bbfda8aSnia
7090bbfda8aSniastatic void
7100bbfda8aSniapackwindow(TwmWindow *tmp_win, const char *direction)
7110bbfda8aSnia{
7120bbfda8aSnia	int          cons, newx, newy;
7130bbfda8aSnia	int          x, y, px, py, junkX, junkY;
7140bbfda8aSnia	unsigned int junkK;
7150bbfda8aSnia	Window       junkW;
7160bbfda8aSnia
7170bbfda8aSnia	if(!strcmp(direction,   "left")) {
7180bbfda8aSnia		cons  = FindConstraint(tmp_win, MFD_LEFT);
7190bbfda8aSnia		if(cons == -1) {
7200bbfda8aSnia			return;
7210bbfda8aSnia		}
7220bbfda8aSnia		newx  = cons;
7230bbfda8aSnia		newy  = tmp_win->frame_y;
7240bbfda8aSnia	}
7250bbfda8aSnia	else if(!strcmp(direction,  "right")) {
7260bbfda8aSnia		cons  = FindConstraint(tmp_win, MFD_RIGHT);
7270bbfda8aSnia		if(cons == -1) {
7280bbfda8aSnia			return;
7290bbfda8aSnia		}
7300bbfda8aSnia		newx  = cons;
7310bbfda8aSnia		newx -= tmp_win->frame_width + 2 * tmp_win->frame_bw;
7320bbfda8aSnia		newy  = tmp_win->frame_y;
7330bbfda8aSnia	}
7340bbfda8aSnia	else if(!strcmp(direction,    "top")) {
7350bbfda8aSnia		cons  = FindConstraint(tmp_win, MFD_TOP);
7360bbfda8aSnia		if(cons == -1) {
7370bbfda8aSnia			return;
7380bbfda8aSnia		}
7390bbfda8aSnia		newx  = tmp_win->frame_x;
7400bbfda8aSnia		newy  = cons;
7410bbfda8aSnia	}
7420bbfda8aSnia	else if(!strcmp(direction, "bottom")) {
7430bbfda8aSnia		cons  = FindConstraint(tmp_win, MFD_BOTTOM);
7440bbfda8aSnia		if(cons == -1) {
7450bbfda8aSnia			return;
7460bbfda8aSnia		}
7470bbfda8aSnia		newx  = tmp_win->frame_x;
7480bbfda8aSnia		newy  = cons;
7490bbfda8aSnia		newy -= tmp_win->frame_height + 2 * tmp_win->frame_bw;
7500bbfda8aSnia	}
7510bbfda8aSnia	else {
7520bbfda8aSnia		return;
7530bbfda8aSnia	}
7540bbfda8aSnia
7550bbfda8aSnia	XQueryPointer(dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &x, &y, &junkK);
7560bbfda8aSnia	px = x - tmp_win->frame_x + newx;
7570bbfda8aSnia	py = y - tmp_win->frame_y + newy;
7580bbfda8aSnia	XWarpPointer(dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, px, py);
7590bbfda8aSnia	OtpRaise(tmp_win, WinWin);
7600bbfda8aSnia	XMoveWindow(dpy, tmp_win->frame, newx, newy);
7610bbfda8aSnia	SetupWindow(tmp_win, newx, newy, tmp_win->frame_width,
7620bbfda8aSnia	            tmp_win->frame_height, -1);
7630bbfda8aSnia}
7640bbfda8aSnia
7650bbfda8aSnia
7660bbfda8aSnia/*
7670bbfda8aSnia * f.jump* -- moving incrementally in various directions
7680bbfda8aSnia */
7690bbfda8aSniastatic void jump(TwmWindow *tmp_win, MoveFillDir direction, const char *action);
7700bbfda8aSniaDFHANDLER(jumpleft)
7710bbfda8aSnia{
7720bbfda8aSnia	jump(tmp_win, MFD_LEFT, action);
7730bbfda8aSnia}
7740bbfda8aSniaDFHANDLER(jumpright)
7750bbfda8aSnia{
7760bbfda8aSnia	jump(tmp_win, MFD_RIGHT, action);
7770bbfda8aSnia}
7780bbfda8aSniaDFHANDLER(jumpdown)
7790bbfda8aSnia{
7800bbfda8aSnia	jump(tmp_win, MFD_BOTTOM, action);
7810bbfda8aSnia}
7820bbfda8aSniaDFHANDLER(jumpup)
7830bbfda8aSnia{
7840bbfda8aSnia	jump(tmp_win, MFD_TOP, action);
7850bbfda8aSnia}
7860bbfda8aSnia
7870bbfda8aSniastatic void
7880bbfda8aSniajump(TwmWindow *tmp_win, MoveFillDir direction, const char *action)
7890bbfda8aSnia{
7900bbfda8aSnia	int          fx, fy, px, py, step, status, cons;
7910bbfda8aSnia	int          fwidth, fheight;
7920bbfda8aSnia	int          junkX, junkY;
7930bbfda8aSnia	unsigned int junkK;
7940bbfda8aSnia	Window       junkW;
7950bbfda8aSnia
7960bbfda8aSnia	if(tmp_win->squeezed) {
7970bbfda8aSnia		XBell(dpy, 0);
7980bbfda8aSnia		return;
7990bbfda8aSnia	}
8000bbfda8aSnia
8010bbfda8aSnia	if(! action) {
8020bbfda8aSnia		return;
8030bbfda8aSnia	}
8040bbfda8aSnia	status = sscanf(action, "%d", &step);
8050bbfda8aSnia	if(status != 1) {
8060bbfda8aSnia		return;
8070bbfda8aSnia	}
8080bbfda8aSnia	if(step < 1) {
8090bbfda8aSnia		return;
8100bbfda8aSnia	}
8110bbfda8aSnia
8120bbfda8aSnia	fx = tmp_win->frame_x;
8130bbfda8aSnia	fy = tmp_win->frame_y;
8140bbfda8aSnia	XQueryPointer(dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK);
8150bbfda8aSnia	px -= fx;
8160bbfda8aSnia	py -= fy;
8170bbfda8aSnia
8180bbfda8aSnia	fwidth  = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
8190bbfda8aSnia	fheight = tmp_win->frame_height + 2 * tmp_win->frame_bw;
8200bbfda8aSnia	switch(direction) {
8210bbfda8aSnia		case MFD_LEFT:
8220bbfda8aSnia			cons  = FindConstraint(tmp_win, MFD_LEFT);
8230bbfda8aSnia			if(cons == -1) {
8240bbfda8aSnia				return;
8250bbfda8aSnia			}
8260bbfda8aSnia			fx -= step * Scr->XMoveGrid;
8270bbfda8aSnia			if(fx < cons) {
8280bbfda8aSnia				fx = cons;
8290bbfda8aSnia			}
8300bbfda8aSnia			break;
8310bbfda8aSnia		case MFD_RIGHT:
8320bbfda8aSnia			cons  = FindConstraint(tmp_win, MFD_RIGHT);
8330bbfda8aSnia			if(cons == -1) {
8340bbfda8aSnia				return;
8350bbfda8aSnia			}
8360bbfda8aSnia			fx += step * Scr->XMoveGrid;
8370bbfda8aSnia			if(fx + fwidth > cons) {
8380bbfda8aSnia				fx = cons - fwidth;
8390bbfda8aSnia			}
8400bbfda8aSnia			break;
8410bbfda8aSnia		case MFD_TOP:
8420bbfda8aSnia			cons  = FindConstraint(tmp_win, MFD_TOP);
8430bbfda8aSnia			if(cons == -1) {
8440bbfda8aSnia				return;
8450bbfda8aSnia			}
8460bbfda8aSnia			fy -= step * Scr->YMoveGrid;
8470bbfda8aSnia			if(fy < cons) {
8480bbfda8aSnia				fy = cons;
8490bbfda8aSnia			}
8500bbfda8aSnia			break;
8510bbfda8aSnia		case MFD_BOTTOM:
8520bbfda8aSnia			cons  = FindConstraint(tmp_win, MFD_BOTTOM);
8530bbfda8aSnia			if(cons == -1) {
8540bbfda8aSnia				return;
8550bbfda8aSnia			}
8560bbfda8aSnia			fy += step * Scr->YMoveGrid;
8570bbfda8aSnia			if(fy + fheight > cons) {
8580bbfda8aSnia				fy = cons - fheight;
8590bbfda8aSnia			}
8600bbfda8aSnia			break;
8610bbfda8aSnia	}
8620bbfda8aSnia	/* Pebl Fixme: don't warp if jump happens through iconmgr */
8630bbfda8aSnia	XWarpPointer(dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, fx + px, fy + py);
8640bbfda8aSnia	if(!Scr->NoRaiseMove) {
8650bbfda8aSnia		OtpRaise(tmp_win, WinWin);
8660bbfda8aSnia	}
8670bbfda8aSnia	SetupWindow(tmp_win, fx, fy, tmp_win->frame_width, tmp_win->frame_height, -1);
8680bbfda8aSnia}
8690bbfda8aSnia
8700bbfda8aSnia
8710bbfda8aSnia
8720bbfda8aSnia/*
8730bbfda8aSnia *********************************************************
8740bbfda8aSnia *
8750bbfda8aSnia * Next up, straightforward resizing operations
8760bbfda8aSnia *
8770bbfda8aSnia *********************************************************
8780bbfda8aSnia */
8790bbfda8aSnia
8800bbfda8aSnia/*
8810bbfda8aSnia * Standard f.resize
8820bbfda8aSnia */
8830bbfda8aSniaDFHANDLER(resize)
8840bbfda8aSnia{
8850bbfda8aSnia	PopDownMenu();
8860bbfda8aSnia	if(tmp_win->squeezed) {
8870bbfda8aSnia		XBell(dpy, 0);
8880bbfda8aSnia		return;
8890bbfda8aSnia	}
8900bbfda8aSnia	EventHandler[EnterNotify] = HandleUnknown;
8910bbfda8aSnia	EventHandler[LeaveNotify] = HandleUnknown;
8920bbfda8aSnia
8930bbfda8aSnia	OpaqueResizeSize(tmp_win);
8940bbfda8aSnia
8950bbfda8aSnia	if(pulldown)
8960bbfda8aSnia		XWarpPointer(dpy, None, Scr->Root,
8970bbfda8aSnia		             0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
8980bbfda8aSnia
8990bbfda8aSnia	if(!tmp_win->icon || (w != tmp_win->icon->w)) {         /* can't resize icons */
9000bbfda8aSnia
9010bbfda8aSnia		/*        fromMenu = False;  ????? */
9020bbfda8aSnia		if((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE
9030bbfda8aSnia		                || Context == C_ROOT)
9040bbfda8aSnia		                && cur_fromMenu()) {
9050bbfda8aSnia			resizeFromCenter(w, tmp_win);
9060bbfda8aSnia		}
9070bbfda8aSnia		else {
9080bbfda8aSnia			/*
9090bbfda8aSnia			 * see if this is being done from the titlebar
9100bbfda8aSnia			 */
9110bbfda8aSnia			bool from3dborder = (eventp->xbutton.window == tmp_win->frame);
9120bbfda8aSnia			bool fromtitlebar = !from3dborder &&
9130bbfda8aSnia			                    belongs_to_twm_window(tmp_win, eventp->xbutton.window);
9140bbfda8aSnia
9150bbfda8aSnia			/* Save pointer position so we can tell if it was moved or
9160bbfda8aSnia			   not during the resize. */
9170bbfda8aSnia			ResizeOrigX = eventp->xbutton.x_root;
9180bbfda8aSnia			ResizeOrigY = eventp->xbutton.y_root;
9190bbfda8aSnia
9200bbfda8aSnia			StartResize(eventp, tmp_win, fromtitlebar, from3dborder);
9210bbfda8aSnia			func_reset_cursor = false;  // Leave special cursor alone
9220bbfda8aSnia
9230bbfda8aSnia			do {
9240bbfda8aSnia				XMaskEvent(dpy,
9250bbfda8aSnia				           ButtonPressMask | ButtonReleaseMask |
9260bbfda8aSnia				           EnterWindowMask | LeaveWindowMask |
9270bbfda8aSnia				           ButtonMotionMask | VisibilityChangeMask | ExposureMask, &Event);
9280bbfda8aSnia
9290bbfda8aSnia				if(fromtitlebar && Event.type == ButtonPress) {
9300bbfda8aSnia					fromtitlebar = false;
9310bbfda8aSnia					continue;
9320bbfda8aSnia				}
9330bbfda8aSnia
9340bbfda8aSnia				if(Event.type == MotionNotify) {
9350bbfda8aSnia					/* discard any extra motion events before a release */
9360bbfda8aSnia					while
9370bbfda8aSnia					(XCheckMaskEvent
9380bbfda8aSnia					                (dpy, ButtonMotionMask | ButtonReleaseMask, &Event))
9390bbfda8aSnia						if(Event.type == ButtonRelease) {
9400bbfda8aSnia							break;
9410bbfda8aSnia						}
9420bbfda8aSnia				}
9430bbfda8aSnia
9440bbfda8aSnia				if(!DispatchEvent2()) {
9450bbfda8aSnia					continue;
9460bbfda8aSnia				}
9470bbfda8aSnia
9480bbfda8aSnia			}
9490bbfda8aSnia			while(!(Event.type == ButtonRelease || Cancel));
9500bbfda8aSnia		}
9510bbfda8aSnia	}
9520bbfda8aSnia	return;
9530bbfda8aSnia}
9540bbfda8aSnia
9550bbfda8aSnia
9560bbfda8aSnia/*
9570bbfda8aSnia * The various zoom resizes
9580bbfda8aSnia */
9590bbfda8aSniaDFHANDLER(zoom)
9600bbfda8aSnia{
9610bbfda8aSnia	fullzoom(tmp_win, func);
9620bbfda8aSnia}
9630bbfda8aSniaDFHANDLER(horizoom)
9640bbfda8aSnia{
9650bbfda8aSnia	fullzoom(tmp_win, func);
9660bbfda8aSnia}
9670bbfda8aSniaDFHANDLER(fullzoom)
9680bbfda8aSnia{
9690bbfda8aSnia	fullzoom(tmp_win, func);
9700bbfda8aSnia}
9710bbfda8aSniaDFHANDLER(fullscreenzoom)
9720bbfda8aSnia{
9730bbfda8aSnia	fullzoom(tmp_win, func);
9740bbfda8aSnia}
9750bbfda8aSniaDFHANDLER(leftzoom)
9760bbfda8aSnia{
9770bbfda8aSnia	fullzoom(tmp_win, func);
9780bbfda8aSnia}
9790bbfda8aSniaDFHANDLER(rightzoom)
9800bbfda8aSnia{
9810bbfda8aSnia	fullzoom(tmp_win, func);
9820bbfda8aSnia}
9830bbfda8aSniaDFHANDLER(topzoom)
9840bbfda8aSnia{
9850bbfda8aSnia	fullzoom(tmp_win, func);
9860bbfda8aSnia}
9870bbfda8aSniaDFHANDLER(bottomzoom)
9880bbfda8aSnia{
9890bbfda8aSnia	fullzoom(tmp_win, func);
9900bbfda8aSnia}
9910bbfda8aSnia
992b18c2d1eSniaDFHANDLER(xzoom)
993b18c2d1eSnia{
994b18c2d1eSnia	fullzoom(tmp_win, func);
995b18c2d1eSnia}
996b18c2d1eSniaDFHANDLER(xhorizoom)
997b18c2d1eSnia{
998b18c2d1eSnia	fullzoom(tmp_win, func);
999b18c2d1eSnia}
1000b18c2d1eSniaDFHANDLER(xfullzoom)
1001b18c2d1eSnia{
1002b18c2d1eSnia	fullzoom(tmp_win, func);
1003b18c2d1eSnia}
1004b18c2d1eSniaDFHANDLER(xfullscreenzoom)
1005b18c2d1eSnia{
1006b18c2d1eSnia	fullzoom(tmp_win, func);
1007b18c2d1eSnia}
1008b18c2d1eSniaDFHANDLER(xleftzoom)
1009b18c2d1eSnia{
1010b18c2d1eSnia	fullzoom(tmp_win, func);
1011b18c2d1eSnia}
1012b18c2d1eSniaDFHANDLER(xrightzoom)
1013b18c2d1eSnia{
1014b18c2d1eSnia	fullzoom(tmp_win, func);
1015b18c2d1eSnia}
1016b18c2d1eSniaDFHANDLER(xtopzoom)
1017b18c2d1eSnia{
1018b18c2d1eSnia	fullzoom(tmp_win, func);
1019b18c2d1eSnia}
1020b18c2d1eSniaDFHANDLER(xbottomzoom)
1021b18c2d1eSnia{
1022b18c2d1eSnia	fullzoom(tmp_win, func);
1023b18c2d1eSnia}
1024b18c2d1eSnia
10250bbfda8aSnia
10260bbfda8aSnia/*
10270bbfda8aSnia * f.fill - resizing until collision
10280bbfda8aSnia *
10290bbfda8aSnia * XXX Similar to f.pack's, collapse away this extra level of function.
10300bbfda8aSnia */
10310bbfda8aSniastatic void fillwindow(TwmWindow *tmp_win, const char *direction);
10320bbfda8aSniaDFHANDLER(fill)
10330bbfda8aSnia{
10340bbfda8aSnia	if(tmp_win->squeezed) {
10350bbfda8aSnia		XBell(dpy, 0);
10360bbfda8aSnia		return;
10370bbfda8aSnia	}
10380bbfda8aSnia	fillwindow(tmp_win, action);
10390bbfda8aSnia}
10400bbfda8aSnia
10410bbfda8aSniastatic void
10420bbfda8aSniafillwindow(TwmWindow *tmp_win, const char *direction)
10430bbfda8aSnia{
10440bbfda8aSnia	int cons, newx, newy, save;
10450bbfda8aSnia	unsigned int neww, newh;
10460bbfda8aSnia	int i;
10470bbfda8aSnia	const int winx = tmp_win->frame_x;
10480bbfda8aSnia	const int winy = tmp_win->frame_y;
10490bbfda8aSnia	const int winw = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
10500bbfda8aSnia	const int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
10510bbfda8aSnia
10520bbfda8aSnia	if(!strcmp(direction, "left")) {
10530bbfda8aSnia		cons = FindConstraint(tmp_win, MFD_LEFT);
10540bbfda8aSnia		if(cons == -1) {
10550bbfda8aSnia			return;
10560bbfda8aSnia		}
10570bbfda8aSnia		newx = cons;
10580bbfda8aSnia		newy = tmp_win->frame_y;
10590bbfda8aSnia		neww = winw + winx - newx;
10600bbfda8aSnia		newh = winh;
10610bbfda8aSnia		neww -= 2 * tmp_win->frame_bw;
10620bbfda8aSnia		newh -= 2 * tmp_win->frame_bw;
10630bbfda8aSnia		ConstrainSize(tmp_win, &neww, &newh);
10640bbfda8aSnia	}
10650bbfda8aSnia	else if(!strcmp(direction, "right")) {
10660bbfda8aSnia		for(i = 0; i < 2; i++) {
10670bbfda8aSnia			cons = FindConstraint(tmp_win, MFD_RIGHT);
10680bbfda8aSnia			if(cons == -1) {
10690bbfda8aSnia				return;
10700bbfda8aSnia			}
10710bbfda8aSnia			newx = tmp_win->frame_x;
10720bbfda8aSnia			newy = tmp_win->frame_y;
10730bbfda8aSnia			neww = cons - winx;
10740bbfda8aSnia			newh = winh;
10750bbfda8aSnia			save = neww;
10760bbfda8aSnia			neww -= 2 * tmp_win->frame_bw;
10770bbfda8aSnia			newh -= 2 * tmp_win->frame_bw;
10780bbfda8aSnia			ConstrainSize(tmp_win, &neww, &newh);
10790bbfda8aSnia			if((neww != winw) || (newh != winh) ||
10800bbfda8aSnia			                (cons == Scr->rootw - Scr->BorderRight)) {
10810bbfda8aSnia				break;
10820bbfda8aSnia			}
10830bbfda8aSnia			neww = save;
10840bbfda8aSnia			SetupWindow(tmp_win, newx, newy, neww, newh, -1);
10850bbfda8aSnia		}
10860bbfda8aSnia	}
10870bbfda8aSnia	else if(!strcmp(direction, "top")) {
10880bbfda8aSnia		cons = FindConstraint(tmp_win, MFD_TOP);
10890bbfda8aSnia		if(cons == -1) {
10900bbfda8aSnia			return;
10910bbfda8aSnia		}
10920bbfda8aSnia		newx = tmp_win->frame_x;
10930bbfda8aSnia		newy = cons;
10940bbfda8aSnia		neww = winw;
10950bbfda8aSnia		newh = winh + winy - newy;
10960bbfda8aSnia		neww -= 2 * tmp_win->frame_bw;
10970bbfda8aSnia		newh -= 2 * tmp_win->frame_bw;
10980bbfda8aSnia		ConstrainSize(tmp_win, &neww, &newh);
10990bbfda8aSnia	}
11000bbfda8aSnia	else if(!strcmp(direction, "bottom")) {
11010bbfda8aSnia		for(i = 0; i < 2; i++) {
11020bbfda8aSnia			cons = FindConstraint(tmp_win, MFD_BOTTOM);
11030bbfda8aSnia			if(cons == -1) {
11040bbfda8aSnia				return;
11050bbfda8aSnia			}
11060bbfda8aSnia			newx = tmp_win->frame_x;
11070bbfda8aSnia			newy = tmp_win->frame_y;
11080bbfda8aSnia			neww = winw;
11090bbfda8aSnia			newh = cons - winy;
11100bbfda8aSnia			save = newh;
11110bbfda8aSnia			neww -= 2 * tmp_win->frame_bw;
11120bbfda8aSnia			newh -= 2 * tmp_win->frame_bw;
11130bbfda8aSnia			ConstrainSize(tmp_win, &neww, &newh);
11140bbfda8aSnia			if((neww != winw) || (newh != winh) ||
11150bbfda8aSnia			                (cons == Scr->rooth - Scr->BorderBottom)) {
11160bbfda8aSnia				break;
11170bbfda8aSnia			}
11180bbfda8aSnia			newh = save;
11190bbfda8aSnia			SetupWindow(tmp_win, newx, newy, neww, newh, -1);
11200bbfda8aSnia		}
11210bbfda8aSnia	}
11220bbfda8aSnia	else if(!strcmp(direction, "vertical")) {
11230bbfda8aSnia		if(tmp_win->zoomed == ZOOM_NONE) {
11240bbfda8aSnia			tmp_win->save_frame_height = tmp_win->frame_height;
11250bbfda8aSnia			tmp_win->save_frame_width = tmp_win->frame_width;
11260bbfda8aSnia			tmp_win->save_frame_y = tmp_win->frame_y;
11270bbfda8aSnia			tmp_win->save_frame_x = tmp_win->frame_x;
11280bbfda8aSnia
11290bbfda8aSnia			tmp_win->frame_y++;
11300bbfda8aSnia			newy = FindConstraint(tmp_win, MFD_TOP);
11310bbfda8aSnia			tmp_win->frame_y--;
11320bbfda8aSnia			newh = FindConstraint(tmp_win, MFD_BOTTOM) - newy;
11330bbfda8aSnia			newh -= 2 * tmp_win->frame_bw;
11340bbfda8aSnia
11350bbfda8aSnia			newx = tmp_win->frame_x;
11360bbfda8aSnia			neww = tmp_win->frame_width;
11370bbfda8aSnia
11380bbfda8aSnia			ConstrainSize(tmp_win, &neww, &newh);
11390bbfda8aSnia
11400bbfda8aSnia			/* if the bottom of the window has moved up
11410bbfda8aSnia			 * it will be pushed down */
11420bbfda8aSnia			if(newy + newh < tmp_win->save_frame_y + tmp_win->save_frame_height) {
11430bbfda8aSnia				newy = tmp_win->save_frame_y +
11440bbfda8aSnia				       tmp_win->save_frame_height - newh;
11450bbfda8aSnia			}
11460bbfda8aSnia			tmp_win->zoomed = F_ZOOM;
11470bbfda8aSnia			SetupWindow(tmp_win, newx, newy, neww, newh, -1);
11480bbfda8aSnia		}
11490bbfda8aSnia		else {
11500bbfda8aSnia			fullzoom(tmp_win, tmp_win->zoomed);
11510bbfda8aSnia		}
11520bbfda8aSnia		return;
11530bbfda8aSnia	}
11540bbfda8aSnia	else {
11550bbfda8aSnia		return;
11560bbfda8aSnia	}
11570bbfda8aSnia	SetupWindow(tmp_win, newx, newy, neww, newh, -1);
11580bbfda8aSnia}
11590bbfda8aSnia
11600bbfda8aSnia
11610bbfda8aSnia
11620bbfda8aSnia/*
11630bbfda8aSnia *********************************************************
11640bbfda8aSnia *
11650bbfda8aSnia * Resizing/moving to specified geometries
11660bbfda8aSnia *
11670bbfda8aSnia *********************************************************
11680bbfda8aSnia */
11690bbfda8aSnia
11700bbfda8aSnia/*
11710bbfda8aSnia * Resizing to a window's idea of its "normal" size, from WM_NORMAL_HINTS
11720bbfda8aSnia * property.
11730bbfda8aSnia */
11740bbfda8aSniaDFHANDLER(initsize)
11750bbfda8aSnia{
11760bbfda8aSnia	int grav, x, y;
11770bbfda8aSnia	unsigned int width, height, swidth, sheight;
11780bbfda8aSnia
11790bbfda8aSnia	grav = ((tmp_win->hints.flags & PWinGravity)
11800bbfda8aSnia	        ? tmp_win->hints.win_gravity : NorthWestGravity);
11810bbfda8aSnia
11820bbfda8aSnia	if(!(tmp_win->hints.flags & USSize) && !(tmp_win->hints.flags & PSize)) {
11830bbfda8aSnia		return;
11840bbfda8aSnia	}
11850bbfda8aSnia
11860bbfda8aSnia	width  = tmp_win->hints.width  + 2 * tmp_win->frame_bw3D;
11870bbfda8aSnia	height  = tmp_win->hints.height + 2 * tmp_win->frame_bw3D +
11880bbfda8aSnia	          tmp_win->title_height;
11890bbfda8aSnia	ConstrainSize(tmp_win, &width, &height);
11900bbfda8aSnia
11910bbfda8aSnia	x  = tmp_win->frame_x;
11920bbfda8aSnia	y  = tmp_win->frame_y;
11930bbfda8aSnia	swidth = tmp_win->frame_width;
11940bbfda8aSnia	sheight = tmp_win->frame_height;
11950bbfda8aSnia
11960bbfda8aSnia	switch(grav) {
11970bbfda8aSnia		case ForgetGravity:
11980bbfda8aSnia		case StaticGravity:
11990bbfda8aSnia		case NorthWestGravity:
12000bbfda8aSnia		case NorthGravity:
12010bbfda8aSnia		case WestGravity:
12020bbfda8aSnia		case CenterGravity:
12030bbfda8aSnia			break;
12040bbfda8aSnia
12050bbfda8aSnia		case NorthEastGravity:
12060bbfda8aSnia		case EastGravity:
12070bbfda8aSnia			x += swidth - width;
12080bbfda8aSnia			break;
12090bbfda8aSnia
12100bbfda8aSnia		case SouthWestGravity:
12110bbfda8aSnia		case SouthGravity:
12120bbfda8aSnia			y += sheight - height;
12130bbfda8aSnia			break;
12140bbfda8aSnia
12150bbfda8aSnia		case SouthEastGravity:
12160bbfda8aSnia			x += swidth - width;
12170bbfda8aSnia			y += sheight - height;
12180bbfda8aSnia			break;
12190bbfda8aSnia	}
12200bbfda8aSnia
12210bbfda8aSnia	SetupWindow(tmp_win, x, y, width, height, -1);
12220bbfda8aSnia	return;
12230bbfda8aSnia}
12240bbfda8aSnia
12250bbfda8aSnia
12260bbfda8aSnia/*
12270bbfda8aSnia * Setting a window to a specific specified geometry string.
12280bbfda8aSnia */
12290bbfda8aSniaDFHANDLER(moveresize)
12300bbfda8aSnia{
12310bbfda8aSnia	int x, y, mask;
12320bbfda8aSnia	unsigned int width, height;
12330bbfda8aSnia	int px = 20, py = 30;
12340bbfda8aSnia
1235b18c2d1eSnia	mask = RLayoutXParseGeometry(Scr->Layout, action, &x, &y, &width, &height);
12360bbfda8aSnia	if(!(mask &  WidthValue)) {
12370bbfda8aSnia		width = tmp_win->frame_width;
12380bbfda8aSnia	}
12390bbfda8aSnia	else {
12400bbfda8aSnia		width += 2 * tmp_win->frame_bw3D;
12410bbfda8aSnia	}
12420bbfda8aSnia	if(!(mask & HeightValue)) {
12430bbfda8aSnia		height = tmp_win->frame_height;
12440bbfda8aSnia	}
12450bbfda8aSnia	else {
12460bbfda8aSnia		height += 2 * tmp_win->frame_bw3D + tmp_win->title_height;
12470bbfda8aSnia	}
12480bbfda8aSnia	ConstrainSize(tmp_win, &width, &height);
12490bbfda8aSnia	if(mask & XValue) {
12500bbfda8aSnia		if(mask & XNegative) {
12510bbfda8aSnia			x += Scr->rootw  - width;
12520bbfda8aSnia		}
12530bbfda8aSnia	}
12540bbfda8aSnia	else {
12550bbfda8aSnia		x = tmp_win->frame_x;
12560bbfda8aSnia	}
12570bbfda8aSnia	if(mask & YValue) {
12580bbfda8aSnia		if(mask & YNegative) {
12590bbfda8aSnia			y += Scr->rooth - height;
12600bbfda8aSnia		}
12610bbfda8aSnia	}
12620bbfda8aSnia	else {
12630bbfda8aSnia		y = tmp_win->frame_y;
12640bbfda8aSnia	}
12650bbfda8aSnia
12660bbfda8aSnia	{
12670bbfda8aSnia		int          junkX, junkY;
12680bbfda8aSnia		unsigned int junkK;
12690bbfda8aSnia		Window       junkW;
12700bbfda8aSnia		XQueryPointer(dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK);
12710bbfda8aSnia	}
12720bbfda8aSnia	px -= tmp_win->frame_x;
12730bbfda8aSnia	if(px > width) {
12740bbfda8aSnia		px = width / 2;
12750bbfda8aSnia	}
12760bbfda8aSnia	py -= tmp_win->frame_y;
12770bbfda8aSnia	if(py > height) {
12780bbfda8aSnia		px = height / 2;
12790bbfda8aSnia	}
12800bbfda8aSnia
12810bbfda8aSnia	SetupWindow(tmp_win, x, y, width, height, -1);
12820bbfda8aSnia	XWarpPointer(dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, x + px, y + py);
12830bbfda8aSnia	return;
12840bbfda8aSnia}
12850bbfda8aSnia
12860bbfda8aSnia
12870bbfda8aSnia/*
12880bbfda8aSnia * Making a specified alteration to a window's size
12890bbfda8aSnia */
12900bbfda8aSniaDFHANDLER(changesize)
12910bbfda8aSnia{
12920bbfda8aSnia	/* XXX Only use of this func; should we collapse? */
12930bbfda8aSnia	ChangeSize(action, tmp_win);
12940bbfda8aSnia}
12950bbfda8aSnia
12960bbfda8aSnia
12970bbfda8aSnia/*
12980bbfda8aSnia * Stashing and flipping back to a geometry
12990bbfda8aSnia */
13000bbfda8aSniaDFHANDLER(savegeometry)
13010bbfda8aSnia{
13020bbfda8aSnia	savegeometry(tmp_win);
13030bbfda8aSnia}
13040bbfda8aSnia
13050bbfda8aSniaDFHANDLER(restoregeometry)
13060bbfda8aSnia{
13070bbfda8aSnia	restoregeometry(tmp_win);
13080bbfda8aSnia}
13090bbfda8aSnia
13100bbfda8aSnia
13110bbfda8aSnia
13120bbfda8aSnia
13130bbfda8aSnia/*
13140bbfda8aSnia *********************************************************
13150bbfda8aSnia *
13160bbfda8aSnia * Misc utils used in the above
13170bbfda8aSnia *
13180bbfda8aSnia *********************************************************
13190bbfda8aSnia */
13200bbfda8aSnia
13210bbfda8aSnia/*
13220bbfda8aSnia * Used in the various move/fill/pack/etc bits
13230bbfda8aSnia */
13240bbfda8aSniastatic int
13250bbfda8aSniaFindConstraint(TwmWindow *tmp_win, MoveFillDir direction)
13260bbfda8aSnia{
13270bbfda8aSnia	TwmWindow  *t;
1328b18c2d1eSnia	int ret, limit;
13290bbfda8aSnia	const int winx = tmp_win->frame_x;
13300bbfda8aSnia	const int winy = tmp_win->frame_y;
13310bbfda8aSnia	const int winw = tmp_win->frame_width  + 2 * tmp_win->frame_bw;
13320bbfda8aSnia	const int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
13330bbfda8aSnia
1334b18c2d1eSnia	RArea area = RAreaNew(winx, winy, winw, winh);
1335b18c2d1eSnia
13360bbfda8aSnia	switch(direction) {
13370bbfda8aSnia		case MFD_LEFT:
1338b18c2d1eSnia			limit = RLayoutFindMonitorLeftEdge(Scr->BorderedLayout, &area);
1339b18c2d1eSnia			if(winx < limit) {
13400bbfda8aSnia				return -1;
13410bbfda8aSnia			}
1342b18c2d1eSnia			ret = limit;
13430bbfda8aSnia			break;
13440bbfda8aSnia		case MFD_RIGHT:
1345b18c2d1eSnia			limit = RLayoutFindMonitorRightEdge(Scr->BorderedLayout, &area);
1346b18c2d1eSnia			if(winx + winw > limit) {
13470bbfda8aSnia				return -1;
13480bbfda8aSnia			}
1349b18c2d1eSnia			ret = limit + 1;
13500bbfda8aSnia			break;
13510bbfda8aSnia		case MFD_TOP:
1352b18c2d1eSnia			limit = RLayoutFindMonitorTopEdge(Scr->BorderedLayout, &area);
1353b18c2d1eSnia			if(winy < limit) {
13540bbfda8aSnia				return -1;
13550bbfda8aSnia			}
1356b18c2d1eSnia			ret = limit;
13570bbfda8aSnia			break;
13580bbfda8aSnia		case MFD_BOTTOM:
1359b18c2d1eSnia			limit = RLayoutFindMonitorBottomEdge(Scr->BorderedLayout, &area);
1360b18c2d1eSnia			if(winy + winh > limit) {
13610bbfda8aSnia				return -1;
13620bbfda8aSnia			}
1363b18c2d1eSnia			ret = limit + 1;
13640bbfda8aSnia			break;
13650bbfda8aSnia		default:
13660bbfda8aSnia			return -1;
13670bbfda8aSnia	}
13680bbfda8aSnia	for(t = Scr->FirstWindow; t != NULL; t = t->next) {
13690bbfda8aSnia		const int w = t->frame_width  + 2 * t->frame_bw;
13700bbfda8aSnia		const int h = t->frame_height + 2 * t->frame_bw;
13710bbfda8aSnia
13720bbfda8aSnia		if(t == tmp_win) {
13730bbfda8aSnia			continue;
13740bbfda8aSnia		}
13750bbfda8aSnia		if(!visible(t)) {
13760bbfda8aSnia			continue;
13770bbfda8aSnia		}
13780bbfda8aSnia		if(!t->mapped) {
13790bbfda8aSnia			continue;
13800bbfda8aSnia		}
13810bbfda8aSnia
13820bbfda8aSnia		switch(direction) {
13830bbfda8aSnia			case MFD_LEFT:
13840bbfda8aSnia				if(winx        <= t->frame_x + w) {
13850bbfda8aSnia					continue;
13860bbfda8aSnia				}
13870bbfda8aSnia				if(winy        >= t->frame_y + h) {
13880bbfda8aSnia					continue;
13890bbfda8aSnia				}
13900bbfda8aSnia				if(winy + winh <= t->frame_y) {
13910bbfda8aSnia					continue;
13920bbfda8aSnia				}
13930bbfda8aSnia				ret = MAX(ret, t->frame_x + w);
13940bbfda8aSnia				break;
13950bbfda8aSnia			case MFD_RIGHT:
13960bbfda8aSnia				if(winx + winw >= t->frame_x) {
13970bbfda8aSnia					continue;
13980bbfda8aSnia				}
13990bbfda8aSnia				if(winy        >= t->frame_y + h) {
14000bbfda8aSnia					continue;
14010bbfda8aSnia				}
14020bbfda8aSnia				if(winy + winh <= t->frame_y) {
14030bbfda8aSnia					continue;
14040bbfda8aSnia				}
14050bbfda8aSnia				ret = MIN(ret, t->frame_x);
14060bbfda8aSnia				break;
14070bbfda8aSnia			case MFD_TOP:
14080bbfda8aSnia				if(winy        <= t->frame_y + h) {
14090bbfda8aSnia					continue;
14100bbfda8aSnia				}
14110bbfda8aSnia				if(winx        >= t->frame_x + w) {
14120bbfda8aSnia					continue;
14130bbfda8aSnia				}
14140bbfda8aSnia				if(winx + winw <= t->frame_x) {
14150bbfda8aSnia					continue;
14160bbfda8aSnia				}
14170bbfda8aSnia				ret = MAX(ret, t->frame_y + h);
14180bbfda8aSnia				break;
14190bbfda8aSnia			case MFD_BOTTOM:
14200bbfda8aSnia				if(winy + winh >= t->frame_y) {
14210bbfda8aSnia					continue;
14220bbfda8aSnia				}
14230bbfda8aSnia				if(winx        >= t->frame_x + w) {
14240bbfda8aSnia					continue;
14250bbfda8aSnia				}
14260bbfda8aSnia				if(winx + winw <= t->frame_x) {
14270bbfda8aSnia					continue;
14280bbfda8aSnia				}
14290bbfda8aSnia				ret = MIN(ret, t->frame_y);
14300bbfda8aSnia				break;
14310bbfda8aSnia		}
14320bbfda8aSnia	}
14330bbfda8aSnia	return ret;
14340bbfda8aSnia}
14350bbfda8aSnia
14360bbfda8aSnia
14370bbfda8aSnia/*
14380bbfda8aSnia * Is Window w part of the conglomerate of metawindows we put around the
14390bbfda8aSnia * real window for TwmWindow t?  Note that this does _not_ check if w is
14400bbfda8aSnia * the actual window we built the TwmWindow t around.
14410bbfda8aSnia */
14420bbfda8aSniastatic bool
14430bbfda8aSniabelongs_to_twm_window(TwmWindow *t, Window w)
14440bbfda8aSnia{
14450bbfda8aSnia	/* Safety */
14460bbfda8aSnia	if(!t) {
14470bbfda8aSnia		return false;
14480bbfda8aSnia	}
14490bbfda8aSnia
14500bbfda8aSnia	/* Part of the framing we put around the window? */
14510bbfda8aSnia	if(w == t->frame || w == t->title_w
14520bbfda8aSnia	                || w == t->hilite_wl || w == t->hilite_wr) {
14530bbfda8aSnia		return true;
14540bbfda8aSnia	}
14550bbfda8aSnia
14560bbfda8aSnia	/* Part of the icon bits? */
14570bbfda8aSnia	if(t->icon && (w == t->icon->w || w == t->icon->bm_w)) {
14580bbfda8aSnia		return true;
14590bbfda8aSnia	}
14600bbfda8aSnia
14610bbfda8aSnia	/* One of the title button windows? */
14620bbfda8aSnia	if(t->titlebuttons) {
14630bbfda8aSnia		TBWindow *tbw;
14640bbfda8aSnia		int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
14650bbfda8aSnia		for(tbw = t->titlebuttons ; nb > 0 ; tbw++, nb--) {
14660bbfda8aSnia			if(tbw->window == w) {
14670bbfda8aSnia				return true;
14680bbfda8aSnia			}
14690bbfda8aSnia		}
14700bbfda8aSnia	}
14710bbfda8aSnia
14720bbfda8aSnia	/* Then no */
14730bbfda8aSnia	return false;
14740bbfda8aSnia}
1475