1 /* $Id: pan.c,v 1.1 2004/08/28 19:25:46 dannybackx Exp $ */
2 /*****************************************************************************/
3 /**       Copyright 1988 by Evans & Sutherland Computer Corporation,        **/
4 /**                          Salt Lake City, Utah                           **/
5 /**  Portions Copyright 1989 by the Massachusetts Institute of Technology   **/
6 /**                        Cambridge, Massachusetts                         **/
7 /**                                                                         **/
8 /**                           All Rights Reserved                           **/
9 /**                                                                         **/
10 /**    Permission to use, copy, modify, and distribute this software and    **/
11 /**    its documentation  for  any  purpose  and  without  fee is hereby    **/
12 /**    granted, provided that the above copyright notice appear  in  all    **/
13 /**    copies and that both  that  copyright  notice  and  this  permis-    **/
14 /**    sion  notice appear in supporting  documentation,  and  that  the    **/
15 /**    names of Evans & Sutherland and M.I.T. not be used in advertising    **/
16 /**    in publicity pertaining to distribution of the  software  without    **/
17 /**    specific, written prior permission.                                  **/
18 /**                                                                         **/
19 /**    EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD    **/
20 /**    TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES  OF  MERCHANT-    **/
21 /**    ABILITY  AND  FITNESS,  IN  NO  EVENT SHALL EVANS & SUTHERLAND OR    **/
22 /**    M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL  DAM-    **/
23 /**    AGES OR  ANY DAMAGES WHATSOEVER  RESULTING FROM LOSS OF USE, DATA    **/
24 /**    OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER    **/
25 /**    TORTIOUS ACTION, ARISING OUT OF OR IN  CONNECTION  WITH  THE  USE    **/
26 /**    OR PERFORMANCE OF THIS SOFTWARE.                                     **/
27 /*****************************************************************************/
28 /****************************************************************************
29  * This module is based on Twm, but has been siginificantly modified
30  * by Rob Nation
31  ****************************************************************************/
32 /***********************************************************************
33  * The rest of it is all my fault -- MLM
34  * mwm - "LessTif Window Manager"
35  ***********************************************************************/
36 
37 #include <LTconfig.h>
38 
39 #include <Xm/Xm.h>
40 #include <Xm/MwmUtil.h>
41 #include "mwm.h"
42 
43 #include <Xm/XmosP.h>
44 #if XmVERSION >= 2
45 #include <XmI/XmI.h>
46 #endif
47 
48 /****************************************************************************
49  * The root window is surrounded by four windows which are InputOnly.  This
50  * means you can see 'through' them, but they eat the input that happens
51  * inside them. An EnterEvent in one of these windows causes paging. The
52  * windows have the cursor pointing in the pan direction or are hidden if
53  * there is no more panning left in that direction. This is mostly intended
54  * to enable panning even over Motif applictions, which does not work yet; it
55  * seems that Motif windows eat all mouse events.
56  *
57  * Hermann Dunkel, HEDU, dunkel@cul-ipn.uni-kiel.de 1/94
58  * Anglified the grammar so I could read it -- MLM 9/96
59  ***************************************************************************/
60 
61 /*
62  * Creates the windows for edge-scrolling
63  */
64 void
PAN_Initialize(ScreenInfo * scr)65 PAN_Initialize(ScreenInfo *scr)
66 {
67     XSetWindowAttributes attributes;	/* attributes for create */
68     unsigned long valuemask;
69 
70     attributes.event_mask = (EnterWindowMask | LeaveWindowMask |
71 			     VisibilityChangeMask);
72     valuemask = (CWEventMask | CWCursor);
73 
74     attributes.cursor = scr->cursors[TOP_CURS];
75     scr->panner_top.win =
76 	XCreateWindow(dpy, scr->root_win,
77 		      0, 0,
78 		      scr->d_width, PAN_FRAME_THICKNESS,
79 		      0,	/* no border */
80 		      CopyFromParent, InputOnly,
81 		      CopyFromParent,
82 		      valuemask, &attributes);
83     attributes.cursor = scr->cursors[LEFT_CURS];
84     scr->panner_left.win =
85 	XCreateWindow(dpy, scr->root_win,
86 		      0, PAN_FRAME_THICKNESS,
87 		      PAN_FRAME_THICKNESS,
88 		      scr->d_height - 2 * PAN_FRAME_THICKNESS,
89 		      0,	/* no border */
90 		      CopyFromParent, InputOnly, CopyFromParent,
91 		      valuemask, &attributes);
92     attributes.cursor = scr->cursors[RIGHT_CURS];
93     scr->panner_right.win =
94 	XCreateWindow(dpy, scr->root_win,
95 		      scr->d_width - PAN_FRAME_THICKNESS, PAN_FRAME_THICKNESS,
96 		      PAN_FRAME_THICKNESS,
97 		      scr->d_height - 2 * PAN_FRAME_THICKNESS,
98 		      0,	/* no border */
99 		      CopyFromParent, InputOnly, CopyFromParent,
100 		      valuemask, &attributes);
101     attributes.cursor = scr->cursors[BOTTOM_CURS];
102     scr->panner_bottom.win =
103 	XCreateWindow(dpy, scr->root_win,
104 		      0, scr->d_height - PAN_FRAME_THICKNESS,
105 		      scr->d_width, PAN_FRAME_THICKNESS,
106 		      0,	/* no border */
107 		      CopyFromParent, InputOnly, CopyFromParent,
108 		      valuemask, &attributes);
109     scr->panner_top.isMapped = scr->panner_left.isMapped =
110 	scr->panner_right.isMapped = scr->panner_bottom.isMapped = False;
111 }
112 
113 /*
114  * checkPanFrames hides PanFrames if they are on the very border of the
115  * VIRTUAL screen and EdgeWrap for that direction is off.
116  * (A special cursor for the EdgeWrap border could be nice) HEDU
117  */
118 void
PAN_CheckBounds(ScreenInfo * scr)119 PAN_CheckBounds(ScreenInfo *scr)
120 {
121 
122     /* Remove Pan frames if paging by edge-scroll is permanently or
123      * temporarily disabled */
124     if ((scr->edge_scroll_y == 0) || (DoHandlePageing))
125     {
126 	XUnmapWindow(dpy, scr->panner_top.win);
127 	scr->panner_top.isMapped = False;
128 	XUnmapWindow(dpy, scr->panner_bottom.win);
129 	scr->panner_bottom.isMapped = False;
130     }
131     if ((scr->edge_scroll_x == 0) || (DoHandlePageing))
132     {
133 	XUnmapWindow(dpy, scr->panner_left.win);
134 	scr->panner_left.isMapped = False;
135 	XUnmapWindow(dpy, scr->panner_right.win);
136 	scr->panner_right.isMapped = False;
137     }
138 
139     if (scr->virt_x == 0 && scr->panner_left.isMapped)
140     {
141 	XUnmapWindow(dpy, scr->panner_left.win);
142 	scr->panner_left.isMapped = False;
143     }
144     else if (scr->virt_x > 0 && scr->panner_left.isMapped == False)
145     {
146 	XMapRaised(dpy, scr->panner_left.win);
147 	scr->panner_left.isMapped = True;
148     }
149     if (scr->virt_x == scr->virt_x_max && scr->panner_right.isMapped)
150     {
151 	XUnmapWindow(dpy, scr->panner_right.win);
152 	scr->panner_right.isMapped = False;
153     }
154     else if (scr->virt_x < scr->virt_x_max && scr->panner_right.isMapped == False)
155     {
156 	XMapRaised(dpy, scr->panner_right.win);
157 	scr->panner_right.isMapped = True;
158     }
159     /* TOP, hide only if EdgeWrap is off */
160     if (scr->virt_y == 0 && scr->panner_top.isMapped)
161     {
162 	XUnmapWindow(dpy, scr->panner_top.win);
163 	scr->panner_top.isMapped = False;
164     }
165     else if (scr->virt_y > 0 && scr->panner_top.isMapped == False)
166     {
167 	XMapRaised(dpy, scr->panner_top.win);
168 	scr->panner_top.isMapped = True;
169     }
170     /* BOTTOM, hide only if EdgeWrap is off */
171     if (scr->virt_y == scr->virt_y_max && scr->panner_bottom.isMapped)
172     {
173 	XUnmapWindow(dpy, scr->panner_bottom.win);
174 	scr->panner_bottom.isMapped = False;
175     }
176     else if (scr->virt_y < scr->virt_y_max && scr->panner_bottom.isMapped == False)
177     {
178 	XMapRaised(dpy, scr->panner_bottom.win);
179 	scr->panner_bottom.isMapped = True;
180     }
181 }
182 
183 /*
184  * Gotta make sure these things are on top of everything else, or they
185  * don't work!
186  */
187 void
PAN_Raise(ScreenInfo * scr)188 PAN_Raise(ScreenInfo *scr)
189 {
190     if (scr->panner_top.isMapped)
191 	XRaiseWindow(dpy, scr->panner_top.win);
192     if (scr->panner_left.isMapped)
193 	XRaiseWindow(dpy, scr->panner_left.win);
194     if (scr->panner_right.isMapped)
195 	XRaiseWindow(dpy, scr->panner_right.win);
196     if (scr->panner_bottom.isMapped)
197 	XRaiseWindow(dpy, scr->panner_bottom.win);
198 }
199 
200 /*
201  * check to see if a window is a panner window
202  */
203 Boolean
PAN_IsPannerWindow(ScreenInfo * scr,Window win)204 PAN_IsPannerWindow(ScreenInfo *scr, Window win)
205 {
206     if (win == scr->panner_top.win || win == scr->panner_left.win ||
207 	win == scr->panner_right.win || win == scr->panner_bottom.win)
208 	return True;
209 
210     return False;
211 }
212 
213 /*
214  * Check to see if the pointer is on the edge of the screen, and scroll/page
215  * if needed
216  */
217 void
PAN_PanDesktop(ScreenInfo * scr,int HorWarpSize,int VertWarpSize,int * xl,int * yt,int * delta_x,int * delta_y,Boolean Grab,XEvent * event)218 PAN_PanDesktop(ScreenInfo *scr, int HorWarpSize, int VertWarpSize,
219 	       int *xl, int *yt, int *delta_x, int *delta_y,
220 	       Boolean Grab, XEvent *event)
221 {
222     extern Bool DoHandlePageing;
223     int x, y, total;
224 
225     *delta_x = 0;
226     *delta_y = 0;
227 
228     if (DoHandlePageing)
229     {
230 	if ((scr->ScrollResistance >= 10000) ||
231 	    ((HorWarpSize == 0) && (VertWarpSize == 0)))
232 	    return;
233 
234 	/* need to move the viewport */
235 	if ((*xl >= SCROLL_REGION) && (*xl < scr->d_width - SCROLL_REGION) &&
236 	    (*yt >= SCROLL_REGION) && (*yt < scr->d_height - SCROLL_REGION))
237 	    return;
238 
239 	total = 0;
240 	while (total < scr->ScrollResistance)
241 	{
242 	    _XmMicroSleep(10000);
243 	    total += 10;
244 	    if (XCheckWindowEvent(dpy, scr->panner_top.win,
245 				  LeaveWindowMask, event))
246 	    {
247 		MISC_StashEventTime(event);
248 		return;
249 	    }
250 	    if (XCheckWindowEvent(dpy, scr->panner_bottom.win,
251 				  LeaveWindowMask, event))
252 	    {
253 		MISC_StashEventTime(event);
254 		return;
255 	    }
256 	    if (XCheckWindowEvent(dpy, scr->panner_left.win,
257 				  LeaveWindowMask, event))
258 	    {
259 		MISC_StashEventTime(event);
260 		return;
261 	    }
262 	    if (XCheckWindowEvent(dpy, scr->panner_right.win,
263 				  LeaveWindowMask, event))
264 	    {
265 		MISC_StashEventTime(event);
266 		return;
267 	    }
268 	}
269 
270 	XQueryPointer(dpy, scr->root_win, &JunkRoot, &JunkChild,
271 		      &x, &y, &JunkX, &JunkY, &JunkMask);
272 
273 	/* Turn off the rubberband if its on */
274 	WIN_DrawOutline(scr, scr->root_win, 0, 0, 0, 0);
275 
276 	/* Move the viewport */
277 	/* and/or move the cursor back to the approximate correct location */
278 	/* that is, the same place on the virtual desktop that it */
279 	/* started at */
280 	if (x < SCROLL_REGION)
281 	    *delta_x = -HorWarpSize;
282 	else if (x >= scr->d_width - SCROLL_REGION)
283 	    *delta_x = HorWarpSize;
284 	else
285 	    *delta_x = 0;
286 	if (y < SCROLL_REGION)
287 	    *delta_y = -VertWarpSize;
288 	else if (y >= scr->d_height - SCROLL_REGION)
289 	    *delta_y = VertWarpSize;
290 	else
291 	    *delta_y = 0;
292 
293 	/* Ouch! lots of bounds checking */
294 	if (scr->virt_x + *delta_x < 0)
295 	{
296 	    *delta_x = -scr->virt_x;
297 	    *xl = x - *delta_x;
298 	}
299 	else if (scr->virt_x + *delta_x > scr->virt_x_max)
300 	{
301 	    *delta_x = scr->virt_x_max - scr->virt_x;
302 	    *xl = x - *delta_x;
303 	}
304 	else
305 	    *xl = x - *delta_x;
306 
307 	if (scr->virt_y + *delta_y < 0)
308 	{
309 	    *delta_y = -scr->virt_y;
310 	    *yt = y - *delta_y;
311 	}
312 	else if (scr->virt_y + *delta_y > scr->virt_y_max)
313 	{
314 	    *delta_y = scr->virt_y_max - scr->virt_y;
315 	    *yt = y - *delta_y;
316 	}
317 	else
318 	    *yt = y - *delta_y;
319 
320 	if (*xl <= SCROLL_REGION)
321 	    *xl = SCROLL_REGION + 1;
322 	if (*yt <= SCROLL_REGION)
323 	    *yt = SCROLL_REGION + 1;
324 	if (*xl >= scr->d_width - SCROLL_REGION)
325 	    *xl = scr->d_width - SCROLL_REGION - 1;
326 	if (*yt >= scr->d_height - SCROLL_REGION)
327 	    *yt = scr->d_height - SCROLL_REGION - 1;
328 
329 	if ((*delta_x != 0) || (*delta_y != 0))
330 	{
331 	    if (Grab)
332 		XGrabServer(dpy);
333 	    XWarpPointer(dpy, None, scr->root_win, 0, 0, 0, 0, *xl, *yt);
334 	    PAGER_MoveViewPort(scr, scr->virt_x + *delta_x, scr->virt_y + *delta_y, False);
335 	    XQueryPointer(dpy, scr->root_win, &JunkRoot, &JunkChild,
336 			  xl, yt, &JunkX, &JunkY, &JunkMask);
337 	    if (Grab)
338 		XUngrabServer(dpy);
339 	}
340     }
341 }
342