Restructure how we look for Read files slightly.
[fvwm.git] / modules / FvwmPager / x_pager.c
blob71a5286f7e973c6129bf57addcbdfb0faec82648
1 /* -*-c-*- */
2 /*
3 * This module is all new
4 * by Rob Nation
5 */
7 /* This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * fvwm pager handling code
28 #include "config.h"
30 #include <stdio.h>
31 #include <signal.h>
33 #include <X11/Xlib.h>
34 #include <X11/Xutil.h>
35 #include <X11/Xproto.h>
36 #include <X11/Xatom.h>
37 #include <X11/Intrinsic.h>
38 #include <X11/keysym.h>
40 #include "libs/fvwmlib.h"
41 #include "libs/FScreen.h"
42 #include "libs/FShape.h"
43 #include "libs/Module.h"
44 #include "libs/Colorset.h"
45 #include "libs/Graphics.h"
46 #include "fvwm/fvwm.h"
47 #include "libs/PictureGraphics.h"
48 #include "FvwmPager.h"
51 extern ScreenInfo Scr;
52 extern Display *dpy;
54 Pixel back_pix, fore_pix, hi_pix;
55 Pixel focus_pix;
56 Pixel focus_fore_pix;
57 extern int windowcolorset, activecolorset;
58 extern Pixel win_back_pix, win_fore_pix, win_hi_back_pix, win_hi_fore_pix;
59 extern Bool win_pix_set, win_hi_pix_set;
60 extern int window_w, window_h,window_x,window_y,usposition,uselabel,xneg,yneg;
61 extern int StartIconic;
62 extern int MiniIcons;
63 extern int LabelsBelow;
64 extern int ShapeLabels;
65 extern int ShowBalloons, ShowPagerBalloons, ShowIconBalloons;
66 extern char *BalloonFormatString;
67 extern char *WindowLabelFormat;
68 extern char *PagerFore, *PagerBack, *HilightC;
69 extern char *BalloonFore, *BalloonBack, *BalloonBorderColor;
70 extern Window BalloonView;
71 extern unsigned int WindowBorderWidth;
72 extern unsigned int MinSize;
73 extern Bool WindowBorders3d;
74 extern Bool UseSkipList;
75 extern FvwmPicture *PixmapBack;
76 extern FvwmPicture *HilightPixmap;
77 extern int HilightDesks;
78 extern char fAlwaysCurrentDesk;
80 extern int MoveThreshold;
82 extern int icon_w, icon_h, icon_x, icon_y, icon_xneg, icon_yneg;
83 FlocaleFont *Ffont, *FwindowFont;
84 FlocaleWinString *FwinString;
86 extern PagerWindow *Start;
87 extern PagerWindow *FocusWin;
88 static Atom wm_del_win;
90 extern char *MyName;
92 extern int desk1, desk2, ndesks;
93 extern int Rows,Columns;
94 extern int fd[2];
96 int desk_w = 0;
97 int desk_h = 0;
98 int label_h = 0;
100 DeskInfo *Desks;
101 int Wait = 0;
102 int FvwmErrorHandler(Display *, XErrorEvent *);
103 extern Bool is_transient;
104 extern Bool do_ignore_next_button_release;
105 extern Bool use_dashed_separators;
106 extern Bool use_no_separators;
109 /* assorted gray bitmaps for decorative borders */
110 #define g_width 2
111 #define g_height 2
112 static char g_bits[] = {0x02, 0x01};
114 #define l_g_width 4
115 #define l_g_height 2
116 static char l_g_bits[] = {0x08, 0x02};
118 #define s_g_width 4
119 #define s_g_height 4
120 static char s_g_bits[] = {0x01, 0x02, 0x04, 0x08};
123 Window icon_win; /* icon window */
125 static int MyVx, MyVy; /* copy of Scr.Vx/y for drag logic */
127 static char *GetBalloonLabel(const PagerWindow *pw,const char *fmt);
128 extern void ExitPager(void);
130 Pixmap default_pixmap = None;
132 #ifdef DEBUG
133 #define MYFPRINTF(X) \
134 fprintf X;\
135 fflush (stderr);
136 #else
137 #define MYFPRINTF(X)
138 #endif
141 #define MAX_UNPROCESSED_MESSAGES 1
142 /* sums up pixels to scroll. If do_send_message is True a Scroll command is
143 * sent back to fvwm. The function shall be called with is_message_recieved
144 * True when the Scroll command has been processed by fvwm. This is checked
145 * by talking to ourself. */
146 static void do_scroll(int sx, int sy, Bool do_send_message,
147 Bool is_message_recieved)
149 static int psx = 0;
150 static int psy = 0;
151 static int messages_sent = 0;
152 char command[256];
153 psx+=sx;
154 psy+=sy;
155 if (is_message_recieved)
157 /* There might be other modules with the same name, or someone
158 might send ScrollDone other than the module, so just treat
159 any negative count as zero. */
160 if (--messages_sent < 0)
162 messages_sent = 0;
165 if ((do_send_message || messages_sent < MAX_UNPROCESSED_MESSAGES) &&
166 ( psx != 0 || psy != 0 ))
168 sprintf(command, "Scroll %dp %dp", psx, psy);
169 SendText(fd, command, 0);
170 messages_sent++;
171 SendText(fd, "Send_Reply ScrollDone", 0);
172 psx = 0;
173 psy = 0;
177 void HandleScrollDone(void)
179 do_scroll(0, 0, True, True);
182 /* discard certain events on a window */
183 static void discard_events(long event_type, Window w, XEvent *last_ev)
185 XEvent e;
187 XSync(dpy, 0);
188 while (FCheckTypedWindowEvent(dpy, w, event_type, &e))
190 /* do nothing */
191 if (last_ev)
193 memcpy(last_ev, &e, sizeof(XEvent));
197 return;
202 * Procedure:
203 * CalcGeom - calculates the size and position of a mini-window
204 * given the real window size.
205 * You can always tell bad code by the size of the comments.
207 static void CalcGeom(PagerWindow *t, int win_w, int win_h,
208 int *x_ret, int *y_ret, int *w_ret, int *h_ret)
210 int virt, virt2, edge, edge2, size, page, over;
212 /* coordinate of left hand edge on virtual desktop */
213 virt = Scr.Vx + t->x;
215 /* position of left hand edge of mini-window on pager window */
216 edge = (virt * win_w) / Scr.VWidth;
218 /* absolute coordinate of right hand edge on virtual desktop */
219 virt += t->width - 1;
221 /* to calculate the right edge, mirror the window and use the same
222 * calculations as for the left edge for consistency. */
223 virt2 = Scr.VWidth - 1 - virt;
224 edge2 = (virt2 * win_w) / Scr.VWidth;
226 /* then mirror it back to get the real coordinate */
227 edge2 = win_w - 1 - edge2;
229 /* Calculate the mini-window's width by subtracting its LHS
230 * from its RHS. This theoretically means that the width will
231 * vary slightly as the window travels around the screen, but
232 * this way ensures that the mini-windows in the pager match
233 * the actual screen layout. */
234 size = edge2 - edge + 1;
236 /* Make size big enough to be visible */
237 if (size < MinSize) {
238 size = MinSize;
239 /* this mini-window has to be grown to be visible
240 * which way it grows depends on some magic:
241 * normally it will grow right but if the window is on the right hand
242 * edge of a page it should be grown left so that the pager looks better */
244 /* work out the page that the right hand edge is on */
245 page = virt / Scr.MyDisplayWidth;
247 /* if the left edge is on the same page then possibly move it left */
248 if (page == ((virt - t->width + 1) / Scr.MyDisplayWidth)) {
249 /* calculate how far the mini-window right edge overlaps the page line */
250 /* beware that the "over" is actually one greater than on screen, but
251 this discrepancy is catered for in the next two lines */
252 over = edge + size - ((page + 1) * win_w * Scr.MyDisplayWidth) /
253 Scr.VWidth;
255 /* if the mini-window right edge is beyond the mini-window pager grid */
256 if (over > 0) {
257 /* move it left by the amount of pager grid overlap (!== the growth) */
258 edge -= over;
262 /* fill in return values */
263 *x_ret = edge;
264 *w_ret = size;
266 /* same code for y axis */
267 virt = Scr.Vy + t->y;
268 edge = (virt * win_h) / Scr.VHeight;
269 virt += t->height - 1;
270 virt2 = Scr.VHeight - 1 - virt;
271 edge2 = (virt2 * win_h) / Scr.VHeight;
272 edge2 = win_h - 1 - edge2;
273 size = edge2 - edge + 1;
274 if (size < MinSize)
276 size = MinSize;
277 page = virt / Scr.MyDisplayHeight;
278 if (page == ((virt - t->height + 1) / Scr.MyDisplayHeight)) {
279 over = edge + size - ((page + 1) * win_h * Scr.MyDisplayHeight) /
280 Scr.VHeight;
281 if (over > 0)
282 edge -= over;
285 *y_ret = edge;
286 *h_ret = size;
291 * Procedure:
292 * Initialize_viz_pager - creates a temp window of the correct visual
293 * so that pixmaps may be created for use with the main window
295 void initialize_viz_pager(void)
297 XSetWindowAttributes attr;
298 XGCValues xgcv;
300 /* FIXME: I think that we only need that Pdepth ==
301 * DefaultDepth(dpy, Scr.screen) to use the Scr.Root for Scr.Pager_w */
302 if (Pdefault)
304 Scr.Pager_w = Scr.Root;
306 else
308 attr.background_pixmap = None;
309 attr.border_pixel = 0;
310 attr.colormap = Pcmap;
311 Scr.Pager_w = XCreateWindow(
312 dpy, Scr.Root, -10, -10, 10, 10, 0, Pdepth,
313 InputOutput, Pvisual,
314 CWBackPixmap|CWBorderPixel|CWColormap, &attr);
315 Scr.NormalGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, 0, &xgcv);
317 Scr.NormalGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, 0, NULL);
319 xgcv.plane_mask = AllPlanes;
320 Scr.MiniIconGC = fvwmlib_XCreateGC(
321 dpy, Scr.Pager_w, GCPlaneMask, &xgcv);
322 Scr.black = GetColor("Black");
324 /* Transparent background are only allowed when the depth matched the
325 * root */
326 if (Pdepth == DefaultDepth(dpy, Scr.screen))
328 default_pixmap = ParentRelative;
331 return;
334 /* see also change colorset */
335 void draw_desk_background(int i, int page_w, int page_h)
337 if (Desks[i].colorset > -1)
339 XSetWindowBorder(
340 dpy, Desks[i].title_w, Colorset[Desks[i].colorset].fg);
341 XSetWindowBorder(
342 dpy, Desks[i].w, Colorset[Desks[i].colorset].fg);
343 XSetForeground(
344 dpy, Desks[i].NormalGC,Colorset[Desks[i].colorset].fg);
345 XSetForeground(
346 dpy, Desks[i].DashedGC,Colorset[Desks[i].colorset].fg);
347 if (uselabel)
349 if (CSET_IS_TRANSPARENT(Desks[i].colorset))
351 SetWindowBackground(
352 dpy, Desks[i].title_w,
353 desk_w, label_h,
354 &Colorset[Desks[i].colorset],
355 Pdepth,
356 Scr.NormalGC, True);
358 else
360 SetWindowBackground(
361 dpy, Desks[i].title_w, desk_w,
362 desk_h + label_h,
363 &Colorset[Desks[i].colorset], Pdepth,
364 Scr.NormalGC, True);
367 if (label_h != 0 && uselabel && !LabelsBelow &&
368 !CSET_IS_TRANSPARENT(Desks[i].colorset))
370 SetWindowBackgroundWithOffset(
371 dpy, Desks[i].w, 0, -label_h, desk_w,
372 desk_h + label_h, &Colorset[Desks[i].colorset],
373 Pdepth, Scr.NormalGC, True);
375 else
377 if (CSET_IS_TRANSPARENT(Desks[i].colorset))
379 SetWindowBackground(
380 dpy, Desks[i].w, desk_w, desk_h,
381 &Colorset[Desks[i].colorset], Pdepth,
382 Scr.NormalGC, True);
384 else
386 SetWindowBackground(
387 dpy, Desks[i].w, desk_w,
388 desk_h + label_h,
389 &Colorset[Desks[i].colorset],
390 Pdepth, Scr.NormalGC, True);
394 XClearArea(dpy,Desks[i].w, 0, 0, 0, 0,True);
395 if (Desks[i].highcolorset > -1)
397 XSetForeground(
398 dpy, Desks[i].HiliteGC,
399 Colorset[Desks[i].highcolorset].bg);
400 XSetForeground(
401 dpy, Desks[i].rvGC, Colorset[Desks[i].highcolorset].fg);
402 if (HilightDesks)
404 SetWindowBackground(
405 dpy, Desks[i].CPagerWin, page_w, page_h,
406 &Colorset[Desks[i].highcolorset], Pdepth,
407 Scr.NormalGC, True);
410 if (uselabel)
412 XClearArea(dpy,Desks[i].title_w, 0, 0, 0, 0,True);
415 return;
420 * Procedure:
421 * Initialize_pager - creates the pager window, if needed
423 * Inputs:
424 * x,y location of the window
427 char *pager_name = "Fvwm Pager";
428 XSizeHints sizehints =
430 (PMinSize | PResizeInc | PBaseSize | PWinGravity),
431 0, 0, 100, 100, /* x, y, width and height */
432 1, 1, /* Min width and height */
433 0, 0, /* Max width and height */
434 1, 1, /* Width and height increments */
435 {0, 0}, {0, 0}, /* Aspect ratio - not used */
436 1, 1, /* base size */
437 (NorthWestGravity) /* gravity */
440 void initialize_balloon_window(void)
442 XGCValues xgcv;
443 unsigned long valuemask;
444 XSetWindowAttributes attributes;
445 extern int BalloonBorderWidth;
447 /* create balloon window
448 -- ric@giccs.georgetown.edu */
449 if (!ShowBalloons)
451 Scr.balloon_w = None;
452 return;
454 valuemask = CWOverrideRedirect | CWEventMask | CWColormap;
455 /* tell WM to ignore this window */
456 attributes.override_redirect = True;
457 attributes.event_mask = ExposureMask;
458 attributes.colormap = Pcmap;
459 /* now create the window */
460 Scr.balloon_w = XCreateWindow(
461 dpy, Scr.Root, 0, 0, /* coords set later */ 1, 1,
462 BalloonBorderWidth, Pdepth, InputOutput, Pvisual, valuemask,
463 &attributes);
464 Scr.balloon_gc = fvwmlib_XCreateGC(dpy, Scr.balloon_w, 0, &xgcv);
465 /* Make sure we don't get balloons initially with the Icon option. */
466 ShowBalloons = ShowPagerBalloons;
468 return;
471 void initialize_pager(void)
473 XWMHints wmhints;
474 XClassHint class1;
475 XTextProperty name;
476 unsigned long valuemask;
477 XSetWindowAttributes attributes;
478 extern char *WindowBack, *WindowFore, *WindowHiBack, *WindowHiFore;
479 extern char *BalloonFont;
480 extern char *font_string, *smallFont;
481 int n,m,w,h,i,x,y;
482 XGCValues gcv;
483 char dash_list[2];
484 FlocaleFont *balloon_font;
486 /* I don't think that this is necessary - just let pager die */
487 /* domivogt (07-mar-1999): But it is! A window being moved in the pager
488 * might die at any moment causing the Xlib calls to generate BadMatch
489 * errors. Without an error handler the pager will die! */
490 XSetErrorHandler(FvwmErrorHandler);
492 wm_del_win = XInternAtom(dpy,"WM_DELETE_WINDOW",False);
494 /* load the font */
495 /* Note: "font" is always created, whether labels are used or not
496 because a GC below is set to use a font. dje Dec 2001.
497 OK, I fixed the GC below, but now something else is blowing up.
498 Right now, I've got to do some Real Life stuff, so this kludge is
499 in place, its still better than I found it.
500 I hope that I've fixed this (olicha)
502 Ffont = FlocaleLoadFont(dpy, font_string, MyName);
504 label_h = (uselabel) ? Ffont->height + 2 : 0;
506 /* init our Flocale window string */
507 FlocaleAllocateWinString(&FwinString);
509 /* Check that shape extension exists. */
510 if (FHaveShapeExtension && ShapeLabels)
512 ShapeLabels = (FShapesSupported) ? 1 : 0;
515 if(smallFont != NULL)
517 FwindowFont = FlocaleLoadFont(dpy, smallFont, MyName);
520 /* Load the colors */
521 fore_pix = GetColor(PagerFore);
522 back_pix = GetColor(PagerBack);
523 hi_pix = GetColor(HilightC);
525 if (windowcolorset >= 0)
527 win_back_pix = Colorset[windowcolorset].bg;
528 win_fore_pix = Colorset[windowcolorset].fg;
529 win_pix_set = True;
531 else if (WindowBack && WindowFore)
533 win_back_pix = GetColor(WindowBack);
534 win_fore_pix = GetColor(WindowFore);
535 win_pix_set = True;
538 if (activecolorset >= 0)
540 win_hi_back_pix = Colorset[activecolorset].bg;
541 win_hi_fore_pix = Colorset[activecolorset].fg;
542 win_hi_pix_set = True;
544 else if (WindowHiBack && WindowHiFore)
546 win_hi_back_pix = GetColor(WindowHiBack);
547 win_hi_fore_pix = GetColor(WindowHiFore);
548 win_hi_pix_set = True;
551 /* Load pixmaps for mono use */
552 if(Pdepth<2)
554 Scr.gray_pixmap =
555 XCreatePixmapFromBitmapData(dpy,Scr.Pager_w,g_bits, g_width,g_height,
556 fore_pix,back_pix,Pdepth);
557 Scr.light_gray_pixmap =
558 XCreatePixmapFromBitmapData(dpy,Scr.Pager_w,l_g_bits,l_g_width,
559 l_g_height,
560 fore_pix,back_pix,Pdepth);
561 Scr.sticky_gray_pixmap =
562 XCreatePixmapFromBitmapData(dpy,Scr.Pager_w,s_g_bits,s_g_width,
563 s_g_height,
564 fore_pix,back_pix,Pdepth);
568 n = Scr.VxMax / Scr.MyDisplayWidth;
569 m = Scr.VyMax / Scr.MyDisplayHeight;
571 /* Size the window */
572 if(Rows < 0)
574 if(Columns < 0)
576 Columns = ndesks;
577 Rows = 1;
579 else
581 Rows = ndesks/Columns;
582 if(Rows*Columns < ndesks)
583 Rows++;
586 if(Columns < 0)
588 if (Rows == 0)
589 Rows = 1;
590 Columns = ndesks/Rows;
591 if(Rows*Columns < ndesks)
592 Columns++;
595 if(Rows*Columns < ndesks)
597 if (Columns == 0)
598 Columns = 1;
599 Rows = ndesks/Columns;
600 if (Rows*Columns < ndesks)
601 Rows++;
604 sizehints.width_inc = Columns*(n+1);
605 sizehints.height_inc = Rows*(m+1);
606 sizehints.base_width = Columns * n + Columns - 1;
607 sizehints.base_height = Rows * (m + label_h + 1) - 1;
608 if (window_w > 0)
610 window_w = (window_w - sizehints.base_width) / sizehints.width_inc;
611 window_w = window_w * sizehints.width_inc + sizehints.base_width;
613 else
615 window_w = Columns * (Scr.VWidth / Scr.VScale + n) + Columns - 1;
617 if (window_h > 0)
619 window_h = (window_h - sizehints.base_height) / sizehints.height_inc;
620 window_h = window_h * sizehints.height_inc + sizehints.base_height;
622 else
624 window_h = Rows * (Scr.VHeight / Scr.VScale + m + label_h + 1) - 1;
626 desk_w = (window_w - Columns + 1) / Columns;
627 desk_h = (window_h - Rows * label_h - Rows + 1) / Rows;
628 if (is_transient)
630 rectangle screen_g;
631 fscreen_scr_arg fscr;
633 fscr.xypos.x = window_x;
634 fscr.xypos.y = window_y;
635 FScreenGetScrRect(
636 &fscr, FSCREEN_XYPOS,
637 &screen_g.x, &screen_g.y, &screen_g.width, &screen_g.height);
638 if (window_w + window_x > screen_g.x + screen_g.width)
640 window_x = screen_g.x + screen_g.width - Scr.MyDisplayWidth;
641 xneg = 1;
643 if (window_h + window_y > screen_g.y + screen_g.height)
645 window_y = screen_g.y + screen_g.height - Scr.MyDisplayHeight;
646 yneg = 1;
649 if (xneg)
651 sizehints.win_gravity = NorthEastGravity;
652 window_x = Scr.MyDisplayWidth - window_w + window_x;
654 if (yneg)
656 window_y = Scr.MyDisplayHeight - window_h + window_y;
657 if(sizehints.win_gravity == NorthEastGravity)
658 sizehints.win_gravity = SouthEastGravity;
659 else
660 sizehints.win_gravity = SouthWestGravity;
662 sizehints.width = window_w;
663 sizehints.height = window_h;
665 if(usposition)
666 sizehints.flags |= USPosition;
668 valuemask = (CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask);
669 attributes.background_pixmap = default_pixmap;
670 attributes.border_pixel = 0;
671 attributes.colormap = Pcmap;
672 attributes.event_mask = (StructureNotifyMask);
674 /* destroy the temp window first, don't worry if it's the Root */
675 if (Scr.Pager_w != Scr.Root)
676 XDestroyWindow(dpy, Scr.Pager_w);
677 Scr.Pager_w = XCreateWindow (dpy, Scr.Root, window_x, window_y, window_w,
678 window_h, 0, Pdepth, InputOutput, Pvisual,
679 valuemask, &attributes);
680 XSetWMProtocols(dpy,Scr.Pager_w,&wm_del_win,1);
681 /* hack to prevent mapping on wrong screen with StartsOnScreen */
682 FScreenMangleScreenIntoUSPosHints(FSCREEN_XYPOS, &sizehints);
683 XSetWMNormalHints(dpy,Scr.Pager_w,&sizehints);
684 if (is_transient)
686 XSetTransientForHint(dpy, Scr.Pager_w, Scr.Root);
689 if((desk1==desk2)&&(Desks[0].label != NULL))
691 if (FlocaleTextListToTextProperty(
692 dpy, &Desks[0].label, 1, XStdICCTextStyle, &name) == 0)
694 fprintf(stderr,"%s: fatal error: cannot allocate desk name", MyName);
695 exit(0);
698 else
700 if (FlocaleTextListToTextProperty(
701 dpy, &Desks[0].label, 1, XStdICCTextStyle, &name) == 0)
703 fprintf(stderr,"%s: fatal error: cannot allocate pager name", MyName);
704 exit(0);
708 attributes.event_mask = (StructureNotifyMask| ExposureMask);
709 if(icon_w < 1)
710 icon_w = (window_w - Columns+1)/Columns;
711 if(icon_h < 1)
712 icon_h = (window_h - Rows* label_h - Rows + 1)/Rows;
714 icon_w = (icon_w / (n+1)) *(n+1)+n;
715 icon_h = (icon_h / (m+1)) *(m+1)+m;
716 icon_win = XCreateWindow (dpy, Scr.Root, window_x, window_y, icon_w, icon_h,
717 0, Pdepth, InputOutput, Pvisual, valuemask,
718 &attributes);
719 XGrabButton(dpy, 1, AnyModifier, icon_win,
720 True, ButtonPressMask | ButtonReleaseMask|ButtonMotionMask,
721 GrabModeAsync, GrabModeAsync, None,
722 None);
723 XGrabButton(dpy, 2, AnyModifier, icon_win,
724 True, ButtonPressMask | ButtonReleaseMask|ButtonMotionMask,
725 GrabModeAsync, GrabModeAsync, None,
726 None);
727 XGrabButton(dpy, 3, AnyModifier, icon_win,
728 True, ButtonPressMask | ButtonReleaseMask|ButtonMotionMask,
729 GrabModeAsync, GrabModeAsync, None,
730 None);
732 if(!StartIconic)
733 wmhints.initial_state = NormalState;
734 else
735 wmhints.initial_state = IconicState;
736 wmhints.flags = 0;
737 if (icon_x != -10000)
739 if (icon_xneg)
740 icon_x = Scr.MyDisplayWidth + icon_x - icon_w;
741 if (icon_y != -10000)
743 if (icon_yneg)
744 icon_y = Scr.MyDisplayHeight + icon_y - icon_h;
746 else
748 icon_y = 0;
750 icon_xneg = 0;
751 icon_yneg = 0;
752 wmhints.icon_x = icon_x;
753 wmhints.icon_y = icon_y;
754 wmhints.flags = IconPositionHint;
756 wmhints.icon_window = icon_win;
757 wmhints.input = False;
758 wmhints.flags |= InputHint | StateHint | IconWindowHint;
760 class1.res_name = MyName;
761 class1.res_class = "FvwmPager";
763 XSetWMProperties(dpy,Scr.Pager_w,&name,&name,NULL,0,
764 &sizehints,&wmhints,&class1);
765 XFree((char *)name.value);
767 /* change colour/font for labelling mini-windows */
768 XSetForeground(dpy, Scr.NormalGC, focus_fore_pix);
770 if (FwindowFont != NULL && FwindowFont->font != NULL)
771 XSetFont(dpy, Scr.NormalGC, FwindowFont->font->fid);
773 /* create the 3d bevel GC's if necessary */
774 if (windowcolorset >= 0) {
775 gcv.foreground = Colorset[windowcolorset].hilite;
776 Scr.whGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
777 gcv.foreground = Colorset[windowcolorset].shadow;
778 Scr.wsGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
780 if (activecolorset >= 0) {
781 gcv.foreground = Colorset[activecolorset].hilite;
782 Scr.ahGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
783 gcv.foreground = Colorset[activecolorset].shadow;
784 Scr.asGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
787 balloon_font = FlocaleLoadFont(dpy, BalloonFont, MyName);
788 for(i=0;i<ndesks;i++)
790 w = window_w / Columns;
791 h = window_h / Rows;
792 x = (w + 1) * (i % Columns);
793 y = (h + 1) * (i / Columns);
795 /* create the GC for desk labels */
796 gcv.foreground = (Desks[i].colorset < 0) ? fore_pix
797 : Colorset[Desks[i].colorset].fg;
798 if (uselabel && Ffont && Ffont->font) {
799 gcv.font = Ffont->font->fid;
800 Desks[i].NormalGC =
801 fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground | GCFont, &gcv);
802 } else {
803 Desks[i].NormalGC =
804 fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
806 /* create the active desk hilite GC */
807 if(Pdepth < 2)
808 gcv.foreground = fore_pix;
809 else
810 gcv.foreground = (Desks[i].highcolorset < 0) ? hi_pix
811 : Colorset[Desks[i].highcolorset].bg;
812 Desks[i].HiliteGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
814 /* create the hilight desk title drawing GC */
815 if ((Pdepth < 2) || (fore_pix == hi_pix))
816 gcv.foreground = (Desks[i].highcolorset < 0) ? back_pix
817 : Colorset[Desks[i].highcolorset].fg;
818 else
819 gcv.foreground = (Desks[i].highcolorset < 0) ? fore_pix
820 : Colorset[Desks[i].highcolorset].fg;
822 if (uselabel && Ffont && Ffont->font) {
823 Desks[i].rvGC =
824 fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground | GCFont, &gcv);
825 } else {
826 Desks[i].rvGC =
827 fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
829 /* create the virtual page boundary GC */
830 gcv.foreground = (Desks[i].colorset < 0) ? fore_pix
831 : Colorset[Desks[i].colorset].fg;
832 gcv.line_width = 1;
833 gcv.line_style = (use_dashed_separators) ? LineOnOffDash : LineSolid;
834 Desks[i].DashedGC =
835 fvwmlib_XCreateGC(
836 dpy, Scr.Pager_w, GCForeground | GCLineStyle | GCLineWidth, &gcv);
837 if (use_dashed_separators)
839 /* Although this should already be the default for a freshly created GC,
840 * some X servers do not draw properly dashed lines if the dash style is
841 * not set explicitly. */
842 dash_list[0] = 4;
843 dash_list[1] = 4;
844 XSetDashes(dpy, Desks[i].DashedGC, 0, dash_list, 2);
847 valuemask = (CWBorderPixel | CWColormap | CWEventMask);
848 if (Desks[i].colorset >= 0 && Colorset[Desks[i].colorset].pixmap)
850 valuemask |= CWBackPixmap;
851 attributes.background_pixmap = Colorset[Desks[i].colorset].pixmap;
853 else
855 valuemask |= CWBackPixel;
856 attributes.background_pixel = (Desks[i].colorset < 0) ?
857 (Desks[i].Dcolor ? GetColor(Desks[i].Dcolor) : back_pix)
858 : Colorset[Desks[i].colorset].bg;
861 attributes.border_pixel = (Desks[i].colorset < 0) ? fore_pix
862 : Colorset[Desks[i].colorset].fg;
863 attributes.event_mask = (ExposureMask | ButtonReleaseMask);
864 Desks[i].title_w = XCreateWindow(
865 dpy, Scr.Pager_w, x - 1, y - 1, w, h, 1, CopyFromParent, InputOutput,
866 CopyFromParent, valuemask, &attributes);
867 attributes.event_mask = (ExposureMask | ButtonReleaseMask |
868 ButtonPressMask |ButtonMotionMask);
869 /* or just: desk_h = h - label_h; */
870 desk_h = (window_h - Rows * label_h - Rows + 1) / Rows;
872 valuemask &= ~(CWBackPixel);
875 if (Desks[i].colorset > -1 &&
876 Colorset[Desks[i].colorset].pixmap)
878 valuemask |= CWBackPixmap;
879 attributes.background_pixmap = None; /* set later */
881 else if (Desks[i].bgPixmap)
883 valuemask |= CWBackPixmap;
884 attributes.background_pixmap = Desks[i].bgPixmap->picture;
886 else if (Desks[i].Dcolor)
888 valuemask |= CWBackPixel;
889 attributes.background_pixel = GetColor(Desks[i].Dcolor);
891 else if (PixmapBack)
893 valuemask |= CWBackPixmap;
894 attributes.background_pixmap = PixmapBack->picture;
896 else
898 valuemask |= CWBackPixel;
899 attributes.background_pixel = (Desks[i].colorset < 0) ? back_pix
900 : Colorset[Desks[i].colorset].bg;
903 Desks[i].w = XCreateWindow(
904 dpy, Desks[i].title_w, x - 1, LabelsBelow ? -1 : label_h - 1, w, desk_h,
905 1, CopyFromParent, InputOutput, CopyFromParent, valuemask, &attributes);
907 if (HilightDesks)
909 valuemask &= ~(CWBackPixel | CWBackPixmap);
911 attributes.event_mask = 0;
913 if (Desks[i].highcolorset > -1 &&
914 Colorset[Desks[i].highcolorset].pixmap)
916 valuemask |= CWBackPixmap;
917 attributes.background_pixmap = None; /* set later */
919 else if (HilightPixmap)
921 valuemask |= CWBackPixmap;
922 attributes.background_pixmap = HilightPixmap->picture;
924 else
926 valuemask |= CWBackPixel;
927 attributes.background_pixel = (Desks[i].highcolorset < 0) ? hi_pix
928 : Colorset[Desks[i].highcolorset].bg;
931 w = w / (n + 1);
932 h = desk_h / (m + 1);
933 Desks[i].CPagerWin=XCreateWindow(dpy, Desks[i].w, -32768, -32768, w, h, 0,
934 CopyFromParent, InputOutput,
935 CopyFromParent, valuemask, &attributes);
936 draw_desk_background(i, w, h);
937 XMapRaised(dpy,Desks[i].CPagerWin);
939 else
941 draw_desk_background(i, 0, 0);
944 XMapRaised(dpy,Desks[i].w);
945 XMapRaised(dpy,Desks[i].title_w);
947 /* get font for balloon */
948 Desks[i].balloon.Ffont = balloon_font;
949 if (Desks[i].balloon.Ffont == NULL)
951 fprintf(stderr, "%s: No fonts available, giving up!.\n", MyName);
953 Desks[i].balloon.height = Desks[i].balloon.Ffont->height + 1;
955 initialize_balloon_window();
956 XMapRaised(dpy,Scr.Pager_w);
960 void UpdateWindowShape(void)
962 if (FHaveShapeExtension)
964 int i, j, cnt, shape_count, x_pos, y_pos;
965 XRectangle *shape;
967 if (!ShapeLabels || !uselabel || label_h<=0)
968 return;
970 shape_count =
971 ndesks + ((Scr.CurrentDesk < desk1 || Scr.CurrentDesk >desk2) ? 0 : 1);
973 shape = (XRectangle *)alloca (shape_count * sizeof (XRectangle));
975 if (shape == NULL)
976 return;
978 cnt = 0;
979 y_pos = (LabelsBelow ? 0 : label_h);
981 for (i = 0; i < Rows; ++i)
983 x_pos = 0;
984 for (j = 0; j < Columns; ++j)
986 if (cnt < ndesks)
988 shape[cnt].x = x_pos;
989 shape[cnt].y = y_pos;
990 shape[cnt].width = desk_w + 1;
991 shape[cnt].height = desk_h + 2;
993 if (cnt == Scr.CurrentDesk - desk1)
995 shape[ndesks].x = x_pos;
996 shape[ndesks].y =
997 (LabelsBelow ? y_pos + desk_h + 2 : y_pos - label_h);
998 shape[ndesks].width = desk_w;
999 shape[ndesks].height = label_h + 2;
1002 ++cnt;
1003 x_pos += desk_w + 1;
1005 y_pos += desk_h + 2 + label_h;
1008 FShapeCombineRectangles(
1009 dpy, Scr.Pager_w, FShapeBounding, 0, 0, shape, shape_count, FShapeSet, 0);
1017 * Decide what to do about received X events
1020 void DispatchEvent(XEvent *Event)
1022 int i,x,y;
1023 Window JunkRoot, JunkChild;
1024 Window w;
1025 int JunkX, JunkY;
1026 unsigned JunkMask;
1027 char keychar;
1028 KeySym keysym;
1029 Bool do_move_page = False;
1030 short dx = 0;
1031 short dy = 0;
1033 switch(Event->xany.type)
1035 case EnterNotify:
1036 HandleEnterNotify(Event);
1037 break;
1038 case LeaveNotify:
1039 if ( ShowBalloons )
1040 UnmapBalloonWindow();
1041 break;
1042 case ConfigureNotify:
1043 w = Event->xconfigure.window;
1044 discard_events(ConfigureNotify, Event->xconfigure.window, Event);
1045 if (w != icon_win)
1047 /* icon_win is not handled here */
1048 discard_events(Expose, w, NULL);
1049 ReConfigure();
1051 break;
1052 case Expose:
1053 HandleExpose(Event);
1054 break;
1055 case KeyPress:
1056 if (is_transient)
1058 XLookupString(&(Event->xkey), &keychar, 1, &keysym, NULL);
1059 switch(keysym)
1061 case XK_Up:
1062 dy = -100;
1063 do_move_page = True;
1064 break;
1065 case XK_Down:
1066 dy = 100;
1067 do_move_page = True;
1068 break;
1069 case XK_Left:
1070 dx = -100;
1071 do_move_page = True;
1072 break;
1073 case XK_Right:
1074 dx = 100;
1075 do_move_page = True;
1076 break;
1077 default:
1078 /* does not return */
1079 ExitPager();
1080 break;
1082 if (do_move_page)
1084 char command[64];
1085 sprintf(command,"Scroll %d %d", dx, dy);
1086 SendText(fd, command, 0);
1089 break;
1090 case ButtonRelease:
1091 if (do_ignore_next_button_release)
1093 do_ignore_next_button_release = False;
1094 break;
1096 if (Event->xbutton.button == 3)
1098 for(i=0;i<ndesks;i++)
1100 if(Event->xany.window == Desks[i].w)
1102 if (FQueryPointer(dpy, Desks[i].w, &JunkRoot, &JunkChild,
1103 &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1105 /* pointer is on a different screen - that's okay here */
1107 Scroll(desk_w, desk_h, x, y, i, False);
1110 if(Event->xany.window == icon_win)
1112 if (FQueryPointer(dpy, icon_win, &JunkRoot, &JunkChild,
1113 &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1115 /* pointer is on a different screen - that's okay here */
1117 Scroll(icon_w, icon_h, x, y, 0, True);
1119 /* Flush any pending scroll operations */
1120 do_scroll(0, 0, True, False);
1122 else if((Event->xbutton.button == 1)||
1123 (Event->xbutton.button == 2))
1125 for(i=0;i<ndesks;i++)
1127 if(Event->xany.window == Desks[i].w)
1128 SwitchToDeskAndPage(i,Event);
1129 else if(Event->xany.window == Desks[i].title_w)
1130 SwitchToDesk(i);
1132 if(Event->xany.window == icon_win)
1134 IconSwitchPage(Event);
1137 if (is_transient)
1139 /* does not return */
1140 ExitPager();
1142 break;
1143 case ButtonPress:
1144 do_ignore_next_button_release = False;
1145 if ( ShowBalloons )
1146 UnmapBalloonWindow();
1147 if (((Event->xbutton.button == 2)||
1148 ((Event->xbutton.button == 3)&&
1149 (Event->xbutton.state & Mod1Mask)))&&
1150 (Event->xbutton.subwindow != None))
1152 MoveWindow(Event);
1154 else if (Event->xbutton.button == 3)
1156 /* save initial virtual desk position for drag */
1157 MyVx=Scr.Vx;
1158 MyVy=Scr.Vy;
1159 for(i=0;i<ndesks;i++)
1161 if(Event->xany.window == Desks[i].w)
1163 if (FQueryPointer(dpy, Desks[i].w, &JunkRoot, &JunkChild,
1164 &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1166 /* pointer is on a different screen - that's okay here */
1168 Scroll(desk_w, desk_h, x, y, Scr.CurrentDesk, False);
1169 if (Scr.CurrentDesk != i + desk1)
1171 Wait = 0;
1172 SwitchToDesk(i);
1174 break;
1177 if(Event->xany.window == icon_win)
1179 if (FQueryPointer(dpy, icon_win, &JunkRoot, &JunkChild,
1180 &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1182 /* pointer is on a different screen - that's okay here */
1184 Scroll(icon_w, icon_h, x, y, 0, True);
1187 break;
1188 case MotionNotify:
1189 do_ignore_next_button_release = False;
1190 while(FCheckMaskEvent(dpy, PointerMotionMask | ButtonMotionMask,Event))
1193 if(Event->xmotion.state & Button3MotionMask)
1195 for(i=0;i<ndesks;i++)
1197 if(Event->xany.window == Desks[i].w)
1199 if (FQueryPointer(dpy, Desks[i].w, &JunkRoot, &JunkChild,
1200 &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1202 /* pointer is on a different screen - that's okay here */
1204 Scroll(desk_w, desk_h, x, y, i, False);
1207 if(Event->xany.window == icon_win)
1209 if (FQueryPointer(dpy, icon_win, &JunkRoot, &JunkChild,
1210 &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1212 /* pointer is on a different screen - that's okay here */
1214 Scroll(icon_w, icon_h, x, y, 0, True);
1218 break;
1220 case ClientMessage:
1221 if ((Event->xclient.format==32) &&
1222 (Event->xclient.data.l[0]==wm_del_win))
1224 /* does not return */
1225 ExitPager();
1227 break;
1231 void HandleEnterNotify(XEvent *Event)
1234 PagerWindow *t;
1235 Bool is_icon_view = False;
1236 extern Bool do_focus_on_enter;
1238 if (!ShowBalloons && !do_focus_on_enter)
1239 /* nothing to do */
1240 return;
1242 /* is this the best way to match X event window ID to PagerWindow ID? */
1243 for ( t = Start; t != NULL; t = t->next )
1245 if ( t->PagerView == Event->xcrossing.window )
1247 break;
1249 if ( t->IconView == Event->xcrossing.window )
1251 is_icon_view = True;
1252 break;
1255 if (t == NULL)
1257 return;
1260 if (ShowBalloons)
1262 MapBalloonWindow(t, is_icon_view);
1265 if (do_focus_on_enter)
1267 SendText(fd, "Silent FlipFocus NoWarp", t->w);
1272 XRectangle get_expose_bound(XEvent *Event)
1274 XRectangle r;
1275 int ex, ey, ex2, ey2;
1277 ex = Event->xexpose.x;
1278 ey = Event->xexpose.y;
1279 ex2 = Event->xexpose.x + Event->xexpose.width;
1280 ey2 = Event->xexpose.y + Event->xexpose.height;
1281 while (FCheckTypedWindowEvent(dpy, Event->xany.window, Expose, Event))
1283 ex = min(ex, Event->xexpose.x);
1284 ey = min(ey, Event->xexpose.y);
1285 ex2 = max(ex2, Event->xexpose.x + Event->xexpose.width);
1286 ey2= max(ey2 , Event->xexpose.y + Event->xexpose.height);
1288 r.x = ex;
1289 r.y = ey;
1290 r.width = ex2-ex;
1291 r.height = ey2-ey;
1292 return r;
1295 void HandleExpose(XEvent *Event)
1297 int i;
1298 PagerWindow *t;
1299 XRectangle r;
1301 /* it will be good to have full "clipping redraw". Do that for
1302 * desk label only for now */
1303 for(i=0;i<ndesks;i++)
1305 /* ric@giccs.georgetown.edu */
1306 if (Event->xany.window == Desks[i].w ||
1307 Event->xany.window == Desks[i].title_w)
1309 r = get_expose_bound(Event);
1310 DrawGrid(i, 0, Event->xany.window, &r);
1311 return;
1314 if (Event->xany.window == Scr.balloon_w)
1316 DrawInBalloonWindow(Scr.balloon_desk);
1317 return;
1319 if(Event->xany.window == icon_win)
1320 DrawIconGrid(0);
1322 for (t = Start; t != NULL; t = t->next)
1324 if (t->PagerView == Event->xany.window)
1326 LabelWindow(t);
1327 PictureWindow(t);
1328 BorderWindow(t);
1330 else if(t->IconView == Event->xany.window)
1332 LabelIconWindow(t);
1333 PictureIconWindow(t);
1334 BorderIconWindow(t);
1338 discard_events(Expose, Event->xany.window, NULL);
1343 * Respond to a change in window geometry.
1346 void ReConfigure(void)
1348 Window root;
1349 unsigned border_width, depth;
1350 int n,m,w,h,n1,m1,x,y,i,j,k;
1351 int old_ww;
1352 int old_wh;
1353 int is_size_changed;
1355 old_ww = window_w;
1356 old_wh = window_h;
1357 if (!XGetGeometry(dpy, Scr.Pager_w, &root, &x, &y, (unsigned *)&window_w,
1358 (unsigned *)&window_h, &border_width,&depth))
1360 return;
1362 is_size_changed = (old_ww != window_w || old_wh != window_h);
1364 n1 = Scr.Vx / Scr.MyDisplayWidth;
1365 m1 = Scr.Vy / Scr.MyDisplayHeight;
1366 n = Scr.VxMax / Scr.MyDisplayWidth;
1367 m = Scr.VyMax / Scr.MyDisplayHeight;
1369 sizehints.width_inc = Columns * (n + 1);
1370 sizehints.height_inc = Rows * (m + 1);
1371 sizehints.base_width = Columns * n + Columns - 1;
1372 sizehints.base_height = Rows*(m + label_h+1) - 1;
1373 sizehints.min_width = sizehints.base_width;
1374 sizehints.min_height = sizehints.base_height;
1375 if (window_w > 0)
1377 window_w = (window_w - sizehints.base_width) / sizehints.width_inc;
1378 window_w = window_w * sizehints.width_inc + sizehints.base_width;
1380 if (window_h > 0)
1382 window_h = (window_h - sizehints.base_height) / sizehints.height_inc;
1383 window_h = window_h * sizehints.height_inc + sizehints.base_height;
1385 desk_w = (window_w - Columns + 1) / Columns;
1386 desk_h = (window_h - Rows * label_h - Rows + 1) / Rows;
1387 w = (desk_w - n)/(n+1);
1388 h = (desk_h - m)/(m+1);
1390 XSetWMNormalHints(dpy,Scr.Pager_w,&sizehints);
1392 x = (desk_w - n) * Scr.Vx / Scr.VWidth + n1;
1393 y = (desk_h - m) * Scr.Vy / Scr.VHeight + m1;
1395 for(k=0;k<Rows;k++)
1397 for(j=0;j<Columns;j++)
1399 i = k*Columns+j;
1400 if (i<ndesks)
1402 XMoveResizeWindow(
1403 dpy,Desks[i].title_w, (desk_w+1)*j-1,(desk_h+label_h+1)*k-1,
1404 desk_w,desk_h+label_h);
1405 XMoveResizeWindow(
1406 dpy,Desks[i].w, -1, (LabelsBelow) ? -1 : label_h - 1, desk_w,desk_h);
1407 if (!is_size_changed)
1409 if (CSET_IS_TRANSPARENT(Desks[i].colorset))
1411 draw_desk_background(i, w, h);
1414 if (HilightDesks)
1416 if(i == Scr.CurrentDesk - desk1)
1417 XMoveResizeWindow(dpy, Desks[i].CPagerWin, x,y,w,h);
1418 else
1419 XMoveResizeWindow(dpy, Desks[i].CPagerWin, -32768, -32768,w,h);
1421 draw_desk_background(i, w, h);
1425 /* reconfigure all the subordinate windows */
1426 ReConfigureAll();
1431 * Respond to a "background" change: update the Parental Relative cset
1435 /* layout:
1436 * Root -> pager window (pr) -> title window -> desk window -> window view
1437 * | |-> hilight desk
1438 * |-> icon_window -> icon view
1439 * |-> ballon window
1442 /* update the hilight desk and the windows: desk color change */
1443 static
1444 void update_pr_transparent_subwindows(int i)
1446 int cset;
1447 int n,m,w,h;
1448 PagerWindow *t;
1450 n = Scr.VxMax / Scr.MyDisplayWidth;
1451 m = Scr.VyMax / Scr.MyDisplayHeight;
1452 w = (desk_w - n)/(n+1);
1453 h = (desk_h - m)/(m+1);
1455 if (CSET_IS_TRANSPARENT_PR(Desks[i].highcolorset) && HilightDesks)
1457 SetWindowBackground(
1458 dpy, Desks[i].CPagerWin, w, h,
1459 &Colorset[Desks[i].highcolorset],
1460 Pdepth, Scr.NormalGC, True);
1463 t = Start;
1464 for(t = Start; t != NULL; t = t->next)
1466 cset = (t != FocusWin) ? windowcolorset : activecolorset;
1467 if (t->desk != i && !CSET_IS_TRANSPARENT_PR(cset))
1469 continue;
1471 if (t->PagerView != None)
1473 SetWindowBackground(
1474 dpy, t->PagerView, t->pager_view_width,
1475 t->pager_view_height,
1476 &Colorset[cset], Pdepth, Scr.NormalGC, True);
1478 if (t->IconView)
1480 SetWindowBackground(
1481 dpy, t->IconView, t->icon_view_width,
1482 t->icon_view_height,
1483 &Colorset[cset], Pdepth, Scr.NormalGC, True);
1488 /* update all the parental relative windows: pr background change */
1489 void update_pr_transparent_windows(void)
1491 int i,j,k,cset;
1492 int n,m,w,h;
1493 PagerWindow *t;
1495 n = Scr.VxMax / Scr.MyDisplayWidth;
1496 m = Scr.VyMax / Scr.MyDisplayHeight;
1497 w = (desk_w - n)/(n+1);
1498 h = (desk_h - m)/(m+1);
1500 for(k=0;k<Rows;k++)
1502 for(j=0;j<Columns;j++)
1504 i = k*Columns+j;
1505 if (i < ndesks)
1507 if (CSET_IS_TRANSPARENT_PR(Desks[i].colorset))
1509 draw_desk_background(i, w, h);
1511 else if (CSET_IS_TRANSPARENT_PR(
1512 Desks[i].highcolorset) && HilightDesks)
1514 SetWindowBackground(
1515 dpy, Desks[i].CPagerWin, w, h,
1516 &Colorset[Desks[i].highcolorset],
1517 Pdepth, Scr.NormalGC, True);
1522 /* subordinate windows with a pr parent desk */
1523 t = Start;
1524 for(t = Start; t != NULL; t = t->next)
1526 cset = (t != FocusWin) ? windowcolorset : activecolorset;
1527 if (!CSET_IS_TRANSPARENT_PR(cset) ||
1528 (fAlwaysCurrentDesk &&
1529 !CSET_IS_TRANSPARENT_PR(Desks[0].colorset)) ||
1530 (!fAlwaysCurrentDesk &&
1531 !CSET_IS_TRANSPARENT_PR(Desks[t->desk].colorset)))
1533 continue;
1535 if (t->PagerView != None)
1537 SetWindowBackground(
1538 dpy, t->PagerView, t->pager_view_width,
1539 t->pager_view_height,
1540 &Colorset[cset], Pdepth, Scr.NormalGC, True);
1542 if (t->desk && t->IconView)
1544 SetWindowBackground(
1545 dpy, t->IconView, t->icon_view_width,
1546 t->icon_view_height,
1547 &Colorset[cset], Pdepth, Scr.NormalGC, True);
1551 /* ballon */
1552 if (BalloonView != None)
1554 cset = Desks[Scr.balloon_desk].ballooncolorset;
1555 if (CSET_IS_TRANSPARENT_PR(cset))
1557 XClearArea(dpy, Scr.balloon_w, 0, 0, 0, 0, True);
1562 void MovePage(Bool is_new_desk)
1564 int n1,m1,x,y,n,m,i,w,h;
1565 XTextProperty name;
1566 char str[100],*sptr;
1567 static int icon_desk_shown = -1000;
1569 Wait = 0;
1570 n1 = Scr.Vx/Scr.MyDisplayWidth;
1571 m1 = Scr.Vy/Scr.MyDisplayHeight;
1572 n = Scr.VxMax / Scr.MyDisplayWidth;
1573 m = Scr.VyMax / Scr.MyDisplayHeight;
1575 x = (desk_w - n) * Scr.Vx / Scr.VWidth + n1;
1576 y = (desk_h - m) * Scr.Vy / Scr.VHeight + m1;
1577 w = (desk_w - n)/(n+1);
1578 h = (desk_h - m)/(m+1);
1580 for(i=0;i<ndesks;i++)
1582 if (HilightDesks)
1584 if(i == Scr.CurrentDesk - desk1)
1586 XMoveWindow(dpy, Desks[i].CPagerWin, x,y);
1587 XLowerWindow(dpy,Desks[i].CPagerWin);
1588 if (CSET_IS_TRANSPARENT(Desks[i].highcolorset))
1590 SetWindowBackground(
1591 dpy, Desks[i].CPagerWin, w, h,
1592 &Colorset[Desks[i].highcolorset], Pdepth,
1593 Scr.NormalGC, True);
1596 else
1598 XMoveWindow(dpy, Desks[i].CPagerWin, -32768,-32768);
1602 DrawIconGrid(1);
1604 ReConfigureIcons(!is_new_desk);
1606 if(Scr.CurrentDesk != icon_desk_shown)
1608 icon_desk_shown = Scr.CurrentDesk;
1610 if((Scr.CurrentDesk >= desk1)&&(Scr.CurrentDesk <=desk2))
1611 sptr = Desks[Scr.CurrentDesk -desk1].label;
1612 else
1614 sprintf(str, "GotoDesk %d", Scr.CurrentDesk);
1615 sptr = &str[0];
1618 if (FlocaleTextListToTextProperty(
1619 dpy, &sptr, 1, XStdICCTextStyle, &name) == 0)
1621 fprintf(stderr,"%s: cannot allocate window name", MyName);
1622 return;
1624 XSetWMIconName(dpy,Scr.Pager_w,&name);
1625 XFree(name.value);
1629 void ReConfigureAll(void)
1631 PagerWindow *t;
1633 t = Start;
1634 while(t!= NULL)
1636 MoveResizePagerView(t, True);
1637 t = t->next;
1641 void ReConfigureIcons(Bool do_reconfigure_desk_only)
1643 PagerWindow *t;
1644 int x, y, w, h;
1646 for (t = Start; t != NULL; t = t->next)
1648 if (do_reconfigure_desk_only && t->desk != Scr.CurrentDesk)
1649 continue;
1650 CalcGeom(t, icon_w, icon_h, &x, &y, &w, &h);
1651 t->icon_view_x = x;
1652 t->icon_view_y = y;
1653 t->icon_view_width = w;
1654 t->icon_view_height = h;
1655 if(Scr.CurrentDesk == t->desk)
1656 XMoveResizeWindow(dpy, t->IconView, x, y, w, h);
1657 else
1658 XMoveResizeWindow(dpy, t->IconView, -32768, -32768, w, h);
1664 * Draw grid lines for desk #i
1667 void DrawGrid(int desk, int erase, Window ew, XRectangle *r)
1669 int y, y1, y2, x, x1, x2,d,w;
1670 char str[15], *ptr;
1671 int cs;
1672 XRectangle bound;
1673 Region region = 0;
1675 if((desk < 0 ) || (desk >= ndesks))
1676 return;
1678 /* desk grid */
1679 if (!ew || ew == Desks[desk].w)
1681 x = Scr.MyDisplayWidth;
1682 y1 = 0;
1683 y2 = desk_h;
1684 while (x < Scr.VWidth)
1686 x1 = (x * desk_w) / Scr.VWidth;
1687 if (!use_no_separators)
1689 XDrawLine(
1690 dpy,Desks[desk].w,Desks[desk].DashedGC,
1691 x1,y1,x1,y2);
1693 x += Scr.MyDisplayWidth;
1695 y = Scr.MyDisplayHeight;
1696 x1 = 0;
1697 x2 = desk_w;
1698 while(y < Scr.VHeight)
1700 y1 = (y * desk_h) / Scr.VHeight;
1701 if (!use_no_separators)
1703 XDrawLine(
1704 dpy,Desks[desk].w,Desks[desk].DashedGC,
1705 x1,y1,x2,y1);
1707 y += Scr.MyDisplayHeight;
1711 if (ew && ew != Desks[desk].title_w)
1713 return;
1716 /* desk label */
1717 if (r)
1719 bound.x = r->x;
1720 bound.y = r->y;
1721 bound.width = r->width;
1722 bound.height = r->height;
1723 region = XCreateRegion();
1724 XUnionRectWithRegion (&bound, region, region);
1726 else
1728 bound.x = 0;
1729 bound.y = (LabelsBelow ? desk_h : 0);
1730 bound.width = desk_w;
1731 bound.height = label_h;
1734 if (FftSupport && Ffont->fftf.fftfont != NULL)
1736 erase = True;
1738 if(((Scr.CurrentDesk - desk1) == desk) && !ShapeLabels)
1740 if (uselabel)
1742 XFillRectangle(
1743 dpy,Desks[desk].title_w,Desks[desk].HiliteGC,
1744 bound.x, bound.y, bound.width, bound.height);
1747 else
1749 if(uselabel && erase)
1751 XClearArea(dpy,Desks[desk].title_w,
1752 bound.x, bound.y, bound.width, bound.height,
1753 False);
1757 d = desk1+desk;
1758 ptr = Desks[desk].label;
1759 w = FlocaleTextWidth(Ffont,ptr,strlen(ptr));
1760 if( w > desk_w)
1762 sprintf(str,"%d",d);
1763 ptr = str;
1764 w = FlocaleTextWidth(Ffont,ptr,strlen(ptr));
1766 if((w <= desk_w)&&(uselabel))
1768 FwinString->str = ptr;
1769 FwinString->win = Desks[desk].title_w;
1770 if(desk == (Scr.CurrentDesk - desk1))
1772 cs = Desks[desk].highcolorset;
1773 FwinString->gc = Desks[desk].rvGC;
1775 else
1777 cs = Desks[desk].colorset;
1778 FwinString->gc = Desks[desk].NormalGC;
1781 FwinString->flags.has_colorset = False;
1782 if (cs >= 0)
1784 FwinString->colorset = &Colorset[cs];
1785 FwinString->flags.has_colorset = True;
1787 FwinString->x = (desk_w - w)/2;
1788 FwinString->y = (LabelsBelow ?
1789 desk_h + Ffont->ascent + 1 : Ffont->ascent + 1);
1790 if (region)
1792 FwinString->flags.has_clip_region = True;
1793 FwinString->clip_region = region;
1794 XSetRegion(dpy, FwinString->gc, region);
1796 else
1798 FwinString->flags.has_clip_region = False;
1800 FlocaleDrawString(dpy, Ffont, FwinString, 0);
1801 if (region)
1803 XDestroyRegion(region);
1804 FwinString->flags.has_clip_region = False;
1805 FwinString->clip_region = None;
1806 XSetClipMask(dpy, FwinString->gc, None);
1810 if (FShapesSupported)
1812 UpdateWindowShape ();
1817 void DrawIconGrid(int erase)
1819 int y, y1, y2, x, x1, x2,w,h,n,m,n1,m1;
1820 int i;
1822 if(erase)
1824 int tmp=(Scr.CurrentDesk - desk1);
1826 if ((tmp < 0) || (tmp >= ndesks))
1828 if (PixmapBack)
1829 XSetWindowBackgroundPixmap(dpy, icon_win,PixmapBack->picture);
1830 else
1831 XSetWindowBackground(dpy, icon_win, back_pix);
1833 else
1835 if (Desks[tmp].bgPixmap)
1836 XSetWindowBackgroundPixmap(
1837 dpy, icon_win,Desks[tmp].bgPixmap->picture);
1838 else if (Desks[tmp].Dcolor)
1839 XSetWindowBackground(dpy, icon_win, GetColor(Desks[tmp].Dcolor));
1840 else if (PixmapBack)
1841 XSetWindowBackgroundPixmap(dpy, icon_win, PixmapBack->picture);
1842 else
1843 XSetWindowBackground(dpy, icon_win, back_pix);
1846 XClearWindow(dpy,icon_win);
1849 x = Scr.MyDisplayWidth;
1850 y1 = 0;
1851 y2 = icon_h;
1852 while(x < Scr.VWidth)
1854 x1 = x * icon_w / Scr.VWidth;
1855 if (!use_no_separators)
1856 for(i=0;i<ndesks;i++)
1857 XDrawLine(dpy,icon_win,Desks[i].DashedGC,x1,y1,x1,y2);
1858 x += Scr.MyDisplayWidth;
1861 y = Scr.MyDisplayHeight;
1862 x1 = 0;
1863 x2 = icon_w;
1864 while(y < Scr.VHeight)
1866 y1 = y * icon_h / Scr.VHeight;
1867 if (!use_no_separators)
1868 for(i=0;i<ndesks;i++)
1869 XDrawLine(dpy,icon_win,Desks[i].DashedGC,x1,y1,x2,y1);
1870 y += Scr.MyDisplayHeight;
1872 n1 = Scr.Vx / Scr.MyDisplayWidth;
1873 m1 = Scr.Vy / Scr.MyDisplayHeight;
1874 n = Scr.VxMax / Scr.MyDisplayWidth;
1875 m = Scr.VyMax / Scr.MyDisplayHeight;
1876 w = (icon_w - n) / (n + 1);
1877 h = (icon_h - m) / (m + 1);
1879 x = (icon_w - n) * Scr.Vx / Scr.VWidth + n1;
1880 y = (icon_h - m) * Scr.Vy / Scr.VHeight + m1;
1882 if (HilightDesks)
1884 if (HilightPixmap)
1886 for(i=0;i<ndesks;i++)
1887 XCopyArea(dpy, HilightPixmap->picture, icon_win, Scr.NormalGC, 0, 0,
1888 w, h, x, y);
1890 else
1892 for(i=0;i<ndesks;i++)
1893 XFillRectangle (dpy, icon_win, Desks[i].HiliteGC, x, y, w, h);
1899 void SwitchToDesk(int Desk)
1901 char command[256];
1903 sprintf(command, "GotoDesk 0 %d", Desk + desk1);
1904 SendText(fd,command,0);
1908 void SwitchToDeskAndPage(int Desk, XEvent *Event)
1910 char command[256];
1912 if (Scr.CurrentDesk != (Desk + desk1))
1914 int vx, vy;
1915 /* patch to let mouse button 3 change desks and do not cling to a page */
1916 vx = Event->xbutton.x * Scr.VWidth / (desk_w * Scr.MyDisplayWidth);
1917 vy = Event->xbutton.y * Scr.VHeight / (desk_h * Scr.MyDisplayHeight);
1918 Scr.Vx = vx * Scr.MyDisplayWidth;
1919 Scr.Vy = vy * Scr.MyDisplayHeight;
1920 sprintf(command, "GotoDeskAndPage %d %d %d", Desk + desk1, vx, vy);
1921 SendText(fd, command, 0);
1924 else
1926 int x = Event->xbutton.x * Scr.VWidth / (desk_w * Scr.MyDisplayWidth);
1927 int y = Event->xbutton.y * Scr.VHeight / (desk_h * Scr.MyDisplayHeight);
1929 /* Fix for buggy XFree86 servers that report button release events
1930 * incorrectly when moving fast. Not perfect, but should at least prevent
1931 * that we get a random page. */
1932 if (x < 0)
1933 x = 0;
1934 if (y < 0)
1935 y = 0;
1936 if (x * Scr.MyDisplayWidth > Scr.VxMax)
1937 x = Scr.VxMax / Scr.MyDisplayWidth;
1938 if (y * Scr.MyDisplayHeight > Scr.VyMax)
1939 y = Scr.VyMax / Scr.MyDisplayHeight;
1940 sprintf(command, "GotoPage %d %d", x, y);
1941 SendText(fd, command, 0);
1943 Wait = 1;
1946 void IconSwitchPage(XEvent *Event)
1948 char command[34];
1950 sprintf(command,"GotoPage %d %d",
1951 Event->xbutton.x * Scr.VWidth / (icon_w * Scr.MyDisplayWidth),
1952 Event->xbutton.y * Scr.VHeight / (icon_h * Scr.MyDisplayHeight));
1953 SendText(fd, command, 0);
1954 Wait = 1;
1958 void AddNewWindow(PagerWindow *t)
1960 unsigned long valuemask;
1961 XSetWindowAttributes attributes;
1962 int i, x, y, w, h;
1964 i = t->desk - desk1;
1965 CalcGeom(t, desk_w, desk_h, &x, &y, &w, &h);
1966 t->pager_view_x = x;
1967 t->pager_view_y = y;
1968 t->pager_view_width = w;
1969 t->pager_view_height = h;
1970 valuemask = CWBackPixel | CWEventMask;
1971 attributes.background_pixel = t->back;
1972 attributes.event_mask = ExposureMask;
1974 /* ric@giccs.georgetown.edu -- added Enter and Leave events for
1975 popping up balloon window */
1976 attributes.event_mask =
1977 ExposureMask | EnterWindowMask | LeaveWindowMask;
1979 if ((i >= 0) && (i < ndesks))
1981 t->PagerView = XCreateWindow(
1982 dpy,Desks[i].w, x, y, w, h, 0, CopyFromParent,
1983 InputOutput, CopyFromParent, valuemask, &attributes);
1984 if (windowcolorset > -1)
1986 SetWindowBackground(
1987 dpy, t->PagerView, w, h,
1988 &Colorset[windowcolorset], Pdepth,
1989 Scr.NormalGC, True);
1991 if (!UseSkipList || !DO_SKIP_WINDOW_LIST(t))
1993 if (IS_ICONIFIED(t))
1995 XMoveResizeWindow(
1996 dpy, t->PagerView, -32768, -32768, 1,
1999 XMapRaised(dpy, t->PagerView);
2002 else
2004 t->PagerView = None;
2007 CalcGeom(t, icon_w, icon_h, &x, &y, &w, &h);
2008 t->icon_view_x = x;
2009 t->icon_view_y = y;
2010 t->icon_view_width = w;
2011 t->icon_view_height = h;
2012 if(Scr.CurrentDesk != t->desk)
2014 x = -32768;
2015 y = -32768;
2017 t->IconView = XCreateWindow(
2018 dpy,icon_win, x, y, w, h, 0, CopyFromParent, InputOutput,
2019 CopyFromParent, valuemask, &attributes);
2020 if (windowcolorset > -1)
2022 SetWindowBackground(
2023 dpy, t->IconView, w, h, &Colorset[windowcolorset],
2024 Pdepth, Scr.NormalGC, True);
2026 if(Scr.CurrentDesk == t->desk)
2028 XGrabButton(
2029 dpy, 2, AnyModifier, t->IconView, True,
2030 ButtonPressMask | ButtonReleaseMask|ButtonMotionMask,
2031 GrabModeAsync, GrabModeAsync, None, None);
2033 if (!UseSkipList || !DO_SKIP_WINDOW_LIST(t))
2035 if (IS_ICONIFIED(t))
2037 XMoveResizeWindow(
2038 dpy, t->IconView, -32768, -32768, 1,
2041 XMapRaised(dpy, t->IconView);
2042 t->myflags.is_mapped = 1;
2044 else
2046 t->myflags.is_mapped = 0;
2048 Hilight(t, False);
2050 return;
2054 void ChangeDeskForWindow(PagerWindow *t,long newdesk)
2056 int i, x, y, w, h;
2057 Bool size_changed = False;
2059 i = newdesk - desk1;
2060 if(t->PagerView == None)
2062 t->desk = newdesk;
2063 XDestroyWindow(dpy,t->IconView);
2064 AddNewWindow( t);
2065 return;
2068 CalcGeom(t, desk_w, desk_h, &x, &y, &w, &h);
2069 size_changed = (t->pager_view_width != w || t->pager_view_height != h);
2070 t->pager_view_x = x;
2071 t->pager_view_y = y;
2072 t->pager_view_width = w;
2073 t->pager_view_height = h;
2075 if ((i >= 0) && (i < ndesks))
2077 int cset;
2079 XReparentWindow(dpy, t->PagerView, Desks[i].w, x, y);
2080 if (size_changed)
2081 XResizeWindow(dpy, t->PagerView, w, h);
2082 cset = (t != FocusWin) ? windowcolorset : activecolorset;
2083 if (cset > -1 && (size_changed || CSET_IS_TRANSPARENT(cset)))
2085 SetWindowBackground(
2086 dpy, t->PagerView, t->pager_view_width, t->pager_view_height,
2087 &Colorset[cset], Pdepth, Scr.NormalGC, True);
2090 else
2092 XDestroyWindow(dpy,t->PagerView);
2093 t->PagerView = None;
2095 t->desk = i+desk1;
2097 CalcGeom(t, icon_w, icon_h, &x, &y, &w, &h);
2098 size_changed = (t->icon_view_width != w || t->icon_view_height != h);
2099 t->icon_view_x = x;
2100 t->icon_view_y = y;
2101 t->icon_view_width = w;
2102 t->icon_view_height = h;
2103 if(Scr.CurrentDesk != t->desk)
2104 XMoveResizeWindow(dpy,t->IconView,-32768,-32768,w,h);
2105 else
2107 int cset;
2109 XMoveResizeWindow(dpy,t->IconView,x,y,w,h);
2110 cset = (t != FocusWin) ? windowcolorset : activecolorset;
2111 if (cset > -1 && (size_changed || CSET_IS_TRANSPARENT(cset)))
2113 SetWindowBackground(
2114 dpy, t->IconView, t->icon_view_width, t->icon_view_height,
2115 &Colorset[cset], Pdepth, Scr.NormalGC, True);
2120 void MoveResizePagerView(PagerWindow *t, Bool do_force_redraw)
2122 int x, y, w, h;
2123 Bool size_changed;
2124 Bool position_changed;
2126 if (UseSkipList && DO_SKIP_WINDOW_LIST(t) && t->myflags.is_mapped)
2128 if (t->PagerView)
2129 XUnmapWindow(dpy, t->PagerView);
2130 if (t->IconView)
2131 XUnmapWindow(dpy, t->IconView);
2132 t->myflags.is_mapped = 0;
2134 else if (UseSkipList && !DO_SKIP_WINDOW_LIST(t) && !t->myflags.is_mapped)
2136 if (t->PagerView)
2137 XMapRaised(dpy, t->PagerView);
2138 if (t->IconView)
2139 XMapRaised(dpy, t->IconView);
2140 t->myflags.is_mapped = 1;
2143 CalcGeom(t, desk_w, desk_h, &x, &y, &w, &h);
2144 position_changed = (t->pager_view_x != x || t->pager_view_y != y);
2145 size_changed = (t->pager_view_width != w || t->pager_view_height != h);
2146 t->pager_view_x = x;
2147 t->pager_view_y = y;
2148 t->pager_view_width = w;
2149 t->pager_view_height = h;
2150 if (t->PagerView != None)
2152 if (size_changed || position_changed || do_force_redraw)
2154 int cset;
2156 XMoveResizeWindow(dpy, t->PagerView, x, y, w, h);
2157 cset = (t != FocusWin) ? windowcolorset : activecolorset;
2158 if (cset > -1 && (size_changed || CSET_IS_TRANSPARENT(cset)))
2160 SetWindowBackground(
2161 dpy, t->PagerView, t->pager_view_width, t->pager_view_height,
2162 &Colorset[cset], Pdepth, Scr.NormalGC, True);
2166 else if (t->desk >= desk1 && t->desk <= desk2)
2168 XDestroyWindow(dpy, t->IconView);
2169 AddNewWindow(t);
2170 return;
2173 CalcGeom(t, icon_w, icon_h, &x, &y, &w, &h);
2174 position_changed = (t->icon_view_x != x || t->icon_view_y != y);
2175 size_changed = (t->icon_view_width != w || t->icon_view_height != h);
2176 t->icon_view_x = x;
2177 t->icon_view_y = y;
2178 t->icon_view_width = w;
2179 t->icon_view_height = h;
2180 if (Scr.CurrentDesk == t->desk)
2182 int cset;
2184 XMoveResizeWindow(dpy, t->IconView, x, y, w, h);
2185 cset = (t != FocusWin) ? windowcolorset : activecolorset;
2186 if (cset > -1 && (size_changed || CSET_IS_TRANSPARENT(cset)))
2188 SetWindowBackground(
2189 dpy, t->IconView, t->icon_view_width, t->icon_view_height,
2190 &Colorset[cset], Pdepth, Scr.NormalGC, True);
2193 else
2195 XMoveResizeWindow(dpy, t->IconView, -32768, -32768, w, h);
2200 void MoveStickyWindow(Bool is_new_page, Bool is_new_desk)
2202 PagerWindow *t;
2204 for (t = Start; t != NULL; t = t->next)
2206 if (
2207 is_new_desk && t->desk != Scr.CurrentDesk &&
2208 ((IS_ICONIFIED(t) && IS_ICON_STICKY_ACROSS_DESKS(t)) ||
2209 IS_STICKY_ACROSS_DESKS(t)))
2211 ChangeDeskForWindow(t, Scr.CurrentDesk);
2213 else if (
2214 is_new_page &&
2215 ((IS_ICONIFIED(t) &&
2216 IS_ICON_STICKY_ACROSS_PAGES(t)) ||
2217 IS_STICKY_ACROSS_PAGES(t)))
2219 MoveResizePagerView(t, True);
2224 void Hilight(PagerWindow *t, int on)
2227 if(!t)
2228 return;
2230 if(Pdepth < 2)
2232 if(on)
2234 if(t->PagerView != None)
2235 XSetWindowBackgroundPixmap(dpy,t->PagerView,Scr.gray_pixmap);
2236 XSetWindowBackgroundPixmap(dpy,t->IconView,Scr.gray_pixmap);
2238 else
2240 if(IS_STICKY_ACROSS_DESKS(t) || IS_STICKY_ACROSS_PAGES(t))
2242 if(t->PagerView != None)
2243 XSetWindowBackgroundPixmap(dpy,t->PagerView,
2244 Scr.sticky_gray_pixmap);
2245 XSetWindowBackgroundPixmap(dpy,t->IconView,
2246 Scr.sticky_gray_pixmap);
2248 else
2250 if(t->PagerView != None)
2251 XSetWindowBackgroundPixmap(dpy,t->PagerView,
2252 Scr.light_gray_pixmap);
2253 XSetWindowBackgroundPixmap(dpy,t->IconView,
2254 Scr.light_gray_pixmap);
2257 if(t->PagerView != None)
2258 XClearArea(dpy, t->PagerView, 0, 0, 0, 0, True);
2259 XClearArea(dpy, t->IconView, 0, 0, 0, 0, True);
2261 else
2263 int cset;
2264 Pixel pix;
2266 cset = (on) ? activecolorset : windowcolorset;
2267 pix = (on) ? focus_pix : t->back;
2268 if (cset < 0)
2270 if (t->PagerView != None)
2272 XSetWindowBackground(dpy,t->PagerView,pix);
2273 XClearArea(dpy, t->PagerView, 0, 0, 0, 0, True);
2275 XSetWindowBackground(dpy,t->IconView,pix);
2276 XClearArea(dpy, t->IconView, 0, 0, 0, 0, True);
2278 else
2280 if (t->PagerView != None)
2282 SetWindowBackground(
2283 dpy, t->PagerView, t->pager_view_width, t->pager_view_height,
2284 &Colorset[cset], Pdepth, Scr.NormalGC, True);
2286 SetWindowBackground(
2287 dpy, t->IconView, t->icon_view_width, t->icon_view_height,
2288 &Colorset[cset], Pdepth, Scr.NormalGC, True);
2293 /* Use Desk == -1 to scroll the icon window */
2294 void Scroll(int window_w, int window_h, int x, int y, int Desk,
2295 Bool do_scroll_icon)
2297 static int last_sx = -999999;
2298 static int last_sy = -999999;
2299 int sx;
2300 int sy;
2301 int adjx,adjy;
2303 /* Desk < 0 means we want to scroll an icon window */
2304 if (Desk >= 0 && Desk + desk1 != Scr.CurrentDesk)
2306 return;
2309 /* center around mouse */
2310 adjx = (desk_w / (1 + Scr.VxMax / Scr.MyDisplayWidth));
2311 adjy = (desk_h / (1 + Scr.VyMax / Scr.MyDisplayHeight));
2312 x -= adjx/2;
2313 y -= adjy/2;
2315 /* adjust for pointer going out of range */
2316 if (x < 0)
2318 x = 0;
2320 if (y < 0)
2322 y = 0;
2325 if (x > window_w-adjx)
2327 x = window_w-adjx;
2329 if (y > window_h-adjy)
2331 y = window_h-adjy;
2334 sx = 0;
2335 sy = 0;
2336 if (window_w != 0)
2338 sx = (x * Scr.VWidth / window_w - MyVx);
2340 if (window_h != 0)
2342 sy = (y * Scr.VHeight / window_h - MyVy);
2344 MYFPRINTF((stderr,"[scroll]: %d %d %d %d %d %d\n", window_w, window_h,
2345 x, y, sx, sy));
2346 if (sx == 0 && sy == 0)
2348 return;
2350 if (Wait == 0 || last_sx != sx || last_sy != sy)
2352 do_scroll(sx, sy, False, False);
2354 /* Here we need to track the view offset on the desk. */
2355 /* sx/y are are pixels on the screen to scroll. */
2356 /* We don't use Scr.Vx/y since they lag the true position. */
2357 MyVx += sx;
2358 if (MyVx < 0)
2360 MyVx = 0;
2362 MyVy += sy;
2364 if (MyVy < 0)
2366 MyVy = 0;
2368 Wait = 1;
2370 if (Wait == 0)
2372 last_sx = sx;
2373 last_sy = sy;
2376 return;
2379 void MoveWindow(XEvent *Event)
2381 char command[100];
2382 int x1, y1, wx, wy, n, x, y, xi = 0, yi = 0, wx1, wy1, x2, y2;
2383 int finished = 0;
2384 Window dumwin;
2385 PagerWindow *t;
2386 int m, n1, m1;
2387 int NewDesk, KeepMoving = 0;
2388 int moved = 0;
2389 int row, column;
2390 Window JunkRoot, JunkChild;
2391 int JunkX, JunkY;
2392 unsigned JunkMask;
2393 int do_switch_desk_later = 0;
2395 t = Start;
2396 while (t != NULL && t->PagerView != Event->xbutton.subwindow)
2398 t = t->next;
2401 if (t == NULL)
2403 t = Start;
2404 while (t != NULL && t->IconView != Event->xbutton.subwindow)
2406 t = t->next;
2408 if (t != NULL)
2410 IconMoveWindow(Event, t);
2411 return;
2415 if (t == NULL || !t->allowed_actions.is_movable)
2417 return;
2420 NewDesk = t->desk - desk1;
2421 if (NewDesk < 0 || NewDesk >= ndesks)
2423 return;
2426 n = Scr.VxMax / Scr.MyDisplayWidth;
2427 m = Scr.VyMax / Scr.MyDisplayHeight;
2428 n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
2429 m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
2430 wx = (Scr.Vx + t->x) * (desk_w - n) / Scr.VWidth + n1;
2431 wy = (Scr.Vy + t->y) * (desk_h - m) / Scr.VHeight + m1;
2432 wx1 = wx + (desk_w + 1) * (NewDesk % Columns);
2433 wy1 = wy + label_h + (desk_h + label_h + 1) * (NewDesk / Columns);
2434 if (LabelsBelow)
2436 wy1 -= label_h;
2439 XReparentWindow(dpy, t->PagerView, Scr.Pager_w, wx1, wy1);
2440 XRaiseWindow(dpy, t->PagerView);
2442 XTranslateCoordinates(dpy, Event->xany.window, t->PagerView,
2443 Event->xbutton.x, Event->xbutton.y, &x1, &y1,
2444 &dumwin);
2445 xi = x1;
2446 yi = y1;
2447 while (!finished)
2449 FMaskEvent(dpy, ButtonReleaseMask | ButtonMotionMask |
2450 ExposureMask, Event);
2451 if (Event->type == MotionNotify)
2453 XTranslateCoordinates(dpy, Event->xany.window,
2454 Scr.Pager_w, Event->xmotion.x,
2455 Event->xmotion.y, &x, &y,
2456 &dumwin);
2458 if (moved == 0)
2460 xi = x;
2461 yi = y;
2462 moved = 1;
2464 if (x < -5 || y < -5 || x > window_w + 5 ||
2465 y > window_h + 5)
2467 KeepMoving = 1;
2468 finished = 1;
2470 XMoveWindow(dpy, t->PagerView, x - x1, y - y1);
2472 else if (Event->type == ButtonRelease)
2474 XTranslateCoordinates(dpy, Event->xany.window,
2475 Scr.Pager_w, Event->xbutton.x,
2476 Event->xbutton.y, &x, &y,
2477 &dumwin);
2478 XMoveWindow(dpy, t->PagerView, x - x1, y - y1);
2479 finished = 1;
2481 else if (Event->type == Expose)
2483 HandleExpose(Event);
2487 if (moved)
2489 if (abs(x - xi) < MoveThreshold &&
2490 abs(y - yi) < MoveThreshold)
2492 moved = 0;
2495 if (KeepMoving)
2497 NewDesk = Scr.CurrentDesk;
2499 if (NewDesk >= desk1 && NewDesk <= desk2)
2501 XReparentWindow(dpy, t->PagerView,
2502 Desks[NewDesk-desk1].w, 0, 0);
2504 else
2506 XDestroyWindow(dpy, t->PagerView);
2507 t->PagerView = None;
2509 if (FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
2510 &x, &y, &JunkX, &JunkY, &JunkMask) == False)
2512 /* pointer is on a different screen */
2513 x = 0;
2514 y = 0;
2516 XUngrabPointer(dpy,CurrentTime);
2517 XSync(dpy,0);
2519 if (NewDesk != t->desk)
2521 /* griph: This used to move to NewDesk, but NewDesk
2522 * is current desk, and if fvwm is on another
2523 * desk (due to async operation) we have to move
2524 * the window to it anyway or "Move Pointer" will
2525 * move an invisible window. */
2527 SendText(fd, "Silent MoveToDesk", t->w);
2528 t->desk = NewDesk;
2530 SendText(fd, "Silent Raise", t->w);
2531 SendText(fd, "Silent Move Pointer", t->w);
2532 return;
2534 else
2536 column = x / (desk_w + 1);
2537 if (column >= Columns)
2539 column = Columns - 1;
2541 if (column < 0)
2543 column = 0;
2545 row = y / (desk_h + label_h + 1);
2546 if (row >= Rows)
2548 row = Rows - 1;
2550 if (row < 0)
2552 row = 0;
2554 NewDesk = column + row * Columns;
2555 while (NewDesk < 0)
2557 NewDesk += Columns;
2558 if (NewDesk >= ndesks)
2560 NewDesk = 0;
2563 while (NewDesk >= ndesks)
2565 NewDesk -= Columns;
2566 if (NewDesk < 0)
2568 NewDesk = ndesks - 1;
2571 XTranslateCoordinates(dpy, Scr.Pager_w, Desks[NewDesk].w,
2572 x - x1, y - y1, &x2, &y2, &dumwin);
2574 n1 = x2 * Scr.VWidth / (desk_w * Scr.MyDisplayWidth);
2575 m1 = y2 * Scr.VHeight / (desk_h * Scr.MyDisplayHeight);
2576 x = (x2 - n1) * Scr.VWidth / (desk_w - n) - Scr.Vx;
2577 y = (y2 - m1) * Scr.VHeight / (desk_h - m) - Scr.Vy;
2578 /* force onto desk */
2579 if (x + t->frame_width + Scr.Vx < 0 )
2581 x = -Scr.Vx - t->frame_width;
2583 if (y + t->frame_height + Scr.Vy < 0)
2585 y = -Scr.Vy - t->frame_height;
2587 if (x + Scr.Vx >= Scr.VWidth)
2589 x = Scr.VWidth - Scr.Vx - 1;
2591 if (y + Scr.Vy >= Scr.VHeight)
2593 y = Scr.VHeight - Scr.Vy - 1;
2595 if ((IS_ICONIFIED(t) && IS_ICON_STICKY_ACROSS_DESKS(t)) ||
2596 (IS_STICKY_ACROSS_DESKS(t)))
2598 NewDesk = Scr.CurrentDesk - desk1;
2599 if (x > Scr.MyDisplayWidth - 16)
2601 x = Scr.MyDisplayWidth - 16;
2603 if (y > Scr.MyDisplayHeight - 16)
2605 y = Scr.MyDisplayHeight - 16;
2607 if (x + t->width < 16)
2609 x = 16 - t->width;
2611 if (y + t->height < 16)
2613 y = 16 - t->height;
2616 if (NewDesk + desk1 != t->desk)
2618 if ((IS_ICONIFIED(t) && IS_ICON_STICKY_ACROSS_DESKS(t))
2619 || (IS_STICKY_ACROSS_DESKS(t)))
2621 NewDesk = Scr.CurrentDesk - desk1;
2622 if (t->desk != Scr.CurrentDesk)
2624 ChangeDeskForWindow(t,Scr.CurrentDesk);
2627 else if (NewDesk + desk1 != Scr.CurrentDesk)
2629 sprintf(command, "Silent MoveToDesk 0 %d",
2630 NewDesk + desk1);
2631 SendText(fd, command, t->w);
2632 t->desk = NewDesk + desk1;
2634 else
2636 do_switch_desk_later = 1;
2640 if (NewDesk >= 0 && NewDesk < ndesks)
2642 XReparentWindow(dpy, t->PagerView,
2643 Desks[NewDesk].w, x2, y2);
2644 t->desk = NewDesk;
2645 XClearArea(dpy, t->PagerView, 0, 0, 0, 0, True);
2646 if (moved)
2648 char buf[64];
2649 sprintf(buf, "Silent Move +%dp +%dp", x, y);
2651 SendText(fd, buf, t->w);
2652 XSync(dpy,0);
2654 else
2656 MoveResizePagerView(t, True);
2658 SendText(fd, "Silent Raise", t->w);
2660 if (do_switch_desk_later)
2662 sprintf(command, "Silent MoveToDesk 0 %d", NewDesk +
2663 desk1);
2664 SendText(fd, command, t->w);
2665 t->desk = NewDesk + desk1;
2667 if (Scr.CurrentDesk == t->desk)
2669 XSync(dpy,0);
2670 usleep(5000);
2671 XSync(dpy,0);
2673 SendText(fd, "Silent FlipFocus NoWarp", t->w);
2676 if (is_transient)
2678 /* does not return */
2679 ExitPager();
2686 * Procedure:
2687 * FvwmErrorHandler - displays info on internal errors
2690 int FvwmErrorHandler(Display *dpy, XErrorEvent *event)
2692 #if 1
2693 extern Bool error_occured;
2694 error_occured = True;
2695 return 0;
2696 #else
2697 /* really should just exit here... */
2698 /* domivogt (07-mar-1999): No, not really. See comment above. */
2699 PrintXErrorAndCoredump(dpy, event, MyName);
2700 return 0;
2701 #endif /* 1 */
2704 static void draw_window_border(PagerWindow *t, Window w, int width, int height)
2706 if (w != None)
2708 if (!WindowBorders3d || windowcolorset < 0 || activecolorset < 0)
2710 XSetForeground(dpy, Scr.NormalGC, Scr.black);
2711 RelieveRectangle(
2712 dpy, w, 0, 0, width - 1, t->pager_view_height - 1,
2713 Scr.NormalGC, Scr.NormalGC, WindowBorderWidth);
2715 else if (t == FocusWin)
2717 RelieveRectangle(
2718 dpy, w, 0, 0, width - 1, height - 1,
2719 Scr.ahGC, Scr.asGC, WindowBorderWidth);
2721 else
2723 RelieveRectangle(
2724 dpy, w, 0, 0, width - 1, height - 1,
2725 Scr.whGC, Scr.wsGC, WindowBorderWidth);
2730 void BorderWindow(PagerWindow *t)
2732 draw_window_border(
2733 t, t->PagerView, t->pager_view_width, t->pager_view_height);
2736 void BorderIconWindow(PagerWindow *t)
2738 draw_window_border(
2739 t, t->IconView, t->icon_view_width, t->icon_view_height);
2742 static void do_label_window(PagerWindow *t, Window w)
2744 int cs;
2746 if (t == FocusWin)
2748 XSetForeground(dpy, Scr.NormalGC, focus_fore_pix);
2749 cs = activecolorset;
2751 else
2753 XSetForeground(dpy, Scr.NormalGC, t->text);
2754 cs = windowcolorset;
2757 if (FwindowFont == NULL)
2759 return;
2761 if (MiniIcons && t->mini_icon.picture && (t->PagerView != None))
2763 /* will draw picture instead... */
2764 return;
2766 if (t->icon_name == NULL)
2768 return;
2771 /* Update the window label for this window */
2772 if (t->window_label)
2773 free(t->window_label);
2774 t->window_label = GetBalloonLabel(t, WindowLabelFormat);
2775 if (w != None)
2777 if (FftSupport && FwindowFont != NULL && FwindowFont->fftf.fftfont != NULL)
2778 XClearWindow(dpy, w);
2779 FwinString->str = t->window_label;
2780 FwinString->win = w;
2781 FwinString->gc = Scr.NormalGC;
2782 FwinString->flags.has_colorset = False;
2783 if (cs >= 0)
2785 FwinString->colorset = &Colorset[cs];
2786 FwinString->flags.has_colorset = True;
2788 FwinString->x = 2;
2789 FwinString->y = FwindowFont->ascent+2;
2790 FlocaleDrawString(dpy, FwindowFont, FwinString, 0);
2794 void LabelWindow(PagerWindow *t)
2796 do_label_window(t, t->PagerView);
2799 void LabelIconWindow(PagerWindow *t)
2801 do_label_window(t, t->IconView);
2804 static void do_picture_window(
2805 PagerWindow *t, Window w, int width, int height)
2807 int iconX;
2808 int iconY;
2809 int src_x = 0;
2810 int src_y = 0;
2811 int dest_w, dest_h;
2812 int cs;
2813 FvwmRenderAttributes fra;
2815 if (MiniIcons)
2817 if (t->mini_icon.picture && w != None)
2819 dest_w = t->mini_icon.width;
2820 dest_h = t->mini_icon.height;
2821 if (width > t->mini_icon.width)
2823 iconX = (width - t->mini_icon.width) / 2;
2825 else if (width < t->mini_icon.width)
2827 iconX = 0;
2828 src_x = (t->mini_icon.width - width) / 2;
2829 dest_w = width;
2831 else
2833 iconX = 0;
2835 if (height > t->mini_icon.height)
2837 iconY = (height - t->mini_icon.height) / 2;
2839 else if (height < t->mini_icon.height)
2841 iconY = 0;
2842 src_y = (t->mini_icon.height - height) / 2;
2843 dest_h = height;
2845 else
2847 iconY = 0;
2849 fra.mask = FRAM_DEST_IS_A_WINDOW;
2850 if (t == FocusWin)
2852 cs = activecolorset;
2854 else
2856 cs = windowcolorset;
2858 if (t->mini_icon.alpha != None ||
2859 (cs >= 0 &&
2860 Colorset[cs].icon_alpha_percent < 100))
2862 XClearArea(dpy, w, iconX, iconY,
2863 t->mini_icon.width,
2864 t->mini_icon.height, False);
2866 if (cs >= 0)
2868 fra.mask |= FRAM_HAVE_ICON_CSET;
2869 fra.colorset = &Colorset[cs];
2871 PGraphicsRenderPicture(
2872 dpy, w, &t->mini_icon, &fra, w,
2873 Scr.MiniIconGC, None, None, src_x, src_y,
2874 t->mini_icon.width - src_x,
2875 t->mini_icon.height - src_y,
2876 iconX, iconY, dest_w, dest_h, False);
2881 void PictureWindow (PagerWindow *t)
2883 do_picture_window(t, t->PagerView, t->pager_view_width, t->pager_view_height);
2886 void PictureIconWindow (PagerWindow *t)
2888 do_picture_window(t, t->IconView, t->icon_view_width, t->icon_view_height);
2891 void IconMoveWindow(XEvent *Event, PagerWindow *t)
2893 int x1, y1, finished = 0, wx, wy, n, x = 0, y = 0, xi = 0, yi = 0;
2894 Window dumwin;
2895 int m, n1, m1;
2896 int moved = 0;
2897 int KeepMoving = 0;
2898 Window JunkRoot, JunkChild;
2899 int JunkX, JunkY;
2900 unsigned JunkMask;
2902 if (t == NULL || !t->allowed_actions.is_movable)
2904 return;
2907 n = Scr.VxMax / Scr.MyDisplayWidth;
2908 m = Scr.VyMax / Scr.MyDisplayHeight;
2909 n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
2910 m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
2911 wx = (Scr.Vx + t->x) * (icon_w - n) / Scr.VWidth + n1;
2912 wy = (Scr.Vy + t->y) * (icon_h - m) / Scr.VHeight + m1;
2914 XRaiseWindow(dpy, t->IconView);
2916 XTranslateCoordinates(dpy, Event->xany.window, t->IconView,
2917 Event->xbutton.x, Event->xbutton.y, &x1, &y1,
2918 &dumwin);
2919 while (!finished)
2921 FMaskEvent(dpy, ButtonReleaseMask | ButtonMotionMask |
2922 ExposureMask, Event);
2924 if (Event->type == MotionNotify)
2926 x = Event->xbutton.x;
2927 y = Event->xbutton.y;
2928 if (moved == 0)
2930 xi = x;
2931 yi = y;
2932 moved = 1;
2935 XMoveWindow(dpy, t->IconView, x - x1, y - y1);
2936 if (x < -5 || y < -5 || x > icon_w + 5 ||
2937 y > icon_h + 5)
2939 finished = 1;
2940 KeepMoving = 1;
2943 else if (Event->type == ButtonRelease)
2945 x = Event->xbutton.x;
2946 y = Event->xbutton.y;
2947 XMoveWindow(dpy, t->PagerView, x - x1, y - y1);
2948 finished = 1;
2950 else if (Event->type == Expose)
2952 HandleExpose(Event);
2956 if (moved)
2958 if (abs(x - xi) < MoveThreshold &&
2959 abs(y - yi) < MoveThreshold)
2961 moved = 0;
2965 if (KeepMoving)
2967 if (FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
2968 &x, &y, &JunkX, &JunkY, &JunkMask) == False)
2970 /* pointer is on a different screen */
2971 x = 0;
2972 y = 0;
2974 XUngrabPointer(dpy, CurrentTime);
2975 XSync(dpy, 0);
2976 SendText(fd, "Silent Raise", t->w);
2977 SendText(fd, "Silent Move Pointer", t->w);
2979 else
2981 x = x - x1;
2982 y = y - y1;
2983 n1 = x * Scr.VWidth / (icon_w * Scr.MyDisplayWidth);
2984 m1 = y * Scr.VHeight / (icon_h * Scr.MyDisplayHeight);
2985 x = (x - n1) * Scr.VWidth / (icon_w - n) - Scr.Vx;
2986 y = (y - m1) * Scr.VHeight / (icon_h - m) - Scr.Vy;
2987 /* force onto desk */
2988 if (x + t->icon_width + Scr.Vx < 0 )
2990 x = - Scr.Vx - t->icon_width;
2992 if (y + t->icon_height + Scr.Vy < 0)
2994 y = - Scr.Vy - t->icon_height;
2996 if (x + Scr.Vx >= Scr.VWidth)
2998 x = Scr.VWidth - Scr.Vx - 1;
3000 if (y + Scr.Vy >= Scr.VHeight)
3002 y = Scr.VHeight - Scr.Vy - 1;
3004 if ((IS_ICONIFIED(t) && IS_ICON_STICKY_ACROSS_DESKS(t)) ||
3005 IS_STICKY_ACROSS_DESKS(t))
3007 if (x > Scr.MyDisplayWidth - 16)
3009 x = Scr.MyDisplayWidth - 16;
3011 if (y > Scr.MyDisplayHeight - 16)
3013 y = Scr.MyDisplayHeight - 16;
3015 if (x + t->width < 16)
3017 x = 16 - t->width;
3019 if (y + t->height < 16)
3021 y = 16 - t->height;
3024 if (moved)
3026 char buf[64];
3027 sprintf(buf, "Silent Move +%dp +%dp", x, y);
3028 SendText(fd, buf, t->w);
3029 XSync(dpy, 0);
3031 else
3033 MoveResizePagerView(t, True);
3035 SendText(fd, "Silent Raise", t->w);
3036 SendText(fd, "Silent FlipFocus NoWarp", t->w);
3038 if (is_transient)
3040 /* does not return */
3041 ExitPager();
3046 void setup_balloon_window(int i)
3048 XSetWindowAttributes xswa;
3049 unsigned long valuemask;
3051 if (!ShowBalloons && Scr.balloon_w == None)
3053 return;
3055 XUnmapWindow(dpy, Scr.balloon_w);
3056 if (Desks[i].ballooncolorset < 0)
3058 xswa.border_pixel = (!BalloonBorderColor) ?
3059 fore_pix : GetColor(BalloonBorderColor);
3060 xswa.background_pixel =
3061 (!BalloonBack) ? back_pix : GetColor(BalloonBack);
3062 valuemask = CWBackPixel | CWBorderPixel;
3064 else
3066 xswa.border_pixel = Colorset[Desks[i].ballooncolorset].fg;
3067 xswa.background_pixel = Colorset[Desks[i].ballooncolorset].bg;
3068 if (Colorset[Desks[i].ballooncolorset].pixmap)
3070 /* set later */
3071 xswa.background_pixmap = None;
3072 valuemask = CWBackPixmap | CWBorderPixel;;
3074 else
3076 valuemask = CWBackPixel | CWBorderPixel;
3079 XChangeWindowAttributes(dpy, Scr.balloon_w, valuemask, &xswa);
3081 return;
3084 void setup_balloon_gc(int i, PagerWindow *t)
3086 XGCValues xgcv;
3087 unsigned long valuemask;
3089 valuemask = GCForeground;
3090 if (Desks[i].ballooncolorset < 0)
3092 xgcv.foreground =
3093 (!BalloonFore) ? fore_pix : GetColor(BalloonFore);
3094 if (BalloonFore == NULL)
3096 XSetForeground(dpy, Scr.balloon_gc, t->text);
3099 else
3101 xgcv.foreground = Colorset[Desks[i].ballooncolorset].fg;
3103 if (Desks[i].balloon.Ffont->font != NULL)
3105 xgcv.font = Desks[i].balloon.Ffont->font->fid;
3106 valuemask |= GCFont;
3108 XChangeGC(dpy, Scr.balloon_gc, valuemask, &xgcv);
3110 return;
3113 /* Just maps window ... draw stuff in it later after Expose event
3114 -- ric@giccs.georgetown.edu */
3115 void MapBalloonWindow(PagerWindow *t, Bool is_icon_view)
3117 extern char *BalloonBack;
3118 extern int BalloonYOffset;
3119 extern int BalloonBorderWidth;
3120 Window view, dummy;
3121 int view_width, view_height;
3122 int x, y;
3123 rectangle new_g;
3124 int i;
3126 if (!is_icon_view)
3128 view = t->PagerView;
3129 view_width = t->pager_view_width;
3130 view_height = t->pager_view_height;
3132 else
3134 view = t->IconView;
3135 view_width = t->icon_view_width;
3136 view_height = t->icon_view_height;
3138 BalloonView = view;
3139 /* associate balloon with its pager window */
3140 if (fAlwaysCurrentDesk)
3142 i = 0;
3144 else
3146 i = t->desk - desk1;
3148 Scr.balloon_desk = i;
3149 /* get the label for this balloon */
3150 if (Scr.balloon_label)
3152 free(Scr.balloon_label);
3154 Scr.balloon_label = GetBalloonLabel(t, BalloonFormatString);
3155 #if 0
3156 if (Scr.balloon_label == NULL)
3158 /* dont draw empty labels */
3159 return;
3161 #endif
3162 setup_balloon_window(i);
3163 setup_balloon_gc(i, t);
3164 /* calculate window width to accommodate string */
3165 new_g.height = Desks[i].balloon.height;
3166 new_g.width = 4;
3167 if (Scr.balloon_label)
3169 new_g.width += FlocaleTextWidth(
3170 Desks[i].balloon.Ffont, Scr.balloon_label,
3171 strlen(Scr.balloon_label));
3173 /* get x and y coords relative to pager window */
3174 x = (view_width / 2) - (new_g.width / 2) - BalloonBorderWidth;
3175 if (BalloonYOffset > 0)
3177 y = view_height + BalloonYOffset - 1;
3179 else
3181 y = BalloonYOffset - new_g.height + 1 -
3182 (2 * BalloonBorderWidth);
3184 /* balloon is a top-level window, therefore need to
3185 translate pager window coords to root window coords */
3186 XTranslateCoordinates(
3187 dpy, view, Scr.Root, x, y, &new_g.x, &new_g.y,
3188 &dummy);
3189 /* make sure balloon doesn't go off screen
3190 * (actually 2 pixels from edge rather than 0 just to be pretty :-) */
3191 /* too close to top ... make yoffset +ve */
3192 if ( new_g.y < 2 )
3194 y = - BalloonYOffset - 1 + view_height;
3195 XTranslateCoordinates(
3196 dpy, view, Scr.Root, x, y, &new_g.x, &new_g.y, &dummy);
3198 /* too close to bottom ... make yoffset -ve */
3199 else if ( new_g.y + new_g.height >
3200 Scr.MyDisplayHeight - (2 * BalloonBorderWidth) - 2 )
3202 y = - BalloonYOffset + 1 - new_g.height -
3203 (2 * BalloonBorderWidth);
3204 XTranslateCoordinates(
3205 dpy, view, Scr.Root, x, y, &new_g.x, &new_g.y, &dummy);
3207 /* too close to left */
3208 if ( new_g.x < 2 )
3210 new_g.x = 2;
3212 /* too close to right */
3213 else if (new_g.x + new_g.width >
3214 Scr.MyDisplayWidth - (2 * BalloonBorderWidth) - 2 )
3216 new_g.x = Scr.MyDisplayWidth - new_g.width -
3217 (2 * BalloonBorderWidth) - 2;
3219 /* make changes to window */
3220 XMoveResizeWindow(
3221 dpy, Scr.balloon_w, new_g.x, new_g.y, new_g.width,
3222 new_g.height);
3223 /* if background not set in config make it match pager window */
3224 if ( BalloonBack == NULL )
3226 XSetWindowBackground(dpy, Scr.balloon_w, t->back);
3228 if (Desks[i].ballooncolorset > -1)
3230 SetWindowBackground(
3231 dpy, Scr.balloon_w, new_g.width, new_g.height,
3232 &Colorset[Desks[i].ballooncolorset], Pdepth,
3233 Scr.NormalGC, True);
3234 XSetWindowBorder(
3235 dpy, Scr.balloon_w,
3236 Colorset[Desks[i].ballooncolorset].fg);
3238 XMapRaised(dpy, Scr.balloon_w);
3240 return;
3244 static void InsertExpand(char **dest, char *s)
3246 int len;
3247 char *tmp = *dest;
3249 if (!s || !*s)
3250 return;
3251 len = strlen(*dest) + strlen(s) + 1;
3252 *dest = (char *)safemalloc(len);
3253 strcpy(*dest, tmp);
3254 free(tmp);
3255 strcat(*dest, s);
3256 return;
3260 /* Generate the BallonLabel from the format string
3261 -- disching@fmi.uni-passau.de */
3262 char *GetBalloonLabel(const PagerWindow *pw,const char *fmt)
3264 char *dest = safestrdup("");
3265 const char *pos = fmt;
3266 char buffer[2];
3268 buffer[1] = '\0';
3270 while (*pos) {
3271 if (*pos=='%' && *(pos+1)!='\0') {
3272 pos++;
3273 switch (*pos) {
3274 case 'i':
3275 InsertExpand(&dest, pw->icon_name);
3276 break;
3277 case 't':
3278 InsertExpand(&dest, pw->window_name);
3279 break;
3280 case 'r':
3281 InsertExpand(&dest, pw->res_name);
3282 break;
3283 case 'c':
3284 InsertExpand(&dest, pw->res_class);
3285 break;
3286 case '%':
3287 buffer[0] = '%';
3288 InsertExpand(&dest, buffer);
3289 break;
3290 default:;
3292 } else {
3293 buffer[0] = *pos;
3294 InsertExpand(&dest, buffer);
3296 pos++;
3298 return dest;
3302 /* -- ric@giccs.georgetown.edu */
3303 void UnmapBalloonWindow (void)
3305 XUnmapWindow(dpy, Scr.balloon_w);
3306 BalloonView = None;
3310 /* Draws string in balloon window -- call after it's received Expose event
3311 -- ric@giccs.georgetown.edu */
3312 void DrawInBalloonWindow (int i)
3314 FwinString->str = Scr.balloon_label;
3315 FwinString->win = Scr.balloon_w;
3316 FwinString->gc = Scr.balloon_gc;
3317 if (Desks[i].ballooncolorset >= 0)
3319 FwinString->colorset = &Colorset[Desks[i].ballooncolorset];
3320 FwinString->flags.has_colorset = True;
3322 else
3324 FwinString->flags.has_colorset = False;
3326 FwinString->x = 2;
3327 FwinString->y = Desks[i].balloon.Ffont->ascent;
3328 FlocaleDrawString(dpy, Desks[i].balloon.Ffont, FwinString, 0);
3330 return;
3333 static void set_window_colorset_background(
3334 PagerWindow *t, colorset_t *csetp)
3336 if (t->PagerView != None)
3338 SetWindowBackground(
3339 dpy, t->PagerView, t->pager_view_width, t->pager_view_height,
3340 csetp, Pdepth, Scr.NormalGC, True);
3342 SetWindowBackground(
3343 dpy, t->IconView, t->icon_view_width, t->icon_view_height,
3344 csetp, Pdepth, Scr.NormalGC, True);
3346 return;
3349 /* should be in sync with draw_desk_background */
3350 void change_colorset(int colorset)
3352 int i;
3353 PagerWindow *t;
3355 /* just in case */
3356 if (colorset < 0)
3357 return;
3359 XSetWindowBackgroundPixmap(dpy, Scr.Pager_w, default_pixmap);
3360 for(i=0;i<ndesks;i++)
3362 if (Desks[i].highcolorset == colorset)
3364 XSetForeground(dpy, Desks[i].HiliteGC,Colorset[colorset].bg);
3365 XSetForeground(dpy, Desks[i].rvGC, Colorset[colorset].fg);
3366 if (HilightDesks)
3368 if (uselabel && (i == Scr.CurrentDesk))
3370 SetWindowBackground(
3371 dpy, Desks[i].title_w, desk_w, desk_h, &Colorset[colorset], Pdepth,
3372 Scr.NormalGC, True);
3374 SetWindowBackground(
3375 dpy, Desks[i].CPagerWin, 0, 0, &Colorset[colorset], Pdepth,
3376 Scr.NormalGC, True);
3377 XLowerWindow(dpy,Desks[i].CPagerWin);
3381 if (Desks[i].colorset == colorset)
3383 XSetWindowBorder(dpy, Desks[i].title_w, Colorset[colorset].fg);
3384 XSetWindowBorder(dpy, Desks[i].w, Colorset[colorset].fg);
3385 XSetForeground(dpy, Desks[i].NormalGC,Colorset[colorset].fg);
3386 XSetForeground(dpy, Desks[i].DashedGC,Colorset[colorset].fg);
3387 if (uselabel)
3389 SetWindowBackground(
3390 dpy, Desks[i].title_w, desk_w, desk_h + label_h, &Colorset[colorset],
3391 Pdepth, Scr.NormalGC, True);
3393 if (label_h != 0 && uselabel && !LabelsBelow &&
3394 !CSET_IS_TRANSPARENT_PR(Desks[i].colorset))
3396 SetWindowBackgroundWithOffset(
3397 dpy, Desks[i].w, 0, -label_h, desk_w, desk_h + label_h,
3398 &Colorset[colorset], Pdepth, Scr.NormalGC, True);
3400 else
3402 SetWindowBackground(
3403 dpy, Desks[i].w, desk_w, desk_h + label_h,
3404 &Colorset[Desks[i].colorset], Pdepth, Scr.NormalGC, True);
3406 update_pr_transparent_subwindows(i);
3408 else if (Desks[i].highcolorset == colorset && uselabel)
3410 SetWindowBackground(
3411 dpy, Desks[i].title_w, 0, 0, &Colorset[Desks[i].colorset], Pdepth,
3412 Scr.NormalGC, True);
3415 if (ShowBalloons && Desks[Scr.balloon_desk].ballooncolorset == colorset)
3417 XSetWindowBackground(dpy, Scr.balloon_w, Colorset[colorset].fg);
3418 XSetForeground(dpy,Scr.balloon_gc, Colorset[colorset].fg);
3419 XClearArea(dpy, Scr.balloon_w, 0, 0, 0, 0, True);
3422 if (windowcolorset == colorset)
3424 colorset_t *csetp = &Colorset[colorset];
3426 XSetForeground(dpy, Scr.whGC, csetp->hilite);
3427 XSetForeground(dpy, Scr.wsGC, csetp->shadow);
3428 win_back_pix = csetp->bg;
3429 win_fore_pix = csetp->fg;
3430 win_pix_set = True;
3431 for (t = Start; t != NULL; t = t->next)
3433 t->text = Colorset[colorset].fg;
3434 if (t != FocusWin)
3436 set_window_colorset_background(t, csetp);
3440 if (activecolorset == colorset)
3442 colorset_t *csetp = &Colorset[colorset];
3444 focus_fore_pix = csetp->fg;
3445 XSetForeground(dpy, Scr.ahGC, csetp->hilite);
3446 XSetForeground(dpy, Scr.asGC, csetp->shadow);
3447 win_hi_back_pix = csetp->bg;
3448 win_hi_fore_pix = csetp->fg;
3449 win_hi_pix_set = True;
3450 if (FocusWin)
3452 set_window_colorset_background(FocusWin, csetp);
3456 return;