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