Initial import of the CDE 2.1.30 sources from the Open Group.
[oweals/cde.git] / cde / programs / dtwm / WmCPlace.c
1 /* 
2  * (c) Copyright 1989, 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC. 
3  * ALL RIGHTS RESERVED 
4 */ 
5 /* 
6  * Motif Release 1.2
7 */ 
8 #ifdef REV_INFO
9 #ifndef lint
10 static char rcsid[] = "$XConsortium: WmCPlace.c /main/5 1996/08/09 15:18:04 rswiston $"
11 #endif
12 #endif
13 /*
14  * (c) Copyright 1987, 1988, 1989, 1990 HEWLETT-PACKARD COMPANY */
15
16 /*
17  * Included Files:
18  */
19 #include "WmGlobal.h"
20 #define XK_MISCELLANY
21 #define XK_LATIN1
22 #include <X11/keysymdef.h>
23
24 /* absolute value macro */
25 #ifndef ABS
26 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
27 #endif
28
29 #define GRAB_MASK (KeyPressMask | ButtonPressMask | ButtonReleaseMask |\
30                    PointerMotionMask)
31 #define PGRAB_MASK (ButtonPressMask | ButtonReleaseMask |\
32                     PointerMotionMask | PointerMotionHintMask)
33
34 #define NOFRZ_GRAB_MASK (KeyPressMask | ButtonPressMask |\
35                          ButtonReleaseMask)
36 #define NOFRZ_PGRAB_MASK (ButtonPressMask | ButtonReleaseMask)
37                           
38 /*
39  * include extern functions
40  */
41 #include "WmCDInfo.h"
42 #include "WmCDecor.h"
43 #include "WmFeedback.h"
44 #include "WmWinConf.h"
45
46 /*
47  * Global Variables:
48  */
49 static int placeX;
50 static int placeY;
51 static unsigned int placeWidth;
52 static unsigned int placeHeight;
53
54 static Boolean placeResize;
55 static Boolean placementDone;
56 static int placePointerX;
57 static int placePointerY;
58 static int placeKeyMultiplier;
59
60 static int placeOffsetX;
61 static int placeOffsetY;
62
63
64 \f
65 /*************************************<->*************************************
66  *
67  *  SetupPlacement (pcd)
68  *
69  *
70  *  Description:
71  *  -----------
72  *  Perform the initialization for interactive placement
73  *
74  *
75  *  Inputs:
76  *  ------
77  *  pcd         - pointer to client data
78  * 
79  *  Outputs:
80  *  -------
81  *
82  *
83  *  Comments:
84  *  --------
85  * o sets up global data and puts initial display on the screen
86  * 
87  *************************************<->***********************************/
88 void SetupPlacement (ClientData *pcd)
89 {
90     int cX, cY, junk;
91     Window junk_win;
92
93     /*
94      * Restore the state of the last "depressed" frame gadget
95      */
96
97     if (wmGD.gadgetClient && wmGD.gadgetDepressed)
98     {
99         PopGadgetOut(wmGD.gadgetClient, wmGD.gadgetDepressed);
100
101     }
102         
103     /* get offset of frame origin from window origin */
104     placeOffsetX = pcd->clientOffset.x;
105     placeOffsetY = pcd->clientOffset.y;
106
107     XQueryPointer (DISPLAY, ACTIVE_ROOT, 
108                    &junk_win, &junk_win,
109                    &cX, &cY, &junk, &junk, (unsigned int *)&junk);
110
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);
117
118     /* in "position" mode to start with */
119     placeResize = FALSE;
120     wmGD.preMove = FALSE;
121
122     /* normal window being dealt with, not icon */
123     wmGD.movingIcon = FALSE;
124
125     if (wmGD.showFeedback & WM_SHOW_FB_PLACEMENT)
126     {
127         DoFeedback (pcd, placeX, placeY, placeWidth, placeHeight, 
128                     (FB_SIZE | FB_POSITION), placeResize);
129     }
130
131     /* set up initial visual feedback */
132     MoveOutline (placeX, placeY, placeWidth, placeHeight);
133
134 } /* END OF FUNCTION SetupPlacement  */
135
136 \f
137 /*************************************<->*************************************
138  *
139  *  IsRepeatedKeyEvent (dpy, pEvent, pOldEvent)
140  *
141  *
142  *  Description:
143  *  -----------
144  *  Returns TRUE if the event passed in is a repeat of the key event
145  *  indicated in pOldEvent
146  *
147  *
148  *  Inputs:
149  *  ------
150  *  dpy         - display
151  *  pEvent      - pointer to this event
152  *  pOldEvent   - pointer to previous event (cast to the correct type)
153  *
154  * 
155  *  Outputs:
156  *  -------
157  *  IsRepeatedKeyEvent  - True if the events are "the same," 
158  *                        False otherwise.
159  *
160  *
161  *  Comments:
162  *  --------
163  * 
164  *************************************<->***********************************/
165 Bool IsRepeatedKeyEvent (Display *dpy, XEvent *pEvent, char *pOldEvent)
166 {
167     XEvent *pOld = (XEvent *) pOldEvent;
168
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 */
175     {
176         return (True);
177     }
178     else 
179     { 
180         return (False);
181     }
182 }
183
184 \f
185 /*************************************<->*************************************
186  *
187  *  StartInteractiveSizing (pcd, time)
188  *
189  *
190  *  Description:
191  *  -----------
192  *  Switch from "position" mode to "resize" mode
193  *
194  *
195  *  Inputs:
196  *  ------
197  *  pcd         - pointer to client data
198  *  time        - time stamp of event for pointer regrab
199  *
200  * 
201  *  Outputs:
202  *  -------
203  *
204  *
205  *  Comments:
206  *  --------
207  * 
208  *************************************<->***********************************/
209 void StartInteractiveSizing (ClientData *pcd, Time time)
210 {
211     unsigned int gmask;
212
213     /* regrab pointer to change cursor */
214     gmask = (wmGD.freezeOnConfig)? PGRAB_MASK : NOFRZ_PGRAB_MASK;
215     XChangeActivePointerGrab (DISPLAY, gmask, 
216                               wmGD.sizePlacementCursor, time);
217
218     /* put cursor at lower-right corner */
219     if (wmGD.enableWarp)
220     {
221         XWarpPointer (DISPLAY, None, ACTIVE_ROOT, 0, 0, 0, 0, 
222                   (int) (placeX+placeWidth-1), (int) (placeY+placeHeight-1));
223     }
224
225     /*
226      * Don't go into resize mode if resize is turned off.
227      */
228     if (pcd->clientFunctions & MWM_FUNC_RESIZE)
229     {
230         /* update flags */
231         placeResize = TRUE;
232         wmGD.preMove = FALSE;
233     }
234 }
235
236 \f
237 /*************************************<->*************************************
238  *
239  *  HandlePlacementKeyEvent (pcd, pev)
240  *
241  *
242  *  Description:
243  *  -----------
244  *  Handle key presses during interactive placement
245  *
246  *
247  *  Inputs:
248  *  ------
249  *  pcd         - pointer to client data
250  *  pev         - pointer to key press event
251  * 
252  *  Outputs:
253  *  -------
254  *
255  *
256  *  Comments:
257  *  --------
258  * 
259  *************************************<->***********************************/
260
261 void HandlePlacementKeyEvent (ClientData *pcd, XKeyEvent *pev)
262 {
263     XEvent KeyEvent;
264     KeySym keysym;
265     Boolean control, valid;
266     int big_inc;
267     int tmpX = 0;
268     int tmpY = 0;
269     int warpX, warpY, newX, newY;
270     int keyPlaceX = placeX;
271     int keyPlaceY = placeY;
272     unsigned int keyPlaceWidth = placeWidth;
273     unsigned int keyPlaceHeight = placeHeight;
274
275     /* filter out repeating keys */
276     placeKeyMultiplier = 1;
277     if (pev->type == KeyPress)
278     {
279         while (placeKeyMultiplier <= 10 && 
280                   XCheckIfEvent (DISPLAY, &KeyEvent, IsRepeatedKeyEvent, 
281                   (char *) pev))
282         {
283               placeKeyMultiplier++;
284         }
285     }
286
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;
291
292     /* interpret key data */
293     valid = FALSE;
294     switch (keysym) 
295     {
296         case XK_Left:
297             tmpX = (control) ? (-big_inc) : -1;
298             valid = TRUE;
299             break;
300
301         case XK_Up:
302             tmpY = (control) ? (-big_inc) : -1;
303             valid = TRUE;
304             break;
305
306         case XK_Right:
307             tmpX = (control) ? (big_inc) : 1;
308             valid = TRUE;
309             break;
310
311         case XK_Down:
312             tmpY = (control) ? (big_inc) : 1;
313             valid = TRUE;
314             break;
315
316         case XK_space:
317             StartInteractiveSizing(pcd, pev->time);
318             break;
319
320         case XK_Return:
321             placementDone = TRUE;       /* global "done" flag */
322             break;
323
324         default:
325             break;
326     }
327
328
329     /* if a valid key was pressed, then react to it */
330     if (valid) {
331         tmpX *= placeKeyMultiplier;
332         tmpY *= placeKeyMultiplier;
333
334         if (placeResize)
335         {
336             keyPlaceWidth += tmpX;              /* change size of outline */
337             keyPlaceHeight += tmpY;
338
339             FixFrameValues(pcd, &keyPlaceX, &keyPlaceY, &keyPlaceWidth, 
340                            &keyPlaceHeight, placeResize);
341
342             warpX = keyPlaceX+keyPlaceWidth-1;
343             warpY = keyPlaceY+keyPlaceHeight-1;
344
345             SetPointerPosition (warpX, warpY, &newX, &newY);
346
347             if ((warpX == newX) && (warpY == newY))
348             {
349                 placeWidth = keyPlaceWidth;
350                 placeHeight = keyPlaceHeight;
351             }
352             else 
353             {
354                 placeWidth = newX - keyPlaceX + 1;
355                 placeHeight = newY - keyPlaceY + 1;
356             }
357         }
358         else 
359         {
360             keyPlaceX += tmpX;          /* change position of outline */
361             keyPlaceY += tmpY;
362
363             FixFrameValues(pcd, &keyPlaceX, &keyPlaceY, &keyPlaceWidth, 
364                            &keyPlaceHeight, placeResize);
365
366             warpX = keyPlaceX;
367             warpY = keyPlaceY;
368
369             SetPointerPosition (warpX, warpY, &newX, &newY);
370
371             placeX = newX;
372             placeY = newY;
373         }
374         placePointerX = newX;
375         placePointerY = newY;
376     }
377     FixFrameValues (pcd, &placeX, &placeY, &placeWidth, &placeHeight,
378                     placeResize);
379
380     MoveOutline (placeX, placeY, placeWidth, placeHeight);
381
382     if (wmGD.showFeedback & WM_SHOW_FB_PLACEMENT)
383     {
384         DoFeedback (pcd, placeX, placeY, placeWidth, placeHeight, 
385                     0, placeResize);
386     }
387 } /* END OF FUNCTION HandlePlacementKeyEvent */
388
389 \f
390 /*************************************<->*************************************
391  *
392  *  HandlePlacementButtonEvent (pev)
393  *
394  *
395  *  Description:
396  *  -----------
397  *  XXDescription ...
398  *
399  *
400  *  Inputs:
401  *  ------
402  *  pev         - pointer to button event
403  * 
404  *  Outputs:
405  *  -------
406  *
407  *
408  *  Comments:
409  *  --------
410  * 
411  *************************************<->***********************************/
412
413 void HandlePlacementButtonEvent (XButtonEvent *pev)
414 {
415     /*
416      * Only listen to button 1
417      */
418     if (pev->button == 1)
419     {
420         /* 
421          * Complete interactive placement on button release
422          */
423         if (pev->type == ButtonRelease) 
424         {
425             placementDone = TRUE;               /* global done flag */
426         }
427
428         else if (pev->type == ButtonPress) 
429         {
430
431         /*
432          * Button press, go to pre-resize mode
433          */
434             wmGD.preMoveX = pev->x_root;
435             wmGD.preMoveY = pev->y_root;
436             wmGD.preMove = TRUE;
437         }
438     }
439 }
440
441
442 \f
443 /*************************************<->*************************************
444  *
445  *  HandlePlacementMotionEvent (pcd, pev)
446  *
447  *
448  *  Description:
449  *  -----------
450  *  Handles pointer motion events during interactive placement
451  *
452  *
453  *  Inputs:
454  *  ------
455  *  pcd         - pointer to client data
456  *  pev         - pointer to mouse motion event
457  *
458  * 
459  *  Outputs:
460  *  -------
461  *
462  *
463  *  Comments:
464  *  --------
465  * 
466  *************************************<->***********************************/
467
468 void HandlePlacementMotionEvent (ClientData *pcd, XMotionEvent *pev)
469 {
470     int diffx, diffy;
471
472     /*
473      * If in pre-resize mode, check for motion crossing threshhold before 
474      * switching modes
475      */
476     if (wmGD.preMove) {
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))
481         {
482             StartInteractiveSizing(pcd, pev->time);
483         }
484         return; 
485     }
486
487     if (placeResize) {
488         /*
489          * Track lower right corner
490          */
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;
495     }
496     else {
497         /*
498          * track window position
499          */
500         placeX = pev->x_root;
501         placeY = pev->y_root;
502     }
503
504     placePointerX = pev->x_root;
505     placePointerY = pev->y_root;
506
507     FixFrameValues (pcd, &placeX, &placeY, &placeWidth, &placeHeight,
508                     placeResize);
509
510     MoveOutline (placeX, placeY, placeWidth, placeHeight);
511
512     if (wmGD.showFeedback & WM_SHOW_FB_PLACEMENT)
513     {
514         DoFeedback (pcd, placeX, placeY, placeWidth, placeHeight, 
515                     0, placeResize);
516     }
517 } /* END OF FUNCTION HandlePlacementMotionEvent */
518
519
520 \f
521 /*************************************<->*************************************
522  *
523  *  DoPlacement (pcd)
524  *
525  *
526  *  Description:
527  *  -----------
528  *  Gets window configuration from the user via pointer/keyboard interaction
529  *
530  *
531  *  Inputs:
532  *  ------
533  *  pcd         - pointer to client data
534  *
535  * 
536  *  Outputs:
537  *  -------
538  *  pcd         - clientX, clientY, clientWidth, and clientHeight members
539  *                could be changed
540  *
541  *  Comments:
542  *  --------
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.
545  * 
546  *************************************<->***********************************/
547 void DoPlacement (ClientData *pcd)
548 {
549     XEvent event;
550
551     /*
552      * Initialization
553      */
554     SetupPlacement (pcd);
555
556     /*
557      * Process events
558      */
559     placementDone = FALSE;
560     while (!placementDone)
561     {
562         GetConfigEvent (DISPLAY, ACTIVE_ROOT, GRAB_MASK,
563                 placePointerX, placePointerY, placeX, placeY, 
564                 placeWidth, placeHeight, &event);
565
566         switch (event.type) {
567             case KeyPress:
568                 HandlePlacementKeyEvent(pcd, (XKeyEvent *)&event);
569                 break;
570
571             case ButtonPress:
572                 HandlePlacementButtonEvent((XButtonEvent *)&event);
573                 break;
574
575             case ButtonRelease:
576                 HandlePlacementButtonEvent((XButtonEvent *)&event);
577                 break;
578
579             case MotionNotify:
580                 HandlePlacementMotionEvent(pcd, (XMotionEvent *)&event);
581                 break;
582
583         }
584     }
585     
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;
591
592     /* clean up */
593     MoveOutline (0,0,0,0);
594     HideFeedbackWindow(pcd->pSD);
595
596 } /* END OF FUNCTION DoPlacement  */
597
598
599 \f
600 /*************************************<->*************************************
601  *
602  *  PlaceWindowInteractively(pcd)
603  *
604  *
605  *  Description:
606  *  -----------
607  *  Gets the clients size and position information interactively from the
608  *  user.
609  *
610  *
611  *  Inputs:
612  *  ------
613  *  pcd         - pointer to client data
614  *
615  * 
616  *  Outputs:
617  *  -------
618  *
619  *
620  *  Comments:
621  *  --------
622  * 
623  *************************************<->***********************************/
624 void PlaceWindowInteractively (ClientData *pcd)
625 {
626     unsigned int gmask;
627
628     gmask = (wmGD.freezeOnConfig)? PGRAB_MASK : NOFRZ_PGRAB_MASK;
629
630     /*
631      * Return if config is in progress or if grabs fail
632      */
633     if (!DoGrabs (ACTIVE_ROOT, wmGD.movePlacementCursor, 
634         gmask, CurrentTime, pcd, True))
635     {
636         return;
637     }
638
639     /*
640      *  Get the size and position of the window from the user.
641      *  Do our own event processing until a button-up event occurs
642      */
643     DoPlacement(pcd);
644
645     /*
646      * Finish up and return the data
647      */
648     UndoGrabs();
649     wmGD.preMove = FALSE;
650 }
651
652
653
654