1 /* $Id: pager.c,v 1.1 2004/08/28 19:25:46 dannybackx Exp $ */
2 /****************************************************************************
3 * This module is all new
4 * by Rob Nation
5 ****************************************************************************/
6 /***********************************************************************
7 * The rest of it is all my fault -- MLM
8 * mwm - "LessTif Window Manager"
9 ***********************************************************************/
10
11 #include <LTconfig.h>
12
13 #include <string.h>
14
15 #include <Xm/Xm.h>
16 #include <Xm/MwmUtil.h>
17
18 #include "mwm.h"
19
20
21 Bool pagerOn = True;
22 Bool EnablePagerRedraw = True;
23 Bool DoHandlePageing = True;
24
25 static char *pager_name = "Mwm Pager";
26
27 static XClassHint classhints =
28 {
29 "pager",
30 "Mwm"
31 };
32
33 static XSizeHints sizehints =
34 {
35 (PMinSize | PResizeInc | PBaseSize | PWinGravity),
36 0, 0, 100, 100, /* x, y, width and height */
37 1, 1, /* Min width and height */
38 0, 0, /* Max width and height */
39 1, 1, /* Width and height increments */
40 {0, 0},
41 {0, 0}, /* Aspect ratio - not used */
42 1, 1, /* base size */
43 (NorthWestGravity) /* gravity */
44 };
45
46 /*
47 * draw the lines delimiting the virtual screens
48 */
49 static void
draw_partitions(ScreenInfo * scr)50 draw_partitions(ScreenInfo *scr)
51 {
52 int y, y1, y2, x, x1, x2;
53 int MaxW, MaxH, width, height;
54
55 MaxW = scr->virt_x_max + scr->d_width;
56 MaxH = scr->virt_y_max + scr->d_height;
57
58 width = scr->mwm_pager->frame_width -
59 2 * scr->mwm_pager->boundary_width -
60 2 * scr->mwm_pager->matte_width;
61 height = scr->mwm_pager->frame_height -
62 scr->mwm_pager->title_height -
63 2 * scr->mwm_pager->boundary_width -
64 2 * scr->mwm_pager->matte_width;
65
66 x = scr->d_width;
67 y1 = 0;
68 y2 = height;
69 while (x < MaxW)
70 {
71 x1 = x * width / MaxW;
72 XDrawLine(dpy, scr->pager_win,
73 scr->components[MWM_PAGER].normal_GC, x1, y1, x1, y2);
74 x += scr->d_width;
75 }
76
77 y = scr->d_height;
78 x1 = 0;
79 x2 = width;
80 while (y < MaxH)
81 {
82 y1 = y * height / MaxH;
83 XDrawLine(dpy, scr->pager_win,
84 scr->components[MWM_PAGER].normal_GC, x1, y1, x2, y1);
85 y += scr->d_height;
86 }
87 }
88
89 /*
90 * clear the pager area. This will cause the pager to be redrawn.
91 */
92 void
PAGER_Clear(ScreenInfo * scr)93 PAGER_Clear(ScreenInfo *scr)
94 {
95 if ((scr->mwm_pager) && (EnablePagerRedraw))
96 XClearArea(dpy, scr->pager_win, 0, 0, scr->mwm_pager->frame_width,
97 scr->mwm_pager->frame_height, True);
98 }
99
100 /*
101 * redraw the pager: we try to be clever - re-draw the pager by causing
102 * an expose event, so that the redraw occurs when the expose arrives.
103 * The advantage is that the number of re-draws will be minimized.
104 */
105 void
PAGER_Redraw(ScreenInfo * scr)106 PAGER_Redraw(ScreenInfo *scr)
107 {
108 MwmWindow *t;
109
110 if (!scr->mwm_pager)
111 return;
112
113 MISC_FlushExpose(scr->pager_win);
114 MISC_FlushExpose(scr->pager_child_win);
115
116 if (scr->components[MWM_PAGER].f_height > 0)
117 {
118 if (scr->mwm_highlight != NULL)
119 {
120 if (!(scr->mwm_highlight->flags & STICKY) &&
121 (scr->mwm_highlight->icon_label != NULL))
122 {
123 MISC_FlushExpose(scr->mwm_highlight->pager_view);
124 XDrawImageString(dpy, scr->mwm_highlight->pager_view,
125 scr->components[MWM_PAGER].normal_GC,
126 2, scr->components[MWM_PAGER].f_y + 2,
127 scr->mwm_highlight->icon_label,
128 strlen(scr->mwm_highlight->icon_label));
129 }
130 }
131
132 for (t = scr->mwm_root.next; t != NULL; t = t->next)
133 {
134 if (t != scr->mwm_highlight)
135 {
136 if (!(t->flags & STICKY) &&
137 (t->icon_label != NULL))
138 {
139 MISC_FlushExpose(t->pager_view);
140 XDrawImageString(dpy, t->pager_view,
141 scr->components[MWM_PAGER].normal_GC,
142 2, scr->components[MWM_PAGER].f_y + 2,
143 t->icon_label, strlen(t->icon_label));
144 }
145 }
146 }
147 }
148 draw_partitions(scr);
149 }
150
151 /*
152 * update the child. MLM -- I'm still not sure what this is.
153 */
154 void
PAGER_UpdateViewPort(ScreenInfo * scr)155 PAGER_UpdateViewPort(ScreenInfo *scr)
156 {
157 int width, height, x1, x2, y1, y2;
158
159 if ((scr->pager_child_win) && (scr->mwm_pager))
160 {
161 width = scr->mwm_pager->frame_width -
162 2 * scr->mwm_pager->boundary_width -
163 2 * scr->mwm_pager->matte_width;
164 height = scr->mwm_pager->frame_height -
165 scr->mwm_pager->title_height -
166 2 * scr->mwm_pager->boundary_width -
167 2 * scr->mwm_pager->matte_width;
168 x1 = scr->virt_x * width / (scr->virt_x_max + scr->d_width) + 1;
169 y1 = scr->virt_y * height / (scr->virt_y_max + scr->d_height) + 1;
170 x2 = (scr->d_width) * width / (scr->virt_x_max + scr->d_width) - 1;
171 y2 = (scr->d_height) * height / (scr->virt_y_max + scr->d_height) - 1;
172 if (x1 == 1)
173 {
174 x1--;
175 x2++;
176 }
177 if (y1 == 1)
178 {
179 y1--;
180 y2++;
181 }
182 XMoveResizeWindow(dpy, scr->pager_child_win, x1, y1, x2, y2);
183 }
184 }
185
186 /*
187 * update the pager view
188 */
189 void
PAGER_UpdateView(ScreenInfo * scr,MwmWindow * t)190 PAGER_UpdateView(ScreenInfo *scr, MwmWindow *t)
191 {
192 unsigned int width, height;
193 int ww, wh;
194 int wx, wy;
195 int MaxH, MaxW;
196
197 if ((!scr->mwm_pager) || (!pagerOn))
198 return;
199
200 width = scr->mwm_pager->frame_width -
201 2 * scr->mwm_pager->boundary_width -
202 2 * scr->mwm_pager->matte_width;
203 height = scr->mwm_pager->frame_height -
204 scr->mwm_pager->title_height -
205 2 * scr->mwm_pager->boundary_width -
206 2 * scr->mwm_pager->matte_width;
207
208 MaxW = scr->virt_x_max + scr->d_width;
209 MaxH = scr->virt_y_max + scr->d_height;
210
211 if ((!(t->flags & STICKY)) &&
212 (!((t->flags & ICONIFIED) && (t->flags & ICON_UNMAPPED))) &&
213 (t->Desk == scr->current_desk))
214 {
215 if (t->flags & ICONIFIED)
216 {
217 /* show the icon loc */
218 wx = (t->icon_x_loc + scr->virt_x) * (int)width / MaxW;;
219 wy = (t->icon_y_loc + scr->virt_y) * (int)height / MaxH;
220 ww = t->icon_w_width * (int)width / MaxW;
221 wh = (t->icon_w_height + t->icon_p_height) * (int)height / MaxH;
222 }
223 else
224 {
225 /* show the actual window */
226 wx = (t->frame_x + scr->virt_x) * (int)width / MaxW;
227 wy = (t->frame_y + scr->virt_y) * (int)height / MaxH;
228 ww = t->frame_width * (int)width / MaxW;
229 wh = t->frame_height * (int)height / MaxH;
230 }
231 if (ww < 2)
232 ww = 2;
233 if (wh < 2)
234 wh = 2;
235 XMoveResizeWindow(dpy, t->pager_view, wx, wy, ww, wh);
236 }
237 else
238 {
239 /* window is sticky - make sure that the pager_view window is not
240 * visible */
241 XMoveResizeWindow(dpy, t->pager_view, -10, -10, 5, 5);
242 }
243
244 PAGER_Clear(scr);
245 }
246
247 /*
248 * Moves the viewport within thwe virtual desktop
249 */
250 void
PAGER_MoveViewPort(ScreenInfo * scr,int newx,int newy,Boolean grab)251 PAGER_MoveViewPort(ScreenInfo *scr, int newx, int newy, Boolean grab)
252 {
253 MwmWindow *t;
254 int deltax, deltay;
255 XEvent oevent;
256
257 if (grab)
258 XGrabServer(dpy);
259
260 if (newx > scr->virt_x_max)
261 newx = scr->virt_x_max;
262 if (newy > scr->virt_y_max)
263 newy = scr->virt_y_max;
264 if (newx < 0)
265 newx = 0;
266 if (newy < 0)
267 newy = 0;
268
269 deltay = scr->virt_y - newy;
270 deltax = scr->virt_x - newx;
271
272 scr->virt_x = newx;
273 scr->virt_y = newy;
274
275 if ((deltax != 0) || (deltay != 0))
276 {
277 for (t = scr->mwm_root.next; t != NULL; t = t->next)
278 {
279 /* If the window is iconified, and sticky Icons is set,
280 * then the window should essentially be sticky */
281 if (!(t->flags & STICKY))
282 {
283 t->icon_x_loc += deltax;
284 t->icon_xl_loc += deltax;
285 t->icon_y_loc += deltay;
286
287 if (t->icon_pixmap_w != None)
288 XMoveWindow(dpy, t->icon_pixmap_w, t->icon_x_loc,
289 t->icon_y_loc);
290 if (t->icon_w != None)
291 XMoveWindow(dpy, t->icon_w, t->icon_x_loc,
292 t->icon_y_loc + t->icon_p_height);
293
294 DEC_ConfigureDecorations(scr, t,
295 t->frame_x + deltax,
296 t->frame_y + deltay,
297 t->frame_width, t->frame_height,
298 False);
299 }
300 }
301 for (t = scr->mwm_root.next; t != NULL; t = t->next)
302 {
303 /* If its an icon, and its sticking, autoplace it so
304 * that it doesn't wind up on top a a stationary
305 * icon */
306 if ((t->flags & STICKY) &&
307 (t->flags & ICONIFIED) && (!(t->flags & ICON_MOVED)) &&
308 (!(t->flags & ICON_UNMAPPED)))
309 ICON_AutoPlace(scr, t);
310 }
311
312 }
313 /* fix up the viewport indicator */
314 PAGER_UpdateViewPort(scr);
315 PAN_CheckBounds(scr);
316
317 /* do this with PanFrames too ??? HEDU */
318 while (XCheckTypedEvent(dpy, MotionNotify, &oevent))
319 MISC_StashEventTime(&oevent);
320 if (grab)
321 XUngrabServer(dpy);
322 }
323
324 /*
325 * switch among pages
326 */
327 void
PAGER_SwitchPage(ScreenInfo * scr,Bool align,Bool ChangeFocus,XEvent * event)328 PAGER_SwitchPage(ScreenInfo *scr, Bool align, Bool ChangeFocus, XEvent *event)
329 {
330 int x, y;
331 unsigned int width, height;
332 MwmWindow *tmp_win;
333 Window dumwin;
334
335 if (!scr->mwm_pager)
336 return;
337
338 XTranslateCoordinates(dpy, event->xbutton.window, scr->pager_win,
339 event->xbutton.x, event->xbutton.y, &x, &y, &dumwin);
340
341 width = scr->mwm_pager->frame_width -
342 2 * scr->mwm_pager->boundary_width -
343 2 * scr->mwm_pager->matte_width;
344 height = scr->mwm_pager->frame_height -
345 scr->mwm_pager->title_height -
346 2 * scr->mwm_pager->boundary_width -
347 2 * scr->mwm_pager->matte_width;
348
349 if (x < 0)
350 x = 0;
351 if (y < 0)
352 y = 0;
353 x = x * (scr->virt_x_max + scr->d_width) / width;
354 y = y * (scr->virt_y_max + scr->d_height) / height;
355 if (align)
356 {
357 x = (x / scr->d_width) * scr->d_width;
358 y = (y / scr->d_height) * scr->d_height;
359 }
360 if (x < 0)
361 x = 0;
362 if (y < 0)
363 y = 0;
364 PAGER_MoveViewPort(scr, x, y, True);
365 if ((ChangeFocus) &&
366 (Mwm.keyboard_focus_policy == XmEXPLICIT &&
367 Mwm.auto_key_focus))
368 {
369 tmp_win = WIN_WindowToStruct(scr, event->xbutton.subwindow);
370 if (tmp_win)
371 {
372 WIN_Raise(scr, tmp_win);
373 WIN_SetFocusInTree(tmp_win);
374 WIN_SetFocus(scr, tmp_win->w, tmp_win);
375 MISC_SetFocusSequence(scr);
376 }
377 }
378 }
379
380 /*
381 * creates the pager window, if needed
382 */
383 void
PAGER_Initialize(ScreenInfo * scr,Position x,Position y)384 PAGER_Initialize(ScreenInfo *scr, Position x, Position y)
385 {
386 XTextProperty name;
387 int width, height, window_x, window_y;
388 unsigned long valuemask;
389 XSetWindowAttributes attributes;
390
391 width = (scr->virt_x_max + scr->d_width) / scr->virt_scale;
392 height = (scr->virt_y_max + scr->d_height) / scr->virt_scale;
393
394 if (x >= 0)
395 window_x = x;
396 else
397 {
398 sizehints.win_gravity = NorthEastGravity;
399 window_x = scr->d_width - width + x - 2;
400 }
401
402 if (y >= 0)
403 window_y = y;
404 else
405 {
406 window_y = scr->d_height - height + y - 2;
407 if (x < 0)
408 sizehints.win_gravity = SouthEastGravity;
409 else
410 sizehints.win_gravity = SouthWestGravity;
411 }
412 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
413 attributes.background_pixel = scr->components[MWM_PAGER].background;
414 attributes.border_pixel = scr->components[MWM_PAGER].background;
415 attributes.cursor = scr->cursors[DEFAULT_CURS];
416 attributes.event_mask = (ExposureMask | EnterWindowMask | ButtonReleaseMask |
417 ButtonMotionMask);
418 sizehints.width = width;
419 sizehints.height = height;
420 sizehints.x = window_x;
421 sizehints.y = window_y;
422
423 scr->pager_win = XCreateWindow(dpy, scr->root_win, window_x, window_y, width,
424 height, (unsigned int)1,
425 CopyFromParent, InputOutput,
426 (Visual *)CopyFromParent,
427 valuemask, &attributes);
428 XSetWMNormalHints(dpy, scr->pager_win, &sizehints);
429 XStringListToTextProperty(&pager_name, 1, &name);
430 XSetWMName(dpy, scr->pager_win, &name);
431 XSetWMIconName(dpy, scr->pager_win, &name);
432 XSetClassHint(dpy, scr->pager_win, &classhints);
433 XFree((char *)name.value);
434
435 attributes.event_mask = KeyPressMask | ExposureMask;
436 attributes.background_pixel = scr->components[MWM_PAGER].background;
437 attributes.cursor = scr->cursors[DEFAULT_CURS];
438 scr->pager_child_win = XCreateWindow(dpy, scr->pager_win, -10, -10, 10, 10, 0,
439 CopyFromParent,
440 InputOutput, CopyFromParent,
441 CWEventMask | CWBackPixel | CWCursor,
442 &attributes);
443 XStoreName(dpy, scr->pager_child_win, "PagerChildWin");
444 XMapRaised(dpy, scr->pager_child_win);
445 }
446
447 /*
448 * move a window via the pager
449 */
450 void
PAGER_Update(ScreenInfo * scr,XEvent * event)451 PAGER_Update(ScreenInfo *scr, XEvent *event)
452 {
453 MwmWindow *tmp_win;
454 unsigned int width, height;
455 int Xoff, Yoff, x, y, MaxW, MaxH, xl, yt, xl1, yt1;
456 Window target;
457 Bool done, finished = False;
458 XEvent oevent = *event;
459
460 /* I tried to implement a feature so that when windows which could be
461 * opaque moved in a normal move would get the full size windows moved in
462 * conjunction with the pager version of the window, but it seems to
463 * be buggy on some machines */
464 #ifdef BROKEN_STUFF
465 Bool OpaqueMove = False;
466 int dwidth, dheight;
467
468 #endif
469 if (!scr->mwm_pager)
470 return;
471
472 EnablePagerRedraw = False;
473 target = oevent.xbutton.subwindow;
474 tmp_win = WIN_WindowToStruct(scr, target);
475
476 if (tmp_win == NULL)
477 return;
478
479
480 MaxW = scr->virt_x_max + scr->d_width;
481 MaxH = scr->virt_y_max + scr->d_height;
482
483 width = scr->mwm_pager->frame_width -
484 2 * scr->mwm_pager->boundary_width -
485 2 * scr->mwm_pager->matte_width;
486 height = scr->mwm_pager->frame_height -
487 scr->mwm_pager->title_height -
488 2 * scr->mwm_pager->boundary_width -
489 2 * scr->mwm_pager->matte_width;
490
491 XQueryPointer(dpy, target, &JunkRoot, &JunkChild,
492 &JunkX, &JunkY, &Xoff, &Yoff, &JunkMask);
493
494 XQueryPointer(dpy, scr->pager_win, &JunkRoot, &JunkChild,
495 &JunkX, &JunkY, &xl, &yt, &JunkMask);
496 if (xl < 0)
497 xl = 0;
498 if (yt < 0)
499 yt = 0;
500 if (xl > width)
501 xl = width;
502 if (yt > height)
503 yt = height;
504 xl -= Xoff;
505 yt -= Yoff;
506 xl1 = xl;
507 yt1 = yt;
508
509 while (!finished)
510 {
511 /* block until there is an interesting event */
512 XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask | KeyPressMask |
513 PointerMotionMask | ButtonMotionMask | ExposureMask |
514 VisibilityChangeMask, &oevent);
515 MISC_StashEventTime(&oevent);
516
517 if (oevent.type == MotionNotify)
518 /* discard any extra motion events before a logical release */
519 while (XCheckMaskEvent(dpy, PointerMotionMask | ButtonMotionMask |
520 ButtonRelease, &oevent))
521 {
522 MISC_StashEventTime(&oevent);
523 if (oevent.type == ButtonRelease)
524 break;
525 }
526
527 done = False;
528
529 /* Handle a limited number of key press events to allow mouseless
530 * operation */
531 if (oevent.type == KeyPress)
532 MISC_KeyboardShortcut(scr, &oevent, ButtonRelease);
533 switch (oevent.type)
534 {
535 case ButtonPress:
536 case KeyPress:
537 /* throw away enter and leave events until release */
538 done = True;
539 break;
540 case ButtonRelease:
541 XQueryPointer(dpy, scr->pager_win, &JunkRoot, &JunkChild,
542 &JunkX, &JunkY, &xl, &yt, &JunkMask);
543 if (xl < 0)
544 xl = 0;
545 if (yt < 0)
546 yt = 0;
547 if (xl > width)
548 xl = width;
549 if (yt > height)
550 yt = height;
551 xl -= Xoff;
552 yt -= Yoff;
553 done = True;
554 finished = True;
555 break;
556
557 case MotionNotify:
558 XQueryPointer(dpy, scr->pager_win, &JunkRoot, &JunkChild,
559 &JunkX, &JunkY, &xl, &yt, &JunkMask);
560 if (xl < 0)
561 xl = 0;
562 if (yt < 0)
563 yt = 0;
564 if (xl > width)
565 xl = width;
566 if (yt > height)
567 yt = height;
568
569 /* redraw the rubberband */
570 xl -= Xoff;
571 yt -= Yoff;
572
573 done = True;
574 break;
575
576 default:
577 break;
578 }
579 if (!done)
580 {
581 EVENT_Dispatch(&oevent);
582 }
583 XMoveWindow(dpy, target, xl, yt);
584 draw_partitions(scr);
585
586 }
587
588 x = xl * MaxW / (int)width - scr->virt_x;
589 y = yt * MaxH / (int)height - scr->virt_y;
590
591 PAGER_UpdateView(scr, tmp_win);
592 if ((xl1 != xl) || (yt1 != yt))
593 {
594 if ((tmp_win->flags & ICONIFIED))
595 {
596 tmp_win->icon_x_loc = x;
597 tmp_win->icon_xl_loc = x -
598 (tmp_win->icon_w_width - tmp_win->icon_p_width) / 2;
599 tmp_win->icon_y_loc = y;
600 XMoveWindow(dpy, tmp_win->icon_w, tmp_win->icon_xl_loc, y + tmp_win->icon_p_height);
601
602 if (tmp_win->icon_pixmap_w != None)
603 XMoveWindow(dpy, tmp_win->icon_pixmap_w, x, y);
604
605 tmp_win->flags |= ICON_MOVED;
606
607 }
608 else
609 {
610 /* show the actual window */
611 DEC_ConfigureDecorations(scr, tmp_win, x, y, tmp_win->frame_width, tmp_win->frame_height, False);
612 }
613 }
614 EnablePagerRedraw = True;
615 PAGER_Clear(scr);
616 }
617