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