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