2 * (c) Copyright 1989, 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC.
10 static char rcsid[] = "$XConsortium: WmCPlace.c /main/5 1996/08/09 15:18:04 rswiston $"
14 * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
22 #include <X11/keysymdef.h>
24 /* absolute value macro */
26 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
29 #define GRAB_MASK (KeyPressMask | ButtonPressMask | ButtonReleaseMask |\
31 #define PGRAB_MASK (ButtonPressMask | ButtonReleaseMask |\
32 PointerMotionMask | PointerMotionHintMask)
34 #define NOFRZ_GRAB_MASK (KeyPressMask | ButtonPressMask |\
36 #define NOFRZ_PGRAB_MASK (ButtonPressMask | ButtonReleaseMask)
39 * include extern functions
43 #include "WmFeedback.h"
44 #include "WmWinConf.h"
51 static unsigned int placeWidth;
52 static unsigned int placeHeight;
54 static Boolean placeResize;
55 static Boolean placementDone;
56 static int placePointerX;
57 static int placePointerY;
58 static int placeKeyMultiplier;
60 static int placeOffsetX;
61 static int placeOffsetY;
65 /*************************************<->*************************************
67 * SetupPlacement (pcd)
72 * Perform the initialization for interactive placement
77 * pcd - pointer to client data
85 * o sets up global data and puts initial display on the screen
87 *************************************<->***********************************/
88 void SetupPlacement (ClientData *pcd)
94 * Restore the state of the last "depressed" frame gadget
97 if (wmGD.gadgetClient && wmGD.gadgetDepressed)
99 PopGadgetOut(wmGD.gadgetClient, wmGD.gadgetDepressed);
103 /* get offset of frame origin from window origin */
104 placeOffsetX = pcd->clientOffset.x;
105 placeOffsetY = pcd->clientOffset.y;
107 XQueryPointer (DISPLAY, ACTIVE_ROOT,
108 &junk_win, &junk_win,
109 &cX, &cY, &junk, &junk, (unsigned int *)&junk);
111 /* convert to frame coordinates */
112 placePointerX = placeX = cX;
113 placePointerY = placeY = cY;
114 placeWidth = pcd->clientWidth;
115 placeHeight = pcd->clientHeight;
116 ClientToFrame (pcd, &cX, &cY, &placeWidth, &placeHeight);
118 /* in "position" mode to start with */
120 wmGD.preMove = FALSE;
122 /* normal window being dealt with, not icon */
123 wmGD.movingIcon = FALSE;
125 if (wmGD.showFeedback & WM_SHOW_FB_PLACEMENT)
127 DoFeedback (pcd, placeX, placeY, placeWidth, placeHeight,
128 (FB_SIZE | FB_POSITION), placeResize);
131 /* set up initial visual feedback */
132 MoveOutline (placeX, placeY, placeWidth, placeHeight);
134 } /* END OF FUNCTION SetupPlacement */
137 /*************************************<->*************************************
139 * IsRepeatedKeyEvent (dpy, pEvent, pOldEvent)
144 * Returns TRUE if the event passed in is a repeat of the key event
145 * indicated in pOldEvent
151 * pEvent - pointer to this event
152 * pOldEvent - pointer to previous event (cast to the correct type)
157 * IsRepeatedKeyEvent - True if the events are "the same,"
164 *************************************<->***********************************/
165 Bool IsRepeatedKeyEvent (Display *dpy, XEvent *pEvent, char *pOldEvent)
167 XEvent *pOld = (XEvent *) pOldEvent;
169 if ((pEvent->type == KeyPress) && /* key press event */
170 (pEvent->type == pOld->type) && /* same event type */
171 (pEvent->xkey.keycode == pOld->xkey.keycode) && /* same key code */
172 (pEvent->xkey.state == pOld->xkey.state) && /* same modifiers */
173 (pEvent->xkey.window == pOld->xkey.window) && /* same window */
174 (pEvent->xkey.root == pOld->xkey.root)) /* same root */
185 /*************************************<->*************************************
187 * StartInteractiveSizing (pcd, time)
192 * Switch from "position" mode to "resize" mode
197 * pcd - pointer to client data
198 * time - time stamp of event for pointer regrab
208 *************************************<->***********************************/
209 void StartInteractiveSizing (ClientData *pcd, Time time)
213 /* regrab pointer to change cursor */
214 gmask = (wmGD.freezeOnConfig)? PGRAB_MASK : NOFRZ_PGRAB_MASK;
215 XChangeActivePointerGrab (DISPLAY, gmask,
216 wmGD.sizePlacementCursor, time);
218 /* put cursor at lower-right corner */
221 XWarpPointer (DISPLAY, None, ACTIVE_ROOT, 0, 0, 0, 0,
222 (int) (placeX+placeWidth-1), (int) (placeY+placeHeight-1));
226 * Don't go into resize mode if resize is turned off.
228 if (pcd->clientFunctions & MWM_FUNC_RESIZE)
232 wmGD.preMove = FALSE;
237 /*************************************<->*************************************
239 * HandlePlacementKeyEvent (pcd, pev)
244 * Handle key presses during interactive placement
249 * pcd - pointer to client data
250 * pev - pointer to key press event
259 *************************************<->***********************************/
261 void HandlePlacementKeyEvent (ClientData *pcd, XKeyEvent *pev)
265 Boolean control, valid;
269 int warpX, warpY, newX, newY;
270 int keyPlaceX = placeX;
271 int keyPlaceY = placeY;
272 unsigned int keyPlaceWidth = placeWidth;
273 unsigned int keyPlaceHeight = placeHeight;
275 /* filter out repeating keys */
276 placeKeyMultiplier = 1;
277 if (pev->type == KeyPress)
279 while (placeKeyMultiplier <= 10 &&
280 XCheckIfEvent (DISPLAY, &KeyEvent, IsRepeatedKeyEvent,
283 placeKeyMultiplier++;
287 /* convert event data to useful key data */
288 keysym = XKeycodeToKeysym (DISPLAY, pev->keycode, 0);
289 control = (pev->state & ControlMask) != 0;
290 big_inc = DisplayWidth(DISPLAY, ACTIVE_PSD->screen) / 20;
292 /* interpret key data */
297 tmpX = (control) ? (-big_inc) : -1;
302 tmpY = (control) ? (-big_inc) : -1;
307 tmpX = (control) ? (big_inc) : 1;
312 tmpY = (control) ? (big_inc) : 1;
317 StartInteractiveSizing(pcd, pev->time);
321 placementDone = TRUE; /* global "done" flag */
329 /* if a valid key was pressed, then react to it */
331 tmpX *= placeKeyMultiplier;
332 tmpY *= placeKeyMultiplier;
336 keyPlaceWidth += tmpX; /* change size of outline */
337 keyPlaceHeight += tmpY;
339 FixFrameValues(pcd, &keyPlaceX, &keyPlaceY, &keyPlaceWidth,
340 &keyPlaceHeight, placeResize);
342 warpX = keyPlaceX+keyPlaceWidth-1;
343 warpY = keyPlaceY+keyPlaceHeight-1;
345 SetPointerPosition (warpX, warpY, &newX, &newY);
347 if ((warpX == newX) && (warpY == newY))
349 placeWidth = keyPlaceWidth;
350 placeHeight = keyPlaceHeight;
354 placeWidth = newX - keyPlaceX + 1;
355 placeHeight = newY - keyPlaceY + 1;
360 keyPlaceX += tmpX; /* change position of outline */
363 FixFrameValues(pcd, &keyPlaceX, &keyPlaceY, &keyPlaceWidth,
364 &keyPlaceHeight, placeResize);
369 SetPointerPosition (warpX, warpY, &newX, &newY);
374 placePointerX = newX;
375 placePointerY = newY;
377 FixFrameValues (pcd, &placeX, &placeY, &placeWidth, &placeHeight,
380 MoveOutline (placeX, placeY, placeWidth, placeHeight);
382 if (wmGD.showFeedback & WM_SHOW_FB_PLACEMENT)
384 DoFeedback (pcd, placeX, placeY, placeWidth, placeHeight,
387 } /* END OF FUNCTION HandlePlacementKeyEvent */
390 /*************************************<->*************************************
392 * HandlePlacementButtonEvent (pev)
402 * pev - pointer to button event
411 *************************************<->***********************************/
413 void HandlePlacementButtonEvent (XButtonEvent *pev)
416 * Only listen to button 1
418 if (pev->button == 1)
421 * Complete interactive placement on button release
423 if (pev->type == ButtonRelease)
425 placementDone = TRUE; /* global done flag */
428 else if (pev->type == ButtonPress)
432 * Button press, go to pre-resize mode
434 wmGD.preMoveX = pev->x_root;
435 wmGD.preMoveY = pev->y_root;
443 /*************************************<->*************************************
445 * HandlePlacementMotionEvent (pcd, pev)
450 * Handles pointer motion events during interactive placement
455 * pcd - pointer to client data
456 * pev - pointer to mouse motion event
466 *************************************<->***********************************/
468 void HandlePlacementMotionEvent (ClientData *pcd, XMotionEvent *pev)
473 * If in pre-resize mode, check for motion crossing threshhold before
477 diffx = pev->x_root - wmGD.preMoveX;
478 diffy = pev->y_root - wmGD.preMoveY;
479 if ((ABS(diffx) > wmGD.moveThreshold) ||
480 (ABS(diffy) > wmGD.moveThreshold))
482 StartInteractiveSizing(pcd, pev->time);
489 * Track lower right corner
491 if (pev->x_root > placeX)
492 placeWidth = pev->x_root - placeX + 1;
493 if (pev->y_root > placeY)
494 placeHeight = pev->y_root - placeY + 1;
498 * track window position
500 placeX = pev->x_root;
501 placeY = pev->y_root;
504 placePointerX = pev->x_root;
505 placePointerY = pev->y_root;
507 FixFrameValues (pcd, &placeX, &placeY, &placeWidth, &placeHeight,
510 MoveOutline (placeX, placeY, placeWidth, placeHeight);
512 if (wmGD.showFeedback & WM_SHOW_FB_PLACEMENT)
514 DoFeedback (pcd, placeX, placeY, placeWidth, placeHeight,
517 } /* END OF FUNCTION HandlePlacementMotionEvent */
521 /*************************************<->*************************************
528 * Gets window configuration from the user via pointer/keyboard interaction
533 * pcd - pointer to client data
538 * pcd - clientX, clientY, clientWidth, and clientHeight members
543 * We try to be careful only to remove events that we need from the
544 * event queue while we're in our own event processing loop.
546 *************************************<->***********************************/
547 void DoPlacement (ClientData *pcd)
554 SetupPlacement (pcd);
559 placementDone = FALSE;
560 while (!placementDone)
562 GetConfigEvent (DISPLAY, ACTIVE_ROOT, GRAB_MASK,
563 placePointerX, placePointerY, placeX, placeY,
564 placeWidth, placeHeight, &event);
566 switch (event.type) {
568 HandlePlacementKeyEvent(pcd, (XKeyEvent *)&event);
572 HandlePlacementButtonEvent((XButtonEvent *)&event);
576 HandlePlacementButtonEvent((XButtonEvent *)&event);
580 HandlePlacementMotionEvent(pcd, (XMotionEvent *)&event);
586 /* copy back the configuration information */
587 pcd->clientX = placeX + placeOffsetX;
588 pcd->clientY = placeY + placeOffsetY;
589 pcd->clientWidth = placeWidth - 2*placeOffsetX;
590 pcd->clientHeight = placeHeight - placeOffsetX - placeOffsetY;
593 MoveOutline (0,0,0,0);
594 HideFeedbackWindow(pcd->pSD);
596 } /* END OF FUNCTION DoPlacement */
600 /*************************************<->*************************************
602 * PlaceWindowInteractively(pcd)
607 * Gets the clients size and position information interactively from the
613 * pcd - pointer to client data
623 *************************************<->***********************************/
624 void PlaceWindowInteractively (ClientData *pcd)
628 gmask = (wmGD.freezeOnConfig)? PGRAB_MASK : NOFRZ_PGRAB_MASK;
631 * Return if config is in progress or if grabs fail
633 if (!DoGrabs (ACTIVE_ROOT, wmGD.movePlacementCursor,
634 gmask, CurrentTime, pcd, True))
640 * Get the size and position of the window from the user.
641 * Do our own event processing until a button-up event occurs
646 * Finish up and return the data
649 wmGD.preMove = FALSE;