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