1 /* -*-c-*- */
2 /*
3  * This module is all new
4  * by Rob Nation
5  */
6 
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.
11  *
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.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see: <http://www.gnu.org/licenses/>
19  */
20 
21 /*
22  *
23  * fvwm pager handling code
24  *
25  */
26 
27 #include "config.h"
28 
29 #include <stdio.h>
30 #include <signal.h>
31 
32 #include <X11/Xlib.h>
33 #include <X11/Xutil.h>
34 #include <X11/Xproto.h>
35 #include <X11/Xatom.h>
36 #include <X11/Intrinsic.h>
37 #include <X11/keysym.h>
38 
39 #include "libs/fvwmlib.h"
40 #include "libs/FScreen.h"
41 #include "libs/FShape.h"
42 #include "libs/Module.h"
43 #include "libs/Colorset.h"
44 #include "libs/Graphics.h"
45 #include "fvwm/fvwm.h"
46 #include "libs/PictureGraphics.h"
47 #include "FvwmPager.h"
48 
49 
50 extern ScreenInfo Scr;
51 extern Display *dpy;
52 
53 Pixel back_pix, fore_pix, hi_pix;
54 Pixel focus_pix;
55 Pixel focus_fore_pix;
56 extern int windowcolorset, activecolorset;
57 extern Pixel win_back_pix, win_fore_pix, win_hi_back_pix, win_hi_fore_pix;
58 extern Bool win_pix_set, win_hi_pix_set;
59 extern int window_w, window_h,window_x,window_y,usposition,uselabel,xneg,yneg;
60 extern int StartIconic;
61 extern int MiniIcons;
62 extern int LabelsBelow;
63 extern int ShapeLabels;
64 extern int ShowBalloons, ShowPagerBalloons, ShowIconBalloons;
65 extern char *BalloonFormatString;
66 extern char *WindowLabelFormat;
67 extern char *PagerFore, *PagerBack, *HilightC;
68 extern char *BalloonFore, *BalloonBack, *BalloonBorderColor;
69 extern Window BalloonView;
70 extern unsigned int WindowBorderWidth;
71 extern unsigned int MinSize;
72 extern Bool WindowBorders3d;
73 extern Bool UseSkipList;
74 extern FvwmPicture *PixmapBack;
75 extern FvwmPicture *HilightPixmap;
76 extern int HilightDesks;
77 extern char fAlwaysCurrentDesk;
78 
79 extern int MoveThreshold;
80 
81 extern int icon_w, icon_h, icon_x, icon_y, icon_xneg, icon_yneg;
82 FlocaleFont *Ffont, *FwindowFont;
83 FlocaleWinString *FwinString;
84 
85 extern PagerWindow *Start;
86 extern PagerWindow *FocusWin;
87 static Atom wm_del_win;
88 
89 extern char *MyName;
90 
91 extern int desk1, desk2, ndesks;
92 extern int Rows,Columns;
93 extern int fd[2];
94 
95 int desk_w = 0;
96 int desk_h = 0;
97 int label_h = 0;
98 
99 DeskInfo *Desks;
100 int Wait = 0;
101 int FvwmErrorHandler(Display *, XErrorEvent *);
102 extern Bool is_transient;
103 extern Bool do_ignore_next_button_release;
104 extern Bool use_dashed_separators;
105 extern Bool use_no_separators;
106 
107 
108 /* assorted gray bitmaps for decorative borders */
109 #define g_width 2
110 #define g_height 2
111 static char g_bits[] = {0x02, 0x01};
112 
113 #define l_g_width 4
114 #define l_g_height 2
115 static char l_g_bits[] = {0x08, 0x02};
116 
117 #define s_g_width 4
118 #define s_g_height 4
119 static char s_g_bits[] = {0x01, 0x02, 0x04, 0x08};
120 
121 #define label_border g_width
122 
123 Window icon_win;	       /* icon window */
124 
125 static int MyVx, MyVy;		/* copy of Scr.Vx/y for drag logic */
126 
127 static char *GetBalloonLabel(const PagerWindow *pw,const char *fmt);
128 extern void ExitPager(void);
129 
130 Pixmap default_pixmap = None;
131 
132 #ifdef DEBUG
133 #define MYFPRINTF(X) \
134   fprintf X;\
135   fflush (stderr);
136 #else
137 #define MYFPRINTF(X)
138 #endif
139 
140 
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. */
do_scroll(int sx,int sy,Bool do_send_message,Bool is_message_recieved)146 static void do_scroll(int sx, int sy, Bool do_send_message,
147 		      Bool is_message_recieved)
148 {
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)
156 	{
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)
161 		{
162 			messages_sent = 0;
163 		}
164 	}
165 	if ((do_send_message || messages_sent < MAX_UNPROCESSED_MESSAGES) &&
166 	    ( psx != 0 || psy != 0 ))
167 	{
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;
174 	}
175 }
176 
HandleScrollDone(void)177 void HandleScrollDone(void)
178 {
179 	do_scroll(0, 0, True, True);
180 }
181 
182 typedef struct
183 {
184 	int event_type;
185 	XEvent *ret_last_event;
186 } _weed_window_events_args;
187 
_pred_weed_window_events(Display * display,XEvent * current_event,XPointer arg)188 static int _pred_weed_window_events(
189 	Display *display, XEvent *current_event, XPointer arg)
190 {
191 	_weed_window_events_args *args = (_weed_window_events_args *)arg;
192 
193 	if (current_event->type == args->event_type)
194 	{
195 		if (args->ret_last_event != NULL)
196 		{
197 			*args->ret_last_event = *current_event;
198 		}
199 
200 		return 1;
201 	}
202 
203 	return 0;
204 }
205 
206 /* discard certain events on a window */
discard_events(long event_type,Window w,XEvent * last_ev)207 static void discard_events(long event_type, Window w, XEvent *last_ev)
208 {
209 	_weed_window_events_args args;
210 
211 	XSync(dpy, 0);
212 	args.event_type = event_type;
213 	args.ret_last_event = last_ev;
214 	FWeedIfWindowEvents(dpy, w, _pred_weed_window_events, (XPointer)&args);
215 
216 	return;
217 }
218 
219 /*
220  *
221  *  Procedure:
222  *	CalcGeom - calculates the size and position of a mini-window
223  *	given the real window size.
224  *	You can always tell bad code by the size of the comments.
225  */
CalcGeom(PagerWindow * t,int win_w,int win_h,int * x_ret,int * y_ret,int * w_ret,int * h_ret)226 static void CalcGeom(PagerWindow *t, int win_w, int win_h,
227 		     int *x_ret, int *y_ret, int *w_ret, int *h_ret)
228 {
229   int virt, virt2, edge, edge2, size, page, over;
230 
231   /* coordinate of left hand edge on virtual desktop */
232   virt = Scr.Vx + t->x;
233 
234   /* position of left hand edge of mini-window on pager window */
235   edge = (virt * win_w) / Scr.VWidth;
236 
237   /* absolute coordinate of right hand edge on virtual desktop */
238   virt += t->width - 1;
239 
240   /* to calculate the right edge, mirror the window and use the same
241    * calculations as for the left edge for consistency. */
242   virt2 = Scr.VWidth - 1 - virt;
243   edge2 = (virt2 * win_w) / Scr.VWidth;
244 
245   /* then mirror it back to get the real coordinate */
246   edge2 = win_w - 1 - edge2;
247 
248   /* Calculate the mini-window's width by subtracting its LHS
249    * from its RHS. This theoretically means that the width will
250    * vary slightly as the window travels around the screen, but
251    * this way ensures that the mini-windows in the pager match
252    * the actual screen layout. */
253   size = edge2 - edge + 1;
254 
255   /* Make size big enough to be visible */
256   if (size < MinSize) {
257     size = MinSize;
258     /* this mini-window has to be grown to be visible
259      * which way it grows depends on some magic:
260      * normally it will grow right but if the window is on the right hand
261      * edge of a page it should be grown left so that the pager looks better */
262 
263     /* work out the page that the right hand edge is on */
264     page = virt / Scr.MyDisplayWidth;
265 
266     /* if the left edge is on the same page then possibly move it left */
267     if (page == ((virt - t->width + 1) / Scr.MyDisplayWidth)) {
268       /* calculate how far the mini-window right edge overlaps the page line */
269       /* beware that the "over" is actually one greater than on screen, but
270 	 this discrepancy is catered for in the next two lines */
271       over = edge + size - ((page + 1) * win_w * Scr.MyDisplayWidth) /
272 	Scr.VWidth;
273 
274       /* if the mini-window right edge is beyond the mini-window pager grid */
275       if (over > 0) {
276 	/* move it left by the amount of pager grid overlap (!== the growth) */
277 	edge -= over;
278       }
279     }
280   }
281   /* fill in return values */
282   *x_ret = edge;
283   *w_ret = size;
284 
285   /* same code for y axis */
286   virt = Scr.Vy + t->y;
287   edge = (virt * win_h) / Scr.VHeight;
288   virt += t->height - 1;
289   virt2 = Scr.VHeight - 1 - virt;
290   edge2 = (virt2 * win_h) / Scr.VHeight;
291   edge2 = win_h - 1 - edge2;
292   size = edge2 - edge + 1;
293   if (size < MinSize)
294   {
295     size = MinSize;
296     page = virt / Scr.MyDisplayHeight;
297     if (page == ((virt - t->height + 1) / Scr.MyDisplayHeight)) {
298       over = edge + size - ((page + 1) * win_h * Scr.MyDisplayHeight) /
299 	Scr.VHeight;
300       if (over > 0)
301 	edge -= over;
302     }
303   }
304   *y_ret = edge;
305   *h_ret = size;
306 }
307 
308 /*
309  *
310  *  Procedure:
311  *	Initialize_viz_pager - creates a temp window of the correct visual
312  *	so that pixmaps may be created for use with the main window
313  */
initialize_viz_pager(void)314 void initialize_viz_pager(void)
315 {
316 	XSetWindowAttributes attr;
317 	XGCValues xgcv;
318 
319 	/* FIXME: I think that we only need that Pdepth ==
320 	 * DefaultDepth(dpy, Scr.screen) to use the Scr.Root for Scr.Pager_w */
321 	if (Pdefault)
322 	{
323 		Scr.Pager_w = Scr.Root;
324 	}
325 	else
326 	{
327 		attr.background_pixmap = None;
328 		attr.border_pixel = 0;
329 		attr.colormap = Pcmap;
330 		Scr.Pager_w = XCreateWindow(
331 			dpy, Scr.Root, -10, -10, 10, 10, 0, Pdepth,
332 			InputOutput, Pvisual,
333 			CWBackPixmap|CWBorderPixel|CWColormap, &attr);
334 		Scr.NormalGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, 0, &xgcv);
335 	}
336 	Scr.NormalGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, 0, NULL);
337 
338 	xgcv.plane_mask = AllPlanes;
339 	Scr.MiniIconGC = fvwmlib_XCreateGC(
340 		dpy, Scr.Pager_w, GCPlaneMask, &xgcv);
341 	Scr.black = GetColor("Black");
342 
343 	/* Transparent background are only allowed when the depth matched the
344 	 * root */
345 	if (Pdepth == DefaultDepth(dpy, Scr.screen))
346 	{
347 		default_pixmap = ParentRelative;
348 	}
349 
350 	return;
351 }
352 
353 /* see also change colorset */
draw_desk_background(int i,int page_w,int page_h)354 void draw_desk_background(int i, int page_w, int page_h)
355 {
356 	if (Desks[i].colorset > -1)
357 	{
358 		XSetWindowBorder(
359 			dpy, Desks[i].title_w, Colorset[Desks[i].colorset].fg);
360 		XSetWindowBorder(
361 			dpy, Desks[i].w, Colorset[Desks[i].colorset].fg);
362 		XSetForeground(
363 			dpy, Desks[i].NormalGC,Colorset[Desks[i].colorset].fg);
364 		XSetForeground(
365 			dpy, Desks[i].DashedGC,Colorset[Desks[i].colorset].fg);
366 		if (uselabel)
367 		{
368 			if (CSET_IS_TRANSPARENT(Desks[i].colorset))
369 			{
370 					SetWindowBackground(
371 						dpy, Desks[i].title_w,
372 						desk_w, label_h,
373 						&Colorset[Desks[i].colorset],
374 						Pdepth,
375 						Scr.NormalGC, True);
376 			}
377 			else
378 			{
379 				SetWindowBackground(
380 					dpy, Desks[i].title_w, desk_w,
381 					desk_h + label_h,
382 					&Colorset[Desks[i].colorset], Pdepth,
383 					Scr.NormalGC, True);
384 			}
385 		}
386 		if (label_h != 0 && uselabel && !LabelsBelow &&
387 		    !CSET_IS_TRANSPARENT(Desks[i].colorset))
388 		{
389 			SetWindowBackgroundWithOffset(
390 				dpy, Desks[i].w, 0, -label_h, desk_w,
391 				desk_h + label_h, &Colorset[Desks[i].colorset],
392 				Pdepth, Scr.NormalGC, True);
393 		}
394 		else
395 		{
396 			if (CSET_IS_TRANSPARENT(Desks[i].colorset))
397 			{
398 				SetWindowBackground(
399 					dpy, Desks[i].w, desk_w, desk_h,
400 					&Colorset[Desks[i].colorset], Pdepth,
401 					Scr.NormalGC, True);
402 			}
403 			else
404 			{
405 				SetWindowBackground(
406 					dpy, Desks[i].w, desk_w,
407 					desk_h + label_h,
408 					&Colorset[Desks[i].colorset],
409 					Pdepth, Scr.NormalGC, True);
410 			}
411 		}
412 	}
413 	XClearArea(dpy,Desks[i].w, 0, 0, 0, 0,True);
414 	if (Desks[i].highcolorset > -1)
415 	{
416 		XSetForeground(
417 			dpy, Desks[i].HiliteGC,
418 			Colorset[Desks[i].highcolorset].bg);
419 		XSetForeground(
420 			dpy, Desks[i].rvGC, Colorset[Desks[i].highcolorset].fg);
421 		if (HilightDesks)
422 		{
423 			SetWindowBackground(
424 				dpy, Desks[i].CPagerWin, page_w, page_h,
425 				&Colorset[Desks[i].highcolorset], Pdepth,
426 				Scr.NormalGC, True);
427 		}
428 	}
429 	if (uselabel)
430 	{
431 		XClearArea(dpy,Desks[i].title_w, 0, 0, 0, 0,True);
432 	}
433 
434 	return;
435 }
436 
437 /*
438  *
439  *  Procedure:
440  *	Initialize_pager - creates the pager window, if needed
441  *
442  *  Inputs:
443  *	x,y location of the window
444  *
445  */
446 char *pager_name = "Fvwm Pager";
447 XSizeHints sizehints =
448 {
449   (PMinSize | PResizeInc | PBaseSize | PWinGravity),
450   0, 0, 100, 100,			/* x, y, width and height */
451   1, 1,					/* Min width and height */
452   0, 0,					/* Max width and height */
453   1, 1,					/* Width and height increments */
454   {0, 0}, {0, 0},			/* Aspect ratio - not used */
455   1, 1,					/* base size */
456   (NorthWestGravity)			/* gravity */
457 };
458 
initialize_balloon_window(void)459 void initialize_balloon_window(void)
460 {
461 	XGCValues xgcv;
462 	unsigned long valuemask;
463 	XSetWindowAttributes attributes;
464 	extern int BalloonBorderWidth;
465 
466 	/* create balloon window
467 	   -- ric@giccs.georgetown.edu */
468 	if (!ShowBalloons)
469 	{
470 		Scr.balloon_w = None;
471 		return;
472 	}
473 	valuemask = CWOverrideRedirect | CWEventMask | CWColormap;
474 	/* tell WM to ignore this window */
475 	attributes.override_redirect = True;
476 	attributes.event_mask = ExposureMask;
477 	attributes.colormap = Pcmap;
478 	/* now create the window */
479 	Scr.balloon_w = XCreateWindow(
480 		dpy, Scr.Root, 0, 0, /* coords set later */ 1, 1,
481 		BalloonBorderWidth, Pdepth, InputOutput, Pvisual, valuemask,
482 		&attributes);
483 	Scr.balloon_gc = fvwmlib_XCreateGC(dpy, Scr.balloon_w, 0, &xgcv);
484 	/* Make sure we don't get balloons initially with the Icon option. */
485 	ShowBalloons = ShowPagerBalloons;
486 
487 	return;
488 }
489 
initialize_pager(void)490 void initialize_pager(void)
491 {
492   XWMHints wmhints;
493   XClassHint class1;
494   XTextProperty name;
495   unsigned long valuemask;
496   XSetWindowAttributes attributes;
497   extern char *WindowBack, *WindowFore, *WindowHiBack, *WindowHiFore;
498   extern char *BalloonFont;
499   extern char *font_string, *smallFont;
500   int n,m,w,h,i,x,y;
501   XGCValues gcv;
502   char dash_list[2];
503   FlocaleFont *balloon_font;
504 
505   /* I don't think that this is necessary - just let pager die */
506   /* domivogt (07-mar-1999): But it is! A window being moved in the pager
507    * might die at any moment causing the Xlib calls to generate BadMatch
508    * errors. Without an error handler the pager will die! */
509   XSetErrorHandler(FvwmErrorHandler);
510 
511   wm_del_win = XInternAtom(dpy,"WM_DELETE_WINDOW",False);
512 
513   /* load the font */
514   /* Note: "font" is always created, whether labels are used or not
515      because a GC below is set to use a font. dje Dec 2001.
516      OK, I fixed the GC below, but now something else is blowing up.
517      Right now, I've got to do some Real Life stuff, so this kludge is
518      in place, its still better than I found it.
519      I hope that I've fixed this (olicha)
520   */
521   Ffont = FlocaleLoadFont(dpy, font_string, MyName);
522 
523   label_h = (uselabel) ? Ffont->height + 2 : 0;
524 
525   /* init our Flocale window string */
526   FlocaleAllocateWinString(&FwinString);
527 
528   /* Check that shape extension exists. */
529   if (FHaveShapeExtension && ShapeLabels)
530   {
531     ShapeLabels = (FShapesSupported) ? 1 : 0;
532   }
533 
534   if(smallFont != NULL)
535   {
536     FwindowFont = FlocaleLoadFont(dpy, smallFont, MyName);
537   }
538 
539   /* Load the colors */
540   fore_pix = GetColor(PagerFore);
541   back_pix = GetColor(PagerBack);
542   hi_pix = GetColor(HilightC);
543 
544   if (windowcolorset >= 0)
545   {
546     win_back_pix = Colorset[windowcolorset].bg;
547     win_fore_pix = Colorset[windowcolorset].fg;
548     win_pix_set = True;
549   }
550   else if (WindowBack && WindowFore)
551   {
552     win_back_pix = GetColor(WindowBack);
553     win_fore_pix = GetColor(WindowFore);
554     win_pix_set = True;
555   }
556 
557   if (activecolorset >= 0)
558   {
559     win_hi_back_pix = Colorset[activecolorset].bg;
560     win_hi_fore_pix = Colorset[activecolorset].fg;
561     win_hi_pix_set = True;
562   }
563   else if (WindowHiBack && WindowHiFore)
564   {
565     win_hi_back_pix = GetColor(WindowHiBack);
566     win_hi_fore_pix = GetColor(WindowHiFore);
567     win_hi_pix_set = True;
568   }
569 
570   /* Load pixmaps for mono use */
571   if(Pdepth<2)
572   {
573     Scr.gray_pixmap =
574       XCreatePixmapFromBitmapData(dpy,Scr.Pager_w,g_bits, g_width,g_height,
575 				  fore_pix,back_pix,Pdepth);
576     Scr.light_gray_pixmap =
577       XCreatePixmapFromBitmapData(dpy,Scr.Pager_w,l_g_bits,l_g_width,
578 				  l_g_height,
579 				  fore_pix,back_pix,Pdepth);
580     Scr.sticky_gray_pixmap =
581       XCreatePixmapFromBitmapData(dpy,Scr.Pager_w,s_g_bits,s_g_width,
582 				  s_g_height,
583 				  fore_pix,back_pix,Pdepth);
584   }
585 
586 
587   n = Scr.VxMax / Scr.MyDisplayWidth;
588   m = Scr.VyMax / Scr.MyDisplayHeight;
589 
590   /* Size the window */
591   if(Rows < 0)
592   {
593     if(Columns < 0)
594     {
595       Columns = ndesks;
596       Rows = 1;
597     }
598     else
599     {
600       Rows = ndesks/Columns;
601       if(Rows*Columns < ndesks)
602 	Rows++;
603     }
604   }
605   if(Columns < 0)
606   {
607     if (Rows == 0)
608       Rows = 1;
609     Columns = ndesks/Rows;
610     if(Rows*Columns < ndesks)
611       Columns++;
612   }
613 
614   if(Rows*Columns < ndesks)
615   {
616     if (Columns == 0)
617       Columns = 1;
618     Rows = ndesks/Columns;
619     if (Rows*Columns < ndesks)
620       Rows++;
621   }
622 
623   sizehints.width_inc = Columns*(n+1);
624   sizehints.height_inc = Rows*(m+1);
625   sizehints.base_width = Columns * n + Columns - 1;
626   sizehints.base_height = Rows * (m + label_h + 1) - 1;
627   if (window_w > 0)
628   {
629     window_w = (window_w - sizehints.base_width) / sizehints.width_inc;
630     window_w = window_w * sizehints.width_inc + sizehints.base_width;
631   }
632   else
633   {
634     window_w = Columns * (Scr.VWidth / Scr.VScale + n) + Columns - 1;
635   }
636   if (window_h > 0)
637   {
638     window_h = (window_h - sizehints.base_height) / sizehints.height_inc;
639     window_h = window_h * sizehints.height_inc + sizehints.base_height;
640   }
641   else
642   {
643     window_h = Rows * (Scr.VHeight / Scr.VScale + m + label_h + 1) - 1;
644   }
645   desk_w = (window_w - Columns + 1) / Columns;
646   desk_h = (window_h - Rows * label_h - Rows + 1) / Rows;
647   if (is_transient)
648   {
649     rectangle screen_g;
650     fscreen_scr_arg fscr;
651 
652     fscr.xypos.x = window_x;
653     fscr.xypos.y = window_y;
654     FScreenGetScrRect(
655       &fscr, FSCREEN_XYPOS,
656       &screen_g.x, &screen_g.y, &screen_g.width, &screen_g.height);
657     if (window_w + window_x > screen_g.x + screen_g.width)
658     {
659       window_x = screen_g.x + screen_g.width - Scr.MyDisplayWidth;
660       xneg = 1;
661     }
662     if (window_h + window_y > screen_g.y + screen_g.height)
663     {
664       window_y = screen_g.y + screen_g.height - Scr.MyDisplayHeight;
665       yneg = 1;
666     }
667   }
668   if (xneg)
669   {
670     sizehints.win_gravity = NorthEastGravity;
671     window_x = Scr.MyDisplayWidth - window_w + window_x;
672   }
673   if (yneg)
674   {
675     window_y = Scr.MyDisplayHeight - window_h + window_y;
676     if(sizehints.win_gravity == NorthEastGravity)
677       sizehints.win_gravity = SouthEastGravity;
678     else
679       sizehints.win_gravity = SouthWestGravity;
680   }
681   sizehints.width = window_w;
682   sizehints.height = window_h;
683 
684   if(usposition)
685     sizehints.flags |= USPosition;
686 
687   valuemask = (CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask);
688   attributes.background_pixmap = default_pixmap;
689   attributes.border_pixel = 0;
690   attributes.colormap = Pcmap;
691   attributes.event_mask = (StructureNotifyMask);
692 
693   /* destroy the temp window first, don't worry if it's the Root */
694   if (Scr.Pager_w != Scr.Root)
695     XDestroyWindow(dpy, Scr.Pager_w);
696   Scr.Pager_w = XCreateWindow (dpy, Scr.Root, window_x, window_y, window_w,
697 			       window_h, 0, Pdepth, InputOutput, Pvisual,
698 			       valuemask, &attributes);
699   XSetWMProtocols(dpy,Scr.Pager_w,&wm_del_win,1);
700   /* hack to prevent mapping on wrong screen with StartsOnScreen */
701   FScreenMangleScreenIntoUSPosHints(FSCREEN_XYPOS, &sizehints);
702   XSetWMNormalHints(dpy,Scr.Pager_w,&sizehints);
703   if (is_transient)
704   {
705     XSetTransientForHint(dpy, Scr.Pager_w, Scr.Root);
706   }
707 
708   if((desk1==desk2)&&(Desks[0].label != NULL))
709   {
710     if (FlocaleTextListToTextProperty(
711 	 dpy, &Desks[0].label, 1, XStdICCTextStyle, &name) == 0)
712     {
713       fprintf(stderr,"%s: fatal error: cannot allocate desk name", MyName);
714       exit(0);
715     }
716   }
717   else
718   {
719     if (FlocaleTextListToTextProperty(
720 	 dpy, &Desks[0].label, 1, XStdICCTextStyle, &name) == 0)
721     {
722       fprintf(stderr,"%s: fatal error: cannot allocate pager name", MyName);
723       exit(0);
724     }
725   }
726 
727   attributes.event_mask = (StructureNotifyMask| ExposureMask);
728   if(icon_w < 1)
729     icon_w = (window_w - Columns+1)/Columns;
730   if(icon_h < 1)
731     icon_h = (window_h - Rows* label_h - Rows + 1)/Rows;
732 
733   icon_w = (icon_w / (n+1)) *(n+1)+n;
734   icon_h = (icon_h / (m+1)) *(m+1)+m;
735   icon_win = XCreateWindow (dpy, Scr.Root, window_x, window_y, icon_w, icon_h,
736 			    0, Pdepth, InputOutput, Pvisual, valuemask,
737 			    &attributes);
738   XGrabButton(dpy, 1, AnyModifier, icon_win,
739 	      True, ButtonPressMask | ButtonReleaseMask|ButtonMotionMask,
740 	      GrabModeAsync, GrabModeAsync, None,
741 	      None);
742   XGrabButton(dpy, 2, AnyModifier, icon_win,
743 	      True, ButtonPressMask | ButtonReleaseMask|ButtonMotionMask,
744 	      GrabModeAsync, GrabModeAsync, None,
745 	      None);
746   XGrabButton(dpy, 3, AnyModifier, icon_win,
747 	      True, ButtonPressMask | ButtonReleaseMask|ButtonMotionMask,
748 	      GrabModeAsync, GrabModeAsync, None,
749 	      None);
750 
751   if(!StartIconic)
752     wmhints.initial_state = NormalState;
753   else
754     wmhints.initial_state = IconicState;
755   wmhints.flags = 0;
756   if (icon_x != -10000)
757   {
758     if (icon_xneg)
759       icon_x = Scr.MyDisplayWidth + icon_x - icon_w;
760     if (icon_y != -10000)
761     {
762       if (icon_yneg)
763 	icon_y = Scr.MyDisplayHeight + icon_y - icon_h;
764     }
765     else
766     {
767       icon_y = 0;
768     }
769     icon_xneg = 0;
770     icon_yneg = 0;
771     wmhints.icon_x = icon_x;
772     wmhints.icon_y = icon_y;
773     wmhints.flags = IconPositionHint;
774   }
775   wmhints.icon_window = icon_win;
776   wmhints.input = False;
777   wmhints.flags |= InputHint | StateHint | IconWindowHint;
778 
779   class1.res_name = MyName;
780   class1.res_class = "FvwmPager";
781 
782   XSetWMProperties(dpy,Scr.Pager_w,&name,&name,NULL,0,
783 		   &sizehints,&wmhints,&class1);
784   XFree((char *)name.value);
785 
786   /* change colour/font for labelling mini-windows */
787   XSetForeground(dpy, Scr.NormalGC, focus_fore_pix);
788 
789   if (FwindowFont != NULL && FwindowFont->font != NULL)
790     XSetFont(dpy, Scr.NormalGC, FwindowFont->font->fid);
791 
792   /* create the 3d bevel GC's if necessary */
793   if (windowcolorset >= 0) {
794     gcv.foreground = Colorset[windowcolorset].hilite;
795     Scr.whGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
796     gcv.foreground = Colorset[windowcolorset].shadow;
797     Scr.wsGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
798   }
799   if (activecolorset >= 0) {
800     gcv.foreground = Colorset[activecolorset].hilite;
801     Scr.ahGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
802     gcv.foreground = Colorset[activecolorset].shadow;
803     Scr.asGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
804   }
805 
806   balloon_font = FlocaleLoadFont(dpy, BalloonFont, MyName);
807   for(i=0;i<ndesks;i++)
808   {
809     w = window_w / Columns;
810     h = window_h / Rows;
811     x = (w + 1) * (i % Columns);
812     y = (h + 1) * (i / Columns);
813 
814     /* create the GC for desk labels */
815     gcv.foreground = (Desks[i].colorset < 0) ? fore_pix
816       : Colorset[Desks[i].colorset].fg;
817     if (uselabel && Ffont && Ffont->font) {
818       gcv.font = Ffont->font->fid;
819       Desks[i].NormalGC =
820 	fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground | GCFont, &gcv);
821     } else {
822       Desks[i].NormalGC =
823 	fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
824     }
825     /* create the active desk hilite GC */
826     if(Pdepth < 2)
827       gcv.foreground = fore_pix;
828     else
829       gcv.foreground = (Desks[i].highcolorset < 0) ? hi_pix
830 	: Colorset[Desks[i].highcolorset].bg;
831     Desks[i].HiliteGC = fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
832 
833     /* create the hilight desk title drawing GC */
834     if ((Pdepth < 2) || (fore_pix == hi_pix))
835       gcv.foreground = (Desks[i].highcolorset < 0) ? back_pix
836 	: Colorset[Desks[i].highcolorset].fg;
837     else
838       gcv.foreground = (Desks[i].highcolorset < 0) ? fore_pix
839 	: Colorset[Desks[i].highcolorset].fg;
840 
841     if (uselabel && Ffont && Ffont->font) {
842       Desks[i].rvGC =
843 	fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground | GCFont, &gcv);
844     } else {
845       Desks[i].rvGC =
846 	fvwmlib_XCreateGC(dpy, Scr.Pager_w, GCForeground, &gcv);
847     }
848     /* create the virtual page boundary GC */
849     gcv.foreground = (Desks[i].colorset < 0) ? fore_pix
850       : Colorset[Desks[i].colorset].fg;
851     gcv.line_width = 1;
852     gcv.line_style = (use_dashed_separators) ? LineOnOffDash : LineSolid;
853     Desks[i].DashedGC =
854       fvwmlib_XCreateGC(
855 	dpy, Scr.Pager_w, GCForeground | GCLineStyle | GCLineWidth, &gcv);
856     if (use_dashed_separators)
857     {
858       /* Although this should already be the default for a freshly created GC,
859        * some X servers do not draw properly dashed lines if the dash style is
860        * not set explicitly. */
861       dash_list[0] = 4;
862       dash_list[1] = 4;
863       XSetDashes(dpy, Desks[i].DashedGC, 0, dash_list, 2);
864     }
865 
866     valuemask = (CWBorderPixel | CWColormap | CWEventMask);
867     if (Desks[i].colorset >= 0 && Colorset[Desks[i].colorset].pixmap)
868     {
869 	valuemask |= CWBackPixmap;
870 	attributes.background_pixmap = Colorset[Desks[i].colorset].pixmap;
871     }
872     else
873     {
874 	valuemask |= CWBackPixel;
875 	attributes.background_pixel = (Desks[i].colorset < 0) ?
876 	    (Desks[i].Dcolor ? GetColor(Desks[i].Dcolor) : back_pix)
877 	    : Colorset[Desks[i].colorset].bg;
878     }
879 
880     attributes.border_pixel = (Desks[i].colorset < 0) ? fore_pix
881       : Colorset[Desks[i].colorset].fg;
882     attributes.event_mask = (ExposureMask | ButtonReleaseMask);
883     Desks[i].title_w = XCreateWindow(
884       dpy, Scr.Pager_w, x - 1, y - 1, w, h, 1, CopyFromParent, InputOutput,
885       CopyFromParent, valuemask, &attributes);
886     attributes.event_mask = (ExposureMask | ButtonReleaseMask |
887 			     ButtonPressMask |ButtonMotionMask);
888     /* or just: desk_h = h - label_h; */
889     desk_h = (window_h - Rows * label_h - Rows + 1) / Rows;
890 
891     valuemask &= ~(CWBackPixel);
892 
893 
894     if (Desks[i].colorset > -1 &&
895 	Colorset[Desks[i].colorset].pixmap)
896     {
897       valuemask |= CWBackPixmap;
898       attributes.background_pixmap = None; /* set later */
899     }
900     else if (Desks[i].bgPixmap)
901     {
902       valuemask |= CWBackPixmap;
903       attributes.background_pixmap = Desks[i].bgPixmap->picture;
904     }
905     else if (Desks[i].Dcolor)
906     {
907       valuemask |= CWBackPixel;
908       attributes.background_pixel = GetColor(Desks[i].Dcolor);
909     }
910     else if (PixmapBack)
911     {
912       valuemask |= CWBackPixmap;
913       attributes.background_pixmap = PixmapBack->picture;
914     }
915     else
916     {
917       valuemask |= CWBackPixel;
918       attributes.background_pixel = (Desks[i].colorset < 0) ? back_pix
919 	: Colorset[Desks[i].colorset].bg;
920     }
921 
922     Desks[i].w = XCreateWindow(
923 	    dpy, Desks[i].title_w, x - 1, LabelsBelow ? -1 : label_h - 1, w, desk_h,
924       1, CopyFromParent, InputOutput, CopyFromParent, valuemask, &attributes);
925 
926     if (HilightDesks)
927     {
928       valuemask &= ~(CWBackPixel | CWBackPixmap);
929 
930       attributes.event_mask = 0;
931 
932       if (Desks[i].highcolorset > -1 &&
933 	  Colorset[Desks[i].highcolorset].pixmap)
934       {
935 	valuemask |= CWBackPixmap;
936 	attributes.background_pixmap = None; /* set later */
937       }
938       else if (HilightPixmap)
939       {
940 	valuemask |= CWBackPixmap;
941 	attributes.background_pixmap = HilightPixmap->picture;
942       }
943       else
944       {
945 	valuemask |= CWBackPixel;
946 	attributes.background_pixel = (Desks[i].highcolorset < 0) ? hi_pix
947 	  : Colorset[Desks[i].highcolorset].bg;
948       }
949 
950       w = w / (n + 1);
951       h = desk_h / (m + 1);
952       Desks[i].CPagerWin=XCreateWindow(dpy, Desks[i].w, -32768, -32768, w, h, 0,
953 				       CopyFromParent, InputOutput,
954 				       CopyFromParent, valuemask, &attributes);
955       draw_desk_background(i, w, h);
956       XMapRaised(dpy,Desks[i].CPagerWin);
957     }
958     else
959     {
960       draw_desk_background(i, 0, 0);
961     }
962 
963     XMapRaised(dpy,Desks[i].w);
964     XMapRaised(dpy,Desks[i].title_w);
965 
966     /* get font for balloon */
967     Desks[i].balloon.Ffont = balloon_font;
968     if (Desks[i].balloon.Ffont == NULL)
969     {
970       fprintf(stderr, "%s: No fonts available, giving up!.\n", MyName);
971     }
972     Desks[i].balloon.height = Desks[i].balloon.Ffont->height + 1;
973   }
974   initialize_balloon_window();
975   XMapRaised(dpy,Scr.Pager_w);
976 }
977 
978 
UpdateWindowShape(void)979 void UpdateWindowShape(void)
980 {
981   if (FHaveShapeExtension)
982   {
983     int i, j, cnt, shape_count, x_pos, y_pos;
984     XRectangle *shape;
985 
986     if (!ShapeLabels || !uselabel || label_h<=0)
987       return;
988 
989     shape_count =
990       ndesks + ((Scr.CurrentDesk < desk1 || Scr.CurrentDesk >desk2) ? 0 : 1);
991 
992     shape = (XRectangle *)alloca (shape_count * sizeof (XRectangle));
993 
994     if (shape == NULL)
995       return;
996 
997     cnt = 0;
998     y_pos = (LabelsBelow ? 0 : label_h);
999 
1000     for (i = 0; i < Rows; ++i)
1001     {
1002       x_pos = 0;
1003       for (j = 0; j < Columns; ++j)
1004       {
1005 	if (cnt < ndesks)
1006 	{
1007 	  shape[cnt].x = x_pos;
1008 	  shape[cnt].y = y_pos;
1009 	  shape[cnt].width = desk_w + 1;
1010 	  shape[cnt].height = desk_h + 2;
1011 
1012 	  if (cnt == Scr.CurrentDesk - desk1)
1013 	  {
1014 	    shape[ndesks].x = x_pos;
1015 	    shape[ndesks].y =
1016 	      (LabelsBelow ? y_pos + desk_h + 2 : y_pos - label_h);
1017 	    shape[ndesks].width = desk_w;
1018 	    shape[ndesks].height = label_h + 2;
1019 	  }
1020 	}
1021 	++cnt;
1022 	x_pos += desk_w + 1;
1023       }
1024       y_pos += desk_h + 2 + label_h;
1025     }
1026 
1027     FShapeCombineRectangles(
1028       dpy, Scr.Pager_w, FShapeBounding, 0, 0, shape, shape_count, FShapeSet, 0);
1029   }
1030 }
1031 
1032 
1033 
1034 /*
1035  *
1036  * Decide what to do about received X events
1037  *
1038  */
DispatchEvent(XEvent * Event)1039 void DispatchEvent(XEvent *Event)
1040 {
1041   int i,x,y;
1042   Window JunkRoot, JunkChild;
1043   Window w;
1044   int JunkX, JunkY;
1045   unsigned JunkMask;
1046   char keychar;
1047   KeySym keysym;
1048   Bool do_move_page = False;
1049   short dx = 0;
1050   short dy = 0;
1051 
1052   switch(Event->xany.type)
1053   {
1054   case EnterNotify:
1055     HandleEnterNotify(Event);
1056     break;
1057   case LeaveNotify:
1058     if ( ShowBalloons )
1059       UnmapBalloonWindow();
1060     break;
1061   case ConfigureNotify:
1062     fev_sanitise_configure_notify(&Event->xconfigure);
1063     w = Event->xconfigure.window;
1064     discard_events(ConfigureNotify, Event->xconfigure.window, Event);
1065     fev_sanitise_configure_notify(&Event->xconfigure);
1066     if (w != icon_win)
1067     {
1068       /* icon_win is not handled here */
1069       discard_events(Expose, w, NULL);
1070       ReConfigure();
1071     }
1072     break;
1073   case Expose:
1074     HandleExpose(Event);
1075     break;
1076   case KeyPress:
1077     if (is_transient)
1078     {
1079       XLookupString(&(Event->xkey), &keychar, 1, &keysym, NULL);
1080       switch(keysym)
1081       {
1082       case XK_Up:
1083 	dy = -100;
1084 	do_move_page = True;
1085 	break;
1086       case XK_Down:
1087 	dy = 100;
1088 	do_move_page = True;
1089 	break;
1090       case XK_Left:
1091 	dx = -100;
1092 	do_move_page = True;
1093 	break;
1094       case XK_Right:
1095 	dx = 100;
1096 	do_move_page = True;
1097 	break;
1098       default:
1099 	/* does not return */
1100 	ExitPager();
1101 	break;
1102       }
1103       if (do_move_page)
1104       {
1105 	char command[64];
1106 	sprintf(command,"Scroll %d %d", dx, dy);
1107 	SendText(fd, command, 0);
1108       }
1109     }
1110     break;
1111   case ButtonRelease:
1112     if (do_ignore_next_button_release)
1113     {
1114       do_ignore_next_button_release = False;
1115       break;
1116     }
1117     if (Event->xbutton.button == 3)
1118     {
1119       for(i=0;i<ndesks;i++)
1120       {
1121 	if(Event->xany.window == Desks[i].w)
1122 	{
1123 	  if (FQueryPointer(dpy, Desks[i].w, &JunkRoot, &JunkChild,
1124 			    &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1125 	  {
1126 	    /* pointer is on a different screen - that's okay here */
1127 	  }
1128 	  Scroll(desk_w, desk_h, x, y, i, False);
1129 	}
1130       }
1131       if(Event->xany.window == icon_win)
1132       {
1133 	if (FQueryPointer(dpy, icon_win, &JunkRoot, &JunkChild,
1134 			  &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1135 	{
1136 	  /* pointer is on a different screen - that's okay here */
1137 	}
1138 	Scroll(icon_w, icon_h, x, y, 0, True);
1139       }
1140       /* Flush any pending scroll operations */
1141       do_scroll(0, 0, True, False);
1142     }
1143     else if((Event->xbutton.button == 1)||
1144 	    (Event->xbutton.button == 2))
1145     {
1146       for(i=0;i<ndesks;i++)
1147       {
1148 	if(Event->xany.window == Desks[i].w)
1149 	  SwitchToDeskAndPage(i,Event);
1150 	else if(Event->xany.window == Desks[i].title_w)
1151 	  SwitchToDesk(i);
1152       }
1153       if(Event->xany.window == icon_win)
1154       {
1155 	IconSwitchPage(Event);
1156       }
1157     }
1158     if (is_transient)
1159     {
1160       /* does not return */
1161       ExitPager();
1162     }
1163     break;
1164   case ButtonPress:
1165     do_ignore_next_button_release = False;
1166     if ( ShowBalloons )
1167       UnmapBalloonWindow();
1168     if (((Event->xbutton.button == 2)||
1169 	 ((Event->xbutton.button == 3)&&
1170 	  (Event->xbutton.state & Mod1Mask)))&&
1171 	(Event->xbutton.subwindow != None))
1172     {
1173       MoveWindow(Event);
1174     }
1175     else if (Event->xbutton.button == 3)
1176     {
1177       /* save initial virtual desk position for drag */
1178       MyVx=Scr.Vx;
1179       MyVy=Scr.Vy;
1180       for(i=0;i<ndesks;i++)
1181       {
1182 	if(Event->xany.window == Desks[i].w)
1183 	{
1184 	  if (FQueryPointer(dpy, Desks[i].w, &JunkRoot, &JunkChild,
1185 			    &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1186 	  {
1187 	    /* pointer is on a different screen - that's okay here */
1188 	  }
1189 	  Scroll(desk_w, desk_h, x, y, Scr.CurrentDesk, False);
1190 	  if (Scr.CurrentDesk != i + desk1)
1191 	  {
1192 	    Wait = 0;
1193 	    SwitchToDesk(i);
1194 	  }
1195 	  break;
1196 	}
1197       }
1198       if(Event->xany.window == icon_win)
1199       {
1200 	if (FQueryPointer(dpy, icon_win, &JunkRoot, &JunkChild,
1201 			  &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1202 	{
1203 	  /* pointer is on a different screen - that's okay here */
1204 	}
1205 	Scroll(icon_w, icon_h, x, y, 0, True);
1206       }
1207     }
1208     break;
1209   case MotionNotify:
1210     do_ignore_next_button_release = False;
1211     while(FCheckMaskEvent(dpy, PointerMotionMask | ButtonMotionMask,Event))
1212       ;
1213 
1214     if(Event->xmotion.state & Button3MotionMask)
1215     {
1216       for(i=0;i<ndesks;i++)
1217       {
1218 	if(Event->xany.window == Desks[i].w)
1219 	{
1220 	  if (FQueryPointer(dpy, Desks[i].w, &JunkRoot, &JunkChild,
1221 			    &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1222 	  {
1223 	    /* pointer is on a different screen - that's okay here */
1224 	  }
1225 	  Scroll(desk_w, desk_h, x, y, i, False);
1226 	}
1227       }
1228       if(Event->xany.window == icon_win)
1229       {
1230 	if (FQueryPointer(dpy, icon_win, &JunkRoot, &JunkChild,
1231 			  &JunkX, &JunkY,&x, &y, &JunkMask) == False)
1232 	{
1233 	  /* pointer is on a different screen - that's okay here */
1234 	}
1235 	Scroll(icon_w, icon_h, x, y, 0, True);
1236       }
1237 
1238     }
1239     break;
1240 
1241   case ClientMessage:
1242     if ((Event->xclient.format==32) &&
1243 	(Event->xclient.data.l[0]==wm_del_win))
1244     {
1245       /* does not return */
1246       ExitPager();
1247     }
1248     break;
1249   }
1250 }
1251 
HandleEnterNotify(XEvent * Event)1252 void HandleEnterNotify(XEvent *Event)
1253 
1254 {
1255   PagerWindow *t;
1256   Bool is_icon_view = False;
1257   extern Bool do_focus_on_enter;
1258 
1259   if (!ShowBalloons && !do_focus_on_enter)
1260     /* nothing to do */
1261     return;
1262 
1263   /* is this the best way to match X event window ID to PagerWindow ID? */
1264   for ( t = Start; t != NULL; t = t->next )
1265   {
1266     if ( t->PagerView == Event->xcrossing.window )
1267     {
1268       break;
1269     }
1270     if ( t->IconView == Event->xcrossing.window )
1271     {
1272       is_icon_view = True;
1273       break;
1274     }
1275   }
1276   if (t == NULL)
1277   {
1278     return;
1279   }
1280 
1281   if (ShowBalloons)
1282   {
1283     MapBalloonWindow(t, is_icon_view);
1284   }
1285 
1286   if (do_focus_on_enter)
1287   {
1288     SendText(fd, "Silent FlipFocus NoWarp", t->w);
1289   }
1290 
1291 }
1292 
get_expose_bound(XEvent * Event)1293 XRectangle get_expose_bound(XEvent *Event)
1294 {
1295 	XRectangle r;
1296 	int ex, ey, ex2, ey2;
1297 
1298 	ex = Event->xexpose.x;
1299 	ey = Event->xexpose.y;
1300 	ex2 = Event->xexpose.x + Event->xexpose.width;
1301 	ey2 = Event->xexpose.y + Event->xexpose.height;
1302 	while (FCheckTypedWindowEvent(dpy, Event->xany.window, Expose, Event))
1303 	{
1304 		ex = min(ex, Event->xexpose.x);
1305 		ey = min(ey, Event->xexpose.y);
1306 		ex2 = max(ex2, Event->xexpose.x + Event->xexpose.width);
1307 		ey2= max(ey2 , Event->xexpose.y + Event->xexpose.height);
1308 	}
1309 	r.x = ex;
1310 	r.y = ey;
1311 	r.width = ex2-ex;
1312 	r.height = ey2-ey;
1313 	return r;
1314 }
1315 
HandleExpose(XEvent * Event)1316 void HandleExpose(XEvent *Event)
1317 {
1318 	int i;
1319 	PagerWindow *t;
1320 	XRectangle r;
1321 
1322 	/* it will be good to have full "clipping redraw". Do that for
1323 	 * desk label only for now */
1324 	for(i=0;i<ndesks;i++)
1325 	{
1326 		/* ric@giccs.georgetown.edu */
1327 		if (Event->xany.window == Desks[i].w ||
1328 		    Event->xany.window == Desks[i].title_w)
1329 		{
1330 			r = get_expose_bound(Event);
1331 			DrawGrid(i, 0, Event->xany.window, &r);
1332 			return;
1333 		}
1334 	}
1335 	if (Event->xany.window == Scr.balloon_w)
1336 	{
1337 		DrawInBalloonWindow(Scr.balloon_desk);
1338 		return;
1339 	}
1340 	if(Event->xany.window == icon_win)
1341 		DrawIconGrid(0);
1342 
1343 	for (t = Start; t != NULL; t = t->next)
1344 	{
1345 		if (t->PagerView == Event->xany.window)
1346 		{
1347 			LabelWindow(t);
1348 			PictureWindow(t);
1349 			BorderWindow(t);
1350 		}
1351 		else if(t->IconView == Event->xany.window)
1352 		{
1353 			LabelIconWindow(t);
1354 			PictureIconWindow(t);
1355 			BorderIconWindow(t);
1356 		}
1357 	}
1358 
1359 	discard_events(Expose, Event->xany.window, NULL);
1360 }
1361 
1362 /*
1363  *
1364  * Respond to a change in window geometry.
1365  *
1366  */
ReConfigure(void)1367 void ReConfigure(void)
1368 {
1369   Window root;
1370   unsigned border_width, depth;
1371   int n,m,w,h,n1,m1,x,y,i,j,k;
1372   int old_ww;
1373   int old_wh;
1374   int is_size_changed;
1375 
1376   old_ww = window_w;
1377   old_wh = window_h;
1378   if (!XGetGeometry(dpy, Scr.Pager_w, &root, &x, &y, (unsigned *)&window_w,
1379 		    (unsigned *)&window_h, &border_width,&depth))
1380   {
1381     return;
1382   }
1383   is_size_changed = (old_ww != window_w || old_wh != window_h);
1384 
1385   n1 = Scr.Vx / Scr.MyDisplayWidth;
1386   m1 = Scr.Vy / Scr.MyDisplayHeight;
1387   n = Scr.VxMax / Scr.MyDisplayWidth;
1388   m = Scr.VyMax / Scr.MyDisplayHeight;
1389 
1390   sizehints.width_inc = Columns * (n + 1);
1391   sizehints.height_inc = Rows * (m + 1);
1392   sizehints.base_width = Columns * n + Columns - 1;
1393   sizehints.base_height = Rows*(m + label_h+1) - 1;
1394   sizehints.min_width = sizehints.base_width;
1395   sizehints.min_height = sizehints.base_height;
1396   if (window_w > 0)
1397   {
1398     window_w = (window_w - sizehints.base_width) / sizehints.width_inc;
1399     window_w = window_w * sizehints.width_inc + sizehints.base_width;
1400   }
1401   if (window_h > 0)
1402   {
1403     window_h = (window_h - sizehints.base_height) / sizehints.height_inc;
1404     window_h = window_h * sizehints.height_inc + sizehints.base_height;
1405   }
1406   desk_w = (window_w - Columns + 1) / Columns;
1407   desk_h = (window_h - Rows * label_h - Rows + 1) / Rows;
1408   w = (desk_w - n)/(n+1);
1409   h = (desk_h - m)/(m+1);
1410 
1411   XSetWMNormalHints(dpy,Scr.Pager_w,&sizehints);
1412 
1413   x = (desk_w - n) * Scr.Vx / Scr.VWidth + n1;
1414   y = (desk_h - m) * Scr.Vy / Scr.VHeight + m1;
1415 
1416   for(k=0;k<Rows;k++)
1417   {
1418     for(j=0;j<Columns;j++)
1419     {
1420       i = k*Columns+j;
1421       if (i<ndesks)
1422       {
1423 	XMoveResizeWindow(
1424 	  dpy,Desks[i].title_w, (desk_w+1)*j-1,(desk_h+label_h+1)*k-1,
1425 	  desk_w,desk_h+label_h);
1426 	XMoveResizeWindow(
1427 	  dpy,Desks[i].w, -1, (LabelsBelow) ? -1 : label_h - 1, desk_w,desk_h);
1428 	if (!is_size_changed)
1429 	{
1430 		if (CSET_IS_TRANSPARENT(Desks[i].colorset))
1431 		{
1432 			draw_desk_background(i, w, h);
1433 		}
1434 	}
1435 	if (HilightDesks)
1436 	{
1437 	  if(i == Scr.CurrentDesk - desk1)
1438 	    XMoveResizeWindow(dpy, Desks[i].CPagerWin, x,y,w,h);
1439 	  else
1440 	    XMoveResizeWindow(dpy, Desks[i].CPagerWin, -32768, -32768,w,h);
1441 	}
1442 	draw_desk_background(i, w, h);
1443       }
1444     }
1445   }
1446   /* reconfigure all the subordinate windows */
1447   ReConfigureAll();
1448 }
1449 
1450 /*
1451  *
1452  * Respond to a "background" change: update the Parental Relative cset
1453  *
1454  */
1455 
1456 /* layout:
1457  * Root -> pager window (pr) -> title window -> desk window -> window view
1458  *  |                                                |-> hilight desk
1459  *  |-> icon_window -> icon view
1460  *  |-> ballon window
1461  */
1462 
1463 /* update the hilight desk and the windows: desk color change */
1464 static
update_pr_transparent_subwindows(int i)1465 void update_pr_transparent_subwindows(int i)
1466 {
1467 	int cset;
1468 	int n,m,w,h;
1469 	PagerWindow *t;
1470 
1471 	n = Scr.VxMax / Scr.MyDisplayWidth;
1472 	m = Scr.VyMax / Scr.MyDisplayHeight;
1473 	w = (desk_w - n)/(n+1);
1474 	h = (desk_h - m)/(m+1);
1475 
1476 	if (CSET_IS_TRANSPARENT_PR(Desks[i].highcolorset) && HilightDesks)
1477 	{
1478 		SetWindowBackground(
1479 			dpy, Desks[i].CPagerWin, w, h,
1480 			&Colorset[Desks[i].highcolorset],
1481 			Pdepth, Scr.NormalGC, True);
1482 	}
1483 
1484 	t = Start;
1485 	for(t = Start; t != NULL; t = t->next)
1486 	{
1487 		cset = (t != FocusWin) ? windowcolorset : activecolorset;
1488 		if (t->desk != i && !CSET_IS_TRANSPARENT_PR(cset))
1489 		{
1490 			continue;
1491 		}
1492 		if (t->PagerView != None)
1493 		{
1494 			SetWindowBackground(
1495 				dpy, t->PagerView, t->pager_view_width,
1496 				t->pager_view_height,
1497 				&Colorset[cset], Pdepth, Scr.NormalGC, True);
1498 		}
1499 		if (t->IconView)
1500 		{
1501 			SetWindowBackground(
1502 				dpy, t->IconView, t->icon_view_width,
1503 				t->icon_view_height,
1504 				&Colorset[cset], Pdepth, Scr.NormalGC, True);
1505 		}
1506 	}
1507 }
1508 
1509 /* update all the parental relative windows: pr background change */
update_pr_transparent_windows(void)1510 void update_pr_transparent_windows(void)
1511 {
1512 	int i,j,k,cset;
1513 	int n,m,w,h;
1514 	PagerWindow *t;
1515 
1516 	n = Scr.VxMax / Scr.MyDisplayWidth;
1517 	m = Scr.VyMax / Scr.MyDisplayHeight;
1518 	w = (desk_w - n)/(n+1);
1519 	h = (desk_h - m)/(m+1);
1520 
1521 	for(k=0;k<Rows;k++)
1522 	{
1523 		for(j=0;j<Columns;j++)
1524 		{
1525 			i = k*Columns+j;
1526 			if (i < ndesks)
1527 			{
1528 				if (CSET_IS_TRANSPARENT_PR(Desks[i].colorset))
1529 				{
1530 					draw_desk_background(i, w, h);
1531 				}
1532 				else if (CSET_IS_TRANSPARENT_PR(
1533 					Desks[i].highcolorset) && HilightDesks)
1534 				{
1535 					SetWindowBackground(
1536 						dpy, Desks[i].CPagerWin, w, h,
1537 						&Colorset[Desks[i].highcolorset],
1538 						Pdepth, Scr.NormalGC, True);
1539 				}
1540 			}
1541 		}
1542 	}
1543 	/* subordinate windows with a pr parent desk */
1544 	t = Start;
1545 	for(t = Start; t != NULL; t = t->next)
1546 	{
1547 		cset = (t != FocusWin) ? windowcolorset : activecolorset;
1548 		if (!CSET_IS_TRANSPARENT_PR(cset) ||
1549 		    (fAlwaysCurrentDesk &&
1550 		     !CSET_IS_TRANSPARENT_PR(Desks[0].colorset)) ||
1551 		    (!fAlwaysCurrentDesk &&
1552 		     !CSET_IS_TRANSPARENT_PR(Desks[t->desk].colorset)))
1553 		{
1554 			continue;
1555 		}
1556 		if (t->PagerView != None)
1557 		{
1558 			SetWindowBackground(
1559 				dpy, t->PagerView, t->pager_view_width,
1560 				t->pager_view_height,
1561 				&Colorset[cset], Pdepth, Scr.NormalGC, True);
1562 		}
1563 		if (t->desk && t->IconView)
1564 		{
1565 			SetWindowBackground(
1566 				dpy, t->IconView, t->icon_view_width,
1567 				t->icon_view_height,
1568 				&Colorset[cset], Pdepth, Scr.NormalGC, True);
1569 		}
1570 	}
1571 
1572 	/* ballon */
1573 	if (BalloonView != None)
1574 	{
1575 		cset = Desks[Scr.balloon_desk].ballooncolorset;
1576 		if (CSET_IS_TRANSPARENT_PR(cset))
1577 		{
1578 			XClearArea(dpy, Scr.balloon_w, 0, 0, 0, 0, True);
1579 		}
1580 	}
1581 }
1582 
MovePage(Bool is_new_desk)1583 void MovePage(Bool is_new_desk)
1584 {
1585   int n1,m1,x,y,n,m,i,w,h;
1586   XTextProperty name;
1587   char str[100],*sptr;
1588   static int icon_desk_shown = -1000;
1589 
1590   Wait = 0;
1591   n1 = Scr.Vx/Scr.MyDisplayWidth;
1592   m1 = Scr.Vy/Scr.MyDisplayHeight;
1593   n = Scr.VxMax / Scr.MyDisplayWidth;
1594   m = Scr.VyMax / Scr.MyDisplayHeight;
1595 
1596   x = (desk_w - n) * Scr.Vx / Scr.VWidth + n1;
1597   y = (desk_h - m) * Scr.Vy / Scr.VHeight + m1;
1598   w = (desk_w - n)/(n+1);
1599   h = (desk_h - m)/(m+1);
1600 
1601   for(i=0;i<ndesks;i++)
1602   {
1603     if (HilightDesks)
1604     {
1605       if(i == Scr.CurrentDesk - desk1)
1606       {
1607 	XMoveWindow(dpy, Desks[i].CPagerWin, x,y);
1608 	XLowerWindow(dpy,Desks[i].CPagerWin);
1609 	if (CSET_IS_TRANSPARENT(Desks[i].highcolorset))
1610 	{
1611 		SetWindowBackground(
1612 			dpy, Desks[i].CPagerWin, w, h,
1613 			&Colorset[Desks[i].highcolorset], Pdepth,
1614 			Scr.NormalGC, True);
1615 	}
1616       }
1617       else
1618       {
1619 	XMoveWindow(dpy, Desks[i].CPagerWin, -32768,-32768);
1620       }
1621     }
1622   }
1623   DrawIconGrid(1);
1624 
1625   ReConfigureIcons(!is_new_desk);
1626 
1627   if(Scr.CurrentDesk != icon_desk_shown)
1628   {
1629     icon_desk_shown = Scr.CurrentDesk;
1630 
1631     if((Scr.CurrentDesk >= desk1)&&(Scr.CurrentDesk <=desk2))
1632       sptr = Desks[Scr.CurrentDesk -desk1].label;
1633     else
1634     {
1635       sprintf(str, "GotoDesk %d", Scr.CurrentDesk);
1636       sptr = &str[0];
1637     }
1638 
1639     if (FlocaleTextListToTextProperty(
1640 	  dpy, &sptr, 1, XStdICCTextStyle, &name) == 0)
1641     {
1642       fprintf(stderr,"%s: cannot allocate window name", MyName);
1643       return;
1644     }
1645     XSetWMIconName(dpy,Scr.Pager_w,&name);
1646     XFree(name.value);
1647   }
1648 }
1649 
ReConfigureAll(void)1650 void ReConfigureAll(void)
1651 {
1652   PagerWindow *t;
1653 
1654   t = Start;
1655   while(t!= NULL)
1656   {
1657     MoveResizePagerView(t, True);
1658     t = t->next;
1659   }
1660 }
1661 
ReConfigureIcons(Bool do_reconfigure_desk_only)1662 void ReConfigureIcons(Bool do_reconfigure_desk_only)
1663 {
1664   PagerWindow *t;
1665   int x, y, w, h;
1666 
1667   for (t = Start; t != NULL; t = t->next)
1668   {
1669     if (do_reconfigure_desk_only && t->desk != Scr.CurrentDesk)
1670       continue;
1671     CalcGeom(t, icon_w, icon_h, &x, &y, &w, &h);
1672     t->icon_view_x = x;
1673     t->icon_view_y = y;
1674     t->icon_view_width = w;
1675     t->icon_view_height = h;
1676     if(Scr.CurrentDesk == t->desk)
1677       XMoveResizeWindow(dpy, t->IconView, x, y, w, h);
1678     else
1679       XMoveResizeWindow(dpy, t->IconView, -32768, -32768, w, h);
1680   }
1681 }
1682 
1683 /*
1684  *
1685  * Draw grid lines for desk #i
1686  *
1687  */
DrawGrid(int desk,int erase,Window ew,XRectangle * r)1688 void DrawGrid(int desk, int erase, Window ew, XRectangle *r)
1689 {
1690 	int y, y1, y2, x, x1, x2,d,w;
1691 	char str[15], *ptr;
1692 	int cs;
1693 	XRectangle bound;
1694 	Region region = 0;
1695 
1696 	if((desk < 0 ) || (desk >= ndesks))
1697 		return;
1698 
1699 	/* desk grid */
1700 	if (!ew || ew == Desks[desk].w)
1701 	{
1702 		x = Scr.MyDisplayWidth;
1703 		y1 = 0;
1704 		y2 = desk_h;
1705 		while (x < Scr.VWidth)
1706 		{
1707 			x1 = (x * desk_w) / Scr.VWidth;
1708 			if (!use_no_separators)
1709 			{
1710 				XDrawLine(
1711 					dpy,Desks[desk].w,Desks[desk].DashedGC,
1712 					x1,y1,x1,y2);
1713 			}
1714 			x += Scr.MyDisplayWidth;
1715 		}
1716 		y = Scr.MyDisplayHeight;
1717 		x1 = 0;
1718 		x2 = desk_w;
1719 		while(y < Scr.VHeight)
1720 		{
1721 			y1 = (y * desk_h) / Scr.VHeight;
1722 			if (!use_no_separators)
1723 			{
1724 				XDrawLine(
1725 					dpy,Desks[desk].w,Desks[desk].DashedGC,
1726 					x1,y1,x2,y1);
1727 			}
1728 			y += Scr.MyDisplayHeight;
1729 		}
1730 	}
1731 
1732 	if (ew && ew != Desks[desk].title_w)
1733 	{
1734 		return;
1735 	}
1736 
1737 	/* desk label */
1738 	if (r)
1739 	{
1740 		bound.x = r->x;
1741 		bound.y = r->y;
1742 		bound.width = r->width;
1743 		bound.height = r->height;
1744 		region = XCreateRegion();
1745 		XUnionRectWithRegion (&bound, region, region);
1746 	}
1747 	else
1748 	{
1749 		bound.x = 0;
1750 		bound.y = (LabelsBelow ? desk_h : 0);
1751 		bound.width = desk_w;
1752 		bound.height = label_h;
1753 	}
1754 
1755 	if (FftSupport && Ffont->fftf.fftfont != NULL)
1756 	{
1757 		erase = True;
1758 	}
1759 	if(((Scr.CurrentDesk - desk1) == desk) && !ShapeLabels)
1760 	{
1761 		if (uselabel)
1762 		{
1763 			XFillRectangle(
1764 				dpy,Desks[desk].title_w,Desks[desk].HiliteGC,
1765 				bound.x, bound.y, bound.width, bound.height);
1766 		}
1767 	}
1768 	else
1769 	{
1770 		if(uselabel && erase)
1771 		{
1772 			XClearArea(dpy,Desks[desk].title_w,
1773 				   bound.x, bound.y, bound.width, bound.height,
1774 				   False);
1775 		}
1776 	}
1777 
1778 	d = desk1+desk;
1779 	ptr = Desks[desk].label;
1780 	w = FlocaleTextWidth(Ffont,ptr,strlen(ptr));
1781 	if( w > desk_w)
1782 	{
1783 		sprintf(str,"%d",d);
1784 		ptr = str;
1785 		w = FlocaleTextWidth(Ffont,ptr,strlen(ptr));
1786 	}
1787 	if((w <= desk_w)&&(uselabel))
1788 	{
1789 		FwinString->str = ptr;
1790 		FwinString->win = Desks[desk].title_w;
1791 		if(desk == (Scr.CurrentDesk - desk1))
1792 		{
1793 			cs = Desks[desk].highcolorset;
1794 			FwinString->gc = Desks[desk].rvGC;
1795 		}
1796 		else
1797 		{
1798 			cs = Desks[desk].colorset;
1799 			FwinString->gc = Desks[desk].NormalGC;
1800 		}
1801 
1802 		FwinString->flags.has_colorset = False;
1803 		if (cs >= 0)
1804 		{
1805 			FwinString->colorset = &Colorset[cs];
1806 			FwinString->flags.has_colorset = True;
1807 		}
1808 		FwinString->x = (desk_w - w)/2;
1809 		FwinString->y = (LabelsBelow ?
1810 				 desk_h + Ffont->ascent + 1 : Ffont->ascent + 1);
1811 		if (region)
1812 		{
1813 			FwinString->flags.has_clip_region = True;
1814 			FwinString->clip_region = region;
1815 			XSetRegion(dpy, FwinString->gc, region);
1816 		}
1817 		else
1818 		{
1819 			FwinString->flags.has_clip_region = False;
1820 		}
1821 		FlocaleDrawString(dpy, Ffont, FwinString, 0);
1822 		if (region)
1823 		{
1824 			XDestroyRegion(region);
1825 			FwinString->flags.has_clip_region = False;
1826 			FwinString->clip_region = None;
1827 			XSetClipMask(dpy, FwinString->gc, None);
1828 		}
1829 	}
1830 
1831 	if (FShapesSupported)
1832 	{
1833 		UpdateWindowShape ();
1834 	}
1835 }
1836 
1837 
DrawIconGrid(int erase)1838 void DrawIconGrid(int erase)
1839 {
1840   int y, y1, y2, x, x1, x2,w,h,n,m,n1,m1;
1841   int i;
1842 
1843   if(erase)
1844   {
1845     int tmp=(Scr.CurrentDesk - desk1);
1846 
1847     if ((tmp < 0) || (tmp >= ndesks))
1848     {
1849       if (PixmapBack)
1850 	XSetWindowBackgroundPixmap(dpy, icon_win,PixmapBack->picture);
1851       else
1852 	XSetWindowBackground(dpy, icon_win, back_pix);
1853     }
1854     else
1855     {
1856       if (Desks[tmp].bgPixmap)
1857 	XSetWindowBackgroundPixmap(
1858 	    dpy, icon_win,Desks[tmp].bgPixmap->picture);
1859       else if (Desks[tmp].Dcolor)
1860 	XSetWindowBackground(dpy, icon_win, GetColor(Desks[tmp].Dcolor));
1861       else if (PixmapBack)
1862 	XSetWindowBackgroundPixmap(dpy, icon_win, PixmapBack->picture);
1863       else
1864 	XSetWindowBackground(dpy, icon_win, back_pix);
1865     }
1866 
1867     XClearWindow(dpy,icon_win);
1868   }
1869 
1870   x = Scr.MyDisplayWidth;
1871   y1 = 0;
1872   y2 = icon_h;
1873   while(x < Scr.VWidth)
1874   {
1875     x1 = x * icon_w / Scr.VWidth;
1876     if (!use_no_separators)
1877       for(i=0;i<ndesks;i++)
1878 	XDrawLine(dpy,icon_win,Desks[i].DashedGC,x1,y1,x1,y2);
1879     x += Scr.MyDisplayWidth;
1880   }
1881 
1882   y = Scr.MyDisplayHeight;
1883   x1 = 0;
1884   x2 = icon_w;
1885   while(y < Scr.VHeight)
1886   {
1887     y1 = y * icon_h / Scr.VHeight;
1888     if (!use_no_separators)
1889       for(i=0;i<ndesks;i++)
1890 	XDrawLine(dpy,icon_win,Desks[i].DashedGC,x1,y1,x2,y1);
1891     y += Scr.MyDisplayHeight;
1892   }
1893   n1 = Scr.Vx / Scr.MyDisplayWidth;
1894   m1 = Scr.Vy / Scr.MyDisplayHeight;
1895   n = Scr.VxMax / Scr.MyDisplayWidth;
1896   m = Scr.VyMax / Scr.MyDisplayHeight;
1897   w = (icon_w - n) / (n + 1);
1898   h = (icon_h - m) / (m + 1);
1899 
1900   x = (icon_w - n) * Scr.Vx / Scr.VWidth + n1;
1901   y = (icon_h - m) * Scr.Vy / Scr.VHeight + m1;
1902 
1903   if (HilightDesks)
1904   {
1905     if (HilightPixmap)
1906     {
1907       for(i=0;i<ndesks;i++)
1908 	XCopyArea(dpy, HilightPixmap->picture, icon_win, Scr.NormalGC, 0, 0,
1909 		  w, h, x, y);
1910     }
1911     else
1912     {
1913       for(i=0;i<ndesks;i++)
1914 	XFillRectangle (dpy, icon_win, Desks[i].HiliteGC, x, y, w, h);
1915     }
1916   }
1917 }
1918 
1919 
SwitchToDesk(int Desk)1920 void SwitchToDesk(int Desk)
1921 {
1922   char command[256];
1923 
1924   sprintf(command, "GotoDesk 0 %d", Desk + desk1);
1925   SendText(fd,command,0);
1926 }
1927 
1928 
SwitchToDeskAndPage(int Desk,XEvent * Event)1929 void SwitchToDeskAndPage(int Desk, XEvent *Event)
1930 {
1931   char command[256];
1932 
1933   if (Scr.CurrentDesk != (Desk + desk1))
1934   {
1935     int vx, vy;
1936     /* patch to let mouse button 3 change desks and do not cling to a page */
1937     vx = Event->xbutton.x * Scr.VWidth / (desk_w * Scr.MyDisplayWidth);
1938     vy = Event->xbutton.y * Scr.VHeight / (desk_h * Scr.MyDisplayHeight);
1939     Scr.Vx = vx * Scr.MyDisplayWidth;
1940     Scr.Vy = vy * Scr.MyDisplayHeight;
1941     sprintf(command, "GotoDeskAndPage %d %d %d", Desk + desk1, vx, vy);
1942     SendText(fd, command, 0);
1943 
1944   }
1945   else
1946   {
1947     int x = Event->xbutton.x * Scr.VWidth / (desk_w * Scr.MyDisplayWidth);
1948     int y = Event->xbutton.y * Scr.VHeight / (desk_h * Scr.MyDisplayHeight);
1949 
1950     /* Fix for buggy XFree86 servers that report button release events
1951      * incorrectly when moving fast. Not perfect, but should at least prevent
1952      * that we get a random page. */
1953     if (x < 0)
1954       x = 0;
1955     if (y < 0)
1956       y = 0;
1957     if (x * Scr.MyDisplayWidth > Scr.VxMax)
1958       x = Scr.VxMax / Scr.MyDisplayWidth;
1959     if (y * Scr.MyDisplayHeight > Scr.VyMax)
1960       y = Scr.VyMax / Scr.MyDisplayHeight;
1961     sprintf(command, "GotoPage %d %d", x, y);
1962     SendText(fd, command, 0);
1963   }
1964   Wait = 1;
1965 }
1966 
IconSwitchPage(XEvent * Event)1967 void IconSwitchPage(XEvent *Event)
1968 {
1969   char command[34];
1970 
1971   sprintf(command,"GotoPage %d %d",
1972 	  Event->xbutton.x * Scr.VWidth / (icon_w * Scr.MyDisplayWidth),
1973 	  Event->xbutton.y * Scr.VHeight / (icon_h * Scr.MyDisplayHeight));
1974   SendText(fd, command, 0);
1975   Wait = 1;
1976 }
1977 
1978 
AddNewWindow(PagerWindow * t)1979 void AddNewWindow(PagerWindow *t)
1980 {
1981 	unsigned long valuemask;
1982 	XSetWindowAttributes attributes;
1983 	int i, x, y, w, h;
1984 
1985 	i = t->desk - desk1;
1986 	CalcGeom(t, desk_w, desk_h, &x, &y, &w, &h);
1987 	t->pager_view_x = x;
1988 	t->pager_view_y = y;
1989 	t->pager_view_width = w;
1990 	t->pager_view_height = h;
1991 	valuemask = CWBackPixel | CWEventMask;
1992 	attributes.background_pixel = t->back;
1993 	attributes.event_mask = ExposureMask;
1994 
1995 	/* ric@giccs.georgetown.edu -- added Enter and Leave events for
1996 	   popping up balloon window */
1997 	attributes.event_mask =
1998 		ExposureMask | EnterWindowMask | LeaveWindowMask;
1999 
2000 	if ((i >= 0) && (i < ndesks))
2001 	{
2002 		t->PagerView = XCreateWindow(
2003 			dpy,Desks[i].w, x, y, w, h, 0, CopyFromParent,
2004 			InputOutput, CopyFromParent, valuemask, &attributes);
2005 		if (windowcolorset > -1)
2006 		{
2007 			SetWindowBackground(
2008 				dpy, t->PagerView, w, h,
2009 				&Colorset[windowcolorset], Pdepth,
2010 				Scr.NormalGC, True);
2011 		}
2012 		if (!UseSkipList || !DO_SKIP_WINDOW_LIST(t))
2013 		{
2014 			if (IS_ICONIFIED(t))
2015 			{
2016 				XMoveResizeWindow(
2017 					dpy, t->PagerView, -32768, -32768, 1,
2018 					1);
2019 			}
2020 			XMapRaised(dpy, t->PagerView);
2021 		}
2022 	}
2023 	else
2024 	{
2025 		t->PagerView = None;
2026 	}
2027 
2028 	CalcGeom(t, icon_w, icon_h, &x, &y, &w, &h);
2029 	t->icon_view_x = x;
2030 	t->icon_view_y = y;
2031 	t->icon_view_width = w;
2032 	t->icon_view_height = h;
2033 	if(Scr.CurrentDesk != t->desk)
2034 	{
2035 		x = -32768;
2036 		y = -32768;
2037 	}
2038 	t->IconView = XCreateWindow(
2039 		dpy,icon_win, x, y, w, h, 0, CopyFromParent, InputOutput,
2040 		CopyFromParent, valuemask, &attributes);
2041 	if (windowcolorset > -1)
2042 	{
2043 		SetWindowBackground(
2044 			dpy, t->IconView, w, h, &Colorset[windowcolorset],
2045 			Pdepth, Scr.NormalGC, True);
2046 	}
2047 	if(Scr.CurrentDesk == t->desk)
2048 	{
2049 		XGrabButton(
2050 			dpy, 2, AnyModifier, t->IconView, True,
2051 			ButtonPressMask | ButtonReleaseMask|ButtonMotionMask,
2052 			GrabModeAsync, GrabModeAsync, None, None);
2053 	}
2054 	if (!UseSkipList || !DO_SKIP_WINDOW_LIST(t))
2055 	{
2056 		if (IS_ICONIFIED(t))
2057 		{
2058 			XMoveResizeWindow(
2059 				dpy, t->IconView, -32768, -32768, 1,
2060 				1);
2061 		}
2062 		XMapRaised(dpy, t->IconView);
2063 		t->myflags.is_mapped = 1;
2064 	}
2065 	else
2066 	{
2067 		t->myflags.is_mapped = 0;
2068 	}
2069 	Hilight(t, False);
2070 
2071 	return;
2072 }
2073 
2074 
ChangeDeskForWindow(PagerWindow * t,long newdesk)2075 void ChangeDeskForWindow(PagerWindow *t,long newdesk)
2076 {
2077   int i, x, y, w, h;
2078   Bool size_changed = False;
2079 
2080   i = newdesk - desk1;
2081   if(t->PagerView == None)
2082   {
2083     t->desk = newdesk;
2084     XDestroyWindow(dpy,t->IconView);
2085     AddNewWindow( t);
2086     return;
2087   }
2088 
2089   CalcGeom(t, desk_w, desk_h, &x, &y, &w, &h);
2090   size_changed = (t->pager_view_width != w || t->pager_view_height != h);
2091   t->pager_view_x = x;
2092   t->pager_view_y = y;
2093   t->pager_view_width = w;
2094   t->pager_view_height = h;
2095 
2096   if ((i >= 0) && (i < ndesks))
2097   {
2098     int cset;
2099 
2100     XReparentWindow(dpy, t->PagerView, Desks[i].w, x, y);
2101     if (size_changed)
2102       XResizeWindow(dpy, t->PagerView, w, h);
2103     cset = (t != FocusWin) ? windowcolorset : activecolorset;
2104     if (cset > -1 && (size_changed || CSET_IS_TRANSPARENT(cset)))
2105     {
2106       SetWindowBackground(
2107 	dpy, t->PagerView, t->pager_view_width, t->pager_view_height,
2108 	&Colorset[cset], Pdepth, Scr.NormalGC, True);
2109     }
2110   }
2111   else
2112   {
2113     XDestroyWindow(dpy,t->PagerView);
2114     t->PagerView = None;
2115   }
2116   t->desk = i+desk1;
2117 
2118   CalcGeom(t, icon_w, icon_h, &x, &y, &w, &h);
2119   size_changed = (t->icon_view_width != w || t->icon_view_height != h);
2120   t->icon_view_x = x;
2121   t->icon_view_y = y;
2122   t->icon_view_width = w;
2123   t->icon_view_height = h;
2124   if(Scr.CurrentDesk != t->desk)
2125     XMoveResizeWindow(dpy,t->IconView,-32768,-32768,w,h);
2126   else
2127   {
2128     int cset;
2129 
2130     XMoveResizeWindow(dpy,t->IconView,x,y,w,h);
2131     cset = (t != FocusWin) ? windowcolorset : activecolorset;
2132     if (cset > -1 && (size_changed || CSET_IS_TRANSPARENT(cset)))
2133     {
2134       SetWindowBackground(
2135 	dpy, t->IconView, t->icon_view_width, t->icon_view_height,
2136 	&Colorset[cset], Pdepth, Scr.NormalGC, True);
2137     }
2138   }
2139 }
2140 
MoveResizePagerView(PagerWindow * t,Bool do_force_redraw)2141 void MoveResizePagerView(PagerWindow *t, Bool do_force_redraw)
2142 {
2143   int x, y, w, h;
2144   Bool size_changed;
2145   Bool position_changed;
2146 
2147   if (UseSkipList && DO_SKIP_WINDOW_LIST(t) && t->myflags.is_mapped)
2148   {
2149     if (t->PagerView)
2150       XUnmapWindow(dpy, t->PagerView);
2151     if (t->IconView)
2152       XUnmapWindow(dpy, t->IconView);
2153     t->myflags.is_mapped = 0;
2154   }
2155   else if (UseSkipList && !DO_SKIP_WINDOW_LIST(t) && !t->myflags.is_mapped)
2156   {
2157     if (t->PagerView)
2158       XMapRaised(dpy, t->PagerView);
2159     if (t->IconView)
2160       XMapRaised(dpy, t->IconView);
2161     t->myflags.is_mapped = 1;
2162   }
2163 
2164   CalcGeom(t, desk_w, desk_h, &x, &y, &w, &h);
2165   position_changed = (t->pager_view_x != x || t->pager_view_y != y);
2166   size_changed = (t->pager_view_width != w || t->pager_view_height != h);
2167   t->pager_view_x = x;
2168   t->pager_view_y = y;
2169   t->pager_view_width = w;
2170   t->pager_view_height = h;
2171   if (t->PagerView != None)
2172   {
2173     if (size_changed || position_changed || do_force_redraw)
2174     {
2175       int cset;
2176 
2177       XMoveResizeWindow(dpy, t->PagerView, x, y, w, h);
2178       cset = (t != FocusWin) ? windowcolorset : activecolorset;
2179       if (cset > -1 && (size_changed || CSET_IS_TRANSPARENT(cset)))
2180       {
2181 	SetWindowBackground(
2182 	  dpy, t->PagerView, t->pager_view_width, t->pager_view_height,
2183 	  &Colorset[cset], Pdepth, Scr.NormalGC, True);
2184       }
2185     }
2186   }
2187   else if (t->desk >= desk1 && t->desk <= desk2)
2188   {
2189     XDestroyWindow(dpy, t->IconView);
2190     AddNewWindow(t);
2191     return;
2192   }
2193 
2194   CalcGeom(t, icon_w, icon_h, &x, &y, &w, &h);
2195   position_changed = (t->icon_view_x != x || t->icon_view_y != y);
2196   size_changed = (t->icon_view_width != w || t->icon_view_height != h);
2197   t->icon_view_x = x;
2198   t->icon_view_y = y;
2199   t->icon_view_width = w;
2200   t->icon_view_height = h;
2201   if (Scr.CurrentDesk == t->desk)
2202   {
2203     int cset;
2204 
2205     XMoveResizeWindow(dpy, t->IconView, x, y, w, h);
2206     cset = (t != FocusWin) ? windowcolorset : activecolorset;
2207     if (cset > -1 && (size_changed || CSET_IS_TRANSPARENT(cset)))
2208     {
2209       SetWindowBackground(
2210 	dpy, t->IconView, t->icon_view_width, t->icon_view_height,
2211 	&Colorset[cset], Pdepth, Scr.NormalGC, True);
2212     }
2213   }
2214   else
2215   {
2216     XMoveResizeWindow(dpy, t->IconView, -32768, -32768, w, h);
2217   }
2218 }
2219 
2220 
MoveStickyWindow(Bool is_new_page,Bool is_new_desk)2221 void MoveStickyWindow(Bool is_new_page, Bool is_new_desk)
2222 {
2223 	PagerWindow *t;
2224 
2225 	for (t = Start; t != NULL; t = t->next)
2226 	{
2227 		if (
2228 			is_new_desk && t->desk != Scr.CurrentDesk &&
2229 			((IS_ICONIFIED(t) && IS_ICON_STICKY_ACROSS_DESKS(t)) ||
2230 			 IS_STICKY_ACROSS_DESKS(t)))
2231 		{
2232 			ChangeDeskForWindow(t, Scr.CurrentDesk);
2233 		}
2234 		else if (
2235 			is_new_page &&
2236 			((IS_ICONIFIED(t) &&
2237 			  IS_ICON_STICKY_ACROSS_PAGES(t)) ||
2238 			 IS_STICKY_ACROSS_PAGES(t)))
2239 		{
2240 			MoveResizePagerView(t, True);
2241 		}
2242 	}
2243 }
2244 
Hilight(PagerWindow * t,int on)2245 void Hilight(PagerWindow *t, int on)
2246 {
2247 
2248   if(!t)
2249     return;
2250 
2251   if(Pdepth < 2)
2252   {
2253     if(on)
2254     {
2255       if(t->PagerView != None)
2256 	XSetWindowBackgroundPixmap(dpy,t->PagerView,Scr.gray_pixmap);
2257       XSetWindowBackgroundPixmap(dpy,t->IconView,Scr.gray_pixmap);
2258     }
2259     else
2260     {
2261       if(IS_STICKY_ACROSS_DESKS(t) || IS_STICKY_ACROSS_PAGES(t))
2262       {
2263 	if(t->PagerView != None)
2264 	  XSetWindowBackgroundPixmap(dpy,t->PagerView,
2265 				     Scr.sticky_gray_pixmap);
2266 	XSetWindowBackgroundPixmap(dpy,t->IconView,
2267 				   Scr.sticky_gray_pixmap);
2268       }
2269       else
2270       {
2271 	if(t->PagerView != None)
2272 	  XSetWindowBackgroundPixmap(dpy,t->PagerView,
2273 				     Scr.light_gray_pixmap);
2274 	XSetWindowBackgroundPixmap(dpy,t->IconView,
2275 				   Scr.light_gray_pixmap);
2276       }
2277     }
2278     if(t->PagerView != None)
2279       XClearArea(dpy, t->PagerView, 0, 0, 0, 0, True);
2280     XClearArea(dpy, t->IconView, 0, 0, 0, 0, True);
2281   }
2282   else
2283   {
2284     int cset;
2285     Pixel pix;
2286 
2287     cset = (on) ? activecolorset : windowcolorset;
2288     pix = (on) ? focus_pix : t->back;
2289     if (cset < 0)
2290     {
2291       if (t->PagerView != None)
2292       {
2293 	XSetWindowBackground(dpy,t->PagerView,pix);
2294 	XClearArea(dpy, t->PagerView, 0, 0, 0, 0, True);
2295       }
2296       XSetWindowBackground(dpy,t->IconView,pix);
2297       XClearArea(dpy, t->IconView, 0, 0, 0, 0, True);
2298     }
2299     else
2300     {
2301       if (t->PagerView != None)
2302       {
2303 	SetWindowBackground(
2304 	  dpy, t->PagerView, t->pager_view_width, t->pager_view_height,
2305 	  &Colorset[cset], Pdepth, Scr.NormalGC, True);
2306       }
2307       SetWindowBackground(
2308 	dpy, t->IconView, t->icon_view_width, t->icon_view_height,
2309 	&Colorset[cset], Pdepth, Scr.NormalGC, True);
2310     }
2311   }
2312 }
2313 
2314 /* Use Desk == -1 to scroll the icon window */
Scroll(int window_w,int window_h,int x,int y,int Desk,Bool do_scroll_icon)2315 void Scroll(int window_w, int window_h, int x, int y, int Desk,
2316 	    Bool do_scroll_icon)
2317 {
2318 	static int last_sx = -999999;
2319 	static int last_sy = -999999;
2320 	int sx;
2321 	int sy;
2322 	int adjx,adjy;
2323 
2324 	/* Desk < 0 means we want to scroll an icon window */
2325 	if (Desk >= 0 && Desk + desk1 != Scr.CurrentDesk)
2326 	{
2327 		return;
2328 	}
2329 
2330 	/* center around mouse */
2331 	adjx = (desk_w / (1 + Scr.VxMax / Scr.MyDisplayWidth));
2332 	adjy = (desk_h / (1 + Scr.VyMax / Scr.MyDisplayHeight));
2333 	x -= adjx/2;
2334 	y -= adjy/2;
2335 
2336 	/* adjust for pointer going out of range */
2337 	if (x < 0)
2338 	{
2339 		x = 0;
2340 	}
2341 	if (y < 0)
2342 	{
2343 		y = 0;
2344 	}
2345 
2346 	if (x > window_w-adjx)
2347 	{
2348 		x = window_w-adjx;
2349 	}
2350 	if (y > window_h-adjy)
2351 	{
2352 		y = window_h-adjy;
2353 	}
2354 
2355 	sx = 0;
2356 	sy = 0;
2357 	if (window_w != 0)
2358 	{
2359 		sx = (x * Scr.VWidth / window_w - MyVx);
2360 	}
2361 	if (window_h != 0)
2362 	{
2363 		sy = (y * Scr.VHeight / window_h - MyVy);
2364 	}
2365 	MYFPRINTF((stderr,"[scroll]: %d %d %d %d %d %d\n", window_w, window_h,
2366 		   x, y, sx, sy));
2367 	if (sx == 0 && sy == 0)
2368 	{
2369 		return;
2370 	}
2371 	if (Wait == 0 || last_sx != sx || last_sy != sy)
2372 	{
2373 		do_scroll(sx, sy, False, False);
2374 
2375 		/* Here we need to track the view offset on the desk. */
2376 		/* sx/y are are pixels on the screen to scroll. */
2377 		/* We don't use Scr.Vx/y since they lag the true position. */
2378 		MyVx += sx;
2379 		if (MyVx < 0)
2380 		{
2381 			MyVx = 0;
2382 		}
2383 		MyVy += sy;
2384 
2385 		if (MyVy < 0)
2386 		{
2387 			MyVy = 0;
2388 		}
2389 		Wait = 1;
2390 	}
2391 	if (Wait == 0)
2392 	{
2393 		last_sx = sx;
2394 		last_sy = sy;
2395 	}
2396 
2397 	return;
2398 }
2399 
MoveWindow(XEvent * Event)2400 void MoveWindow(XEvent *Event)
2401 {
2402 	char command[100];
2403 	int x1, y1, wx, wy, n, x, y, xi = 0, yi = 0, wx1, wy1, x2, y2;
2404 	int finished = 0;
2405 	Window dumwin;
2406 	PagerWindow *t;
2407 	int m, n1, m1;
2408 	int NewDesk, KeepMoving = 0;
2409 	int moved = 0;
2410 	int row, column;
2411 	Window JunkRoot, JunkChild;
2412 	int JunkX, JunkY;
2413 	unsigned JunkMask;
2414 	int do_switch_desk_later = 0;
2415 
2416 	t = Start;
2417 	while (t != NULL && t->PagerView != Event->xbutton.subwindow)
2418 	{
2419 		t = t->next;
2420 	}
2421 
2422 	if (t == NULL)
2423 	{
2424 		t = Start;
2425 		while (t != NULL && t->IconView != Event->xbutton.subwindow)
2426 		{
2427 			t = t->next;
2428 		}
2429 		if (t != NULL)
2430 		{
2431 			IconMoveWindow(Event, t);
2432 			return;
2433 		}
2434 	}
2435 
2436 	if (t == NULL || !t->allowed_actions.is_movable)
2437 	{
2438 		return;
2439 	}
2440 
2441 	NewDesk = t->desk - desk1;
2442 	if (NewDesk < 0 || NewDesk >= ndesks)
2443 	{
2444 		return;
2445 	}
2446 
2447 	n = Scr.VxMax / Scr.MyDisplayWidth;
2448 	m = Scr.VyMax / Scr.MyDisplayHeight;
2449 	n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
2450 	m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
2451 	wx = (Scr.Vx + t->x) * (desk_w - n) / Scr.VWidth + n1;
2452 	wy = (Scr.Vy + t->y) * (desk_h - m) / Scr.VHeight + m1;
2453 	wx1 = wx + (desk_w + 1) * (NewDesk % Columns);
2454 	wy1 = wy + label_h + (desk_h + label_h + 1) * (NewDesk / Columns);
2455 	if (LabelsBelow)
2456 	{
2457 		wy1 -= label_h;
2458 	}
2459 
2460 	XReparentWindow(dpy, t->PagerView, Scr.Pager_w, wx1, wy1);
2461 	XRaiseWindow(dpy, t->PagerView);
2462 
2463 	XTranslateCoordinates(dpy, Event->xany.window, t->PagerView,
2464 			      Event->xbutton.x, Event->xbutton.y, &x1, &y1,
2465 			      &dumwin);
2466 	xi = x1;
2467 	yi = y1;
2468 	while (!finished)
2469 	{
2470 		FMaskEvent(dpy, ButtonReleaseMask | ButtonMotionMask |
2471 			   ExposureMask, Event);
2472 		if (Event->type == MotionNotify)
2473 		{
2474 			XTranslateCoordinates(dpy, Event->xany.window,
2475 					      Scr.Pager_w, Event->xmotion.x,
2476 					      Event->xmotion.y, &x, &y,
2477 					      &dumwin);
2478 
2479 			if (moved == 0)
2480 			{
2481 				xi = x;
2482 				yi = y;
2483 				moved = 1;
2484 			}
2485 			if (x < -5 || y < -5 || x > window_w + 5 ||
2486 			   y > window_h + 5)
2487 			{
2488 				KeepMoving = 1;
2489 				finished = 1;
2490 			}
2491 			XMoveWindow(dpy, t->PagerView, x - x1, y - y1);
2492 		}
2493 		else if (Event->type == ButtonRelease)
2494 		{
2495 			XTranslateCoordinates(dpy, Event->xany.window,
2496 					      Scr.Pager_w, Event->xbutton.x,
2497 					      Event->xbutton.y, &x, &y,
2498 					      &dumwin);
2499 			XMoveWindow(dpy, t->PagerView, x - x1, y - y1);
2500 			finished = 1;
2501 		}
2502 		else if (Event->type == Expose)
2503 		{
2504 			HandleExpose(Event);
2505 		}
2506 	}
2507 
2508 	if (moved)
2509 	{
2510 		if (abs(x - xi) < MoveThreshold &&
2511 		    abs(y - yi) < MoveThreshold)
2512 		{
2513 			moved = 0;
2514 		}
2515 	}
2516 	if (KeepMoving)
2517 	{
2518 		NewDesk = Scr.CurrentDesk;
2519 
2520 		if (NewDesk >= desk1 && NewDesk <= desk2)
2521 		{
2522 			XReparentWindow(dpy, t->PagerView,
2523 					Desks[NewDesk-desk1].w, 0, 0);
2524 		}
2525 		else
2526 		{
2527 			XDestroyWindow(dpy, t->PagerView);
2528 			t->PagerView = None;
2529 		}
2530 		if (FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
2531 				  &x, &y, &JunkX, &JunkY, &JunkMask) == False)
2532 		{
2533 			/* pointer is on a different screen */
2534 			x = 0;
2535 			y = 0;
2536 		}
2537 		XUngrabPointer(dpy,CurrentTime);
2538 		XSync(dpy,0);
2539 
2540 		if (NewDesk != t->desk)
2541 		{
2542 			/* griph: This used to move to NewDesk, but NewDesk
2543 			 * is current desk, and if fvwm is on another
2544 			 * desk (due to async operation) we have to move
2545 			 * the window to it anyway or "Move Pointer" will
2546 			 * move an invisible window. */
2547 
2548 			SendText(fd, "Silent MoveToDesk", t->w);
2549 			t->desk = NewDesk;
2550 		}
2551 		SendText(fd, "Silent Raise", t->w);
2552 		SendText(fd, "Silent Move Pointer", t->w);
2553 		return;
2554 	}
2555 	else
2556 	{
2557 		column = x / (desk_w + 1);
2558 		if (column >= Columns)
2559 		{
2560 			column = Columns - 1;
2561 		}
2562 		if (column < 0)
2563 		{
2564 			column = 0;
2565 		}
2566 		row = y / (desk_h + label_h + 1);
2567 		if (row >= Rows)
2568 		{
2569 			row = Rows - 1;
2570 		}
2571 		if (row < 0)
2572 		{
2573 			row = 0;
2574 		}
2575 		NewDesk = column + row * Columns;
2576 		while (NewDesk < 0)
2577 		{
2578 			NewDesk += Columns;
2579 			if (NewDesk >= ndesks)
2580 			{
2581 				NewDesk = 0;
2582 			}
2583 		}
2584 		while (NewDesk >= ndesks)
2585 		{
2586 			NewDesk -= Columns;
2587 			if (NewDesk < 0)
2588 			{
2589 				NewDesk = ndesks - 1;
2590 			}
2591 		}
2592 		XTranslateCoordinates(dpy, Scr.Pager_w, Desks[NewDesk].w,
2593 				      x - x1, y - y1, &x2, &y2, &dumwin);
2594 
2595 		n1 = x2 * Scr.VWidth / (desk_w * Scr.MyDisplayWidth);
2596 		m1 = y2 * Scr.VHeight / (desk_h * Scr.MyDisplayHeight);
2597 		x = (x2 - n1) * Scr.VWidth / (desk_w - n) - Scr.Vx;
2598 		y = (y2 - m1) * Scr.VHeight / (desk_h - m) - Scr.Vy;
2599 		/* force onto desk */
2600 		if (x + t->frame_width + Scr.Vx < 0 )
2601 		{
2602 			x = -Scr.Vx - t->frame_width;
2603 		}
2604 		if (y + t->frame_height + Scr.Vy < 0)
2605 		{
2606 			y = -Scr.Vy - t->frame_height;
2607 		}
2608 		if (x + Scr.Vx >= Scr.VWidth)
2609 		{
2610 			x = Scr.VWidth - Scr.Vx - 1;
2611 		}
2612 		if (y + Scr.Vy >= Scr.VHeight)
2613 		{
2614 			y = Scr.VHeight - Scr.Vy - 1;
2615 		}
2616 		if ((IS_ICONIFIED(t) && IS_ICON_STICKY_ACROSS_DESKS(t)) ||
2617 		   (IS_STICKY_ACROSS_DESKS(t)))
2618 		{
2619 			NewDesk = Scr.CurrentDesk - desk1;
2620 			if (x > Scr.MyDisplayWidth - 16)
2621 			{
2622 				x = Scr.MyDisplayWidth - 16;
2623 			}
2624 			if (y > Scr.MyDisplayHeight - 16)
2625 			{
2626 				y = Scr.MyDisplayHeight - 16;
2627 			}
2628 			if (x + t->width < 16)
2629 			{
2630 				x = 16 - t->width;
2631 			}
2632 			if (y + t->height < 16)
2633 			{
2634 				y = 16 - t->height;
2635 			}
2636 		}
2637 		if (NewDesk + desk1 != t->desk)
2638 		{
2639 			if ((IS_ICONIFIED(t) && IS_ICON_STICKY_ACROSS_DESKS(t))
2640 			   || (IS_STICKY_ACROSS_DESKS(t)))
2641 			{
2642 				NewDesk = Scr.CurrentDesk - desk1;
2643 				if (t->desk != Scr.CurrentDesk)
2644 				{
2645 					ChangeDeskForWindow(t,Scr.CurrentDesk);
2646 				}
2647 			}
2648 			else if (NewDesk + desk1 != Scr.CurrentDesk)
2649 			{
2650 				sprintf(command, "Silent MoveToDesk 0 %d",
2651 					NewDesk + desk1);
2652 				SendText(fd, command, t->w);
2653 				t->desk = NewDesk + desk1;
2654 			}
2655 			else
2656 			{
2657 				do_switch_desk_later = 1;
2658 			}
2659 		}
2660 
2661 		if (NewDesk >= 0 && NewDesk < ndesks)
2662 		{
2663 			XReparentWindow(dpy, t->PagerView,
2664 					Desks[NewDesk].w, x2, y2);
2665 			t->desk = NewDesk;
2666 			XClearArea(dpy, t->PagerView, 0, 0, 0, 0, True);
2667 			if (moved)
2668 			{
2669 				char buf[64];
2670 				sprintf(buf, "Silent Move +%dp +%dp", x, y);
2671 
2672 				SendText(fd, buf, t->w);
2673 				XSync(dpy,0);
2674 			}
2675 			else
2676 			{
2677 				MoveResizePagerView(t, True);
2678 			}
2679 			SendText(fd, "Silent Raise", t->w);
2680 		}
2681 		if (do_switch_desk_later)
2682 		{
2683 			sprintf(command, "Silent MoveToDesk 0 %d", NewDesk +
2684 				desk1);
2685 			SendText(fd, command, t->w);
2686 			t->desk = NewDesk + desk1;
2687 		}
2688 		if (Scr.CurrentDesk == t->desk)
2689 		{
2690 			XSync(dpy,0);
2691 			usleep(5000);
2692 			XSync(dpy,0);
2693 
2694 			SendText(fd, "Silent FlipFocus NoWarp", t->w);
2695 		}
2696 	}
2697 	if (is_transient)
2698 	{
2699 		/* does not return */
2700 		ExitPager();
2701 	}
2702 }
2703 
2704 
2705 /*
2706  *
2707  *  Procedure:
2708  *	FvwmErrorHandler - displays info on internal errors
2709  *
2710  */
FvwmErrorHandler(Display * dpy,XErrorEvent * event)2711 int FvwmErrorHandler(Display *dpy, XErrorEvent *event)
2712 {
2713 #if 1
2714   extern Bool error_occured;
2715   error_occured = True;
2716   return 0;
2717 #else
2718   /* really should just exit here... */
2719   /* domivogt (07-mar-1999): No, not really. See comment above. */
2720   PrintXErrorAndCoredump(dpy, event, MyName);
2721   return 0;
2722 #endif /* 1 */
2723 }
2724 
draw_window_border(PagerWindow * t,Window w,int width,int height)2725 static void draw_window_border(PagerWindow *t, Window w, int width, int height)
2726 {
2727   if (w != None)
2728   {
2729     if (!WindowBorders3d || windowcolorset < 0 || activecolorset < 0)
2730     {
2731       XSetForeground(dpy, Scr.NormalGC, Scr.black);
2732       RelieveRectangle(
2733 	dpy, w, 0, 0, width - 1, t->pager_view_height - 1,
2734 	Scr.NormalGC, Scr.NormalGC, WindowBorderWidth);
2735     }
2736     else if (t == FocusWin)
2737     {
2738       RelieveRectangle(
2739 	dpy, w, 0, 0, width - 1, height - 1,
2740 	Scr.ahGC, Scr.asGC, WindowBorderWidth);
2741     }
2742     else
2743     {
2744       RelieveRectangle(
2745 	dpy, w, 0, 0, width - 1, height - 1,
2746 	Scr.whGC, Scr.wsGC, WindowBorderWidth);
2747     }
2748   }
2749 }
2750 
BorderWindow(PagerWindow * t)2751 void BorderWindow(PagerWindow *t)
2752 {
2753   draw_window_border(
2754     t, t->PagerView, t->pager_view_width, t->pager_view_height);
2755 }
2756 
BorderIconWindow(PagerWindow * t)2757 void BorderIconWindow(PagerWindow *t)
2758 {
2759   draw_window_border(
2760     t, t->IconView, t->icon_view_width, t->icon_view_height);
2761 }
2762 
2763 /* draw the window label with simple greedy wrapping */
label_window_wrap(PagerWindow * t)2764 static void label_window_wrap(PagerWindow *t)
2765 {
2766   char *cur, *next, *end;
2767   int space_width, cur_width;
2768 
2769   space_width = FlocaleTextWidth(FwindowFont, " ", 1);
2770   cur_width   = 0;
2771 
2772   cur = next = t->window_label;
2773   end = cur + strlen(cur);
2774 
2775   while (*cur) {
2776     while (*next) {
2777       int width;
2778       char *p;
2779 
2780       if (!(p = strchr(next, ' ')))
2781         p = end;
2782 
2783       width = FlocaleTextWidth(FwindowFont, next, p - next );
2784       if (width > t->pager_view_width - cur_width - space_width - 2*label_border)
2785         break;
2786       cur_width += width + space_width;
2787       next = *p ? p + 1 : p;
2788     }
2789 
2790     if (cur == next) {
2791       /* word too large for window */
2792       while (*next) {
2793         int len, width;
2794 
2795         len   = FlocaleStringNumberOfBytes(FwindowFont, next);
2796         width = FlocaleTextWidth(FwindowFont, next, len);
2797 
2798         if (width > t->pager_view_width - cur_width - 2*label_border && cur != next)
2799           break;
2800 
2801         next      += len;
2802         cur_width += width;
2803       }
2804     }
2805 
2806     FwinString->str = safemalloc(next - cur + 1);
2807     strncpy(FwinString->str, cur, next - cur);
2808     FwinString->str[next - cur] = 0;
2809 
2810     FlocaleDrawString(dpy, FwindowFont, FwinString, 0);
2811 
2812     free(FwinString->str);
2813     FwinString->str = NULL;
2814 
2815     FwinString->y += FwindowFont->height;
2816     cur = next;
2817     cur_width = 0;
2818   }
2819 }
2820 
do_label_window(PagerWindow * t,Window w)2821 static void do_label_window(PagerWindow *t, Window w)
2822 {
2823   int cs;
2824 
2825   if (t == FocusWin)
2826   {
2827     XSetForeground(dpy, Scr.NormalGC, focus_fore_pix);
2828     cs =  activecolorset;
2829   }
2830   else
2831   {
2832     XSetForeground(dpy, Scr.NormalGC, t->text);
2833     cs = windowcolorset;
2834   }
2835 
2836   if (FwindowFont == NULL)
2837   {
2838     return;
2839   }
2840   if (MiniIcons && t->mini_icon.picture && (t->PagerView != None))
2841   {
2842     /* will draw picture instead... */
2843     return;
2844   }
2845   if (t->icon_name == NULL)
2846   {
2847     return;
2848   }
2849 
2850   /* Update the window label for this window */
2851   if (t->window_label)
2852     free(t->window_label);
2853   t->window_label = GetBalloonLabel(t, WindowLabelFormat);
2854   if (w != None)
2855   {
2856     if (FftSupport && FwindowFont != NULL && FwindowFont->fftf.fftfont != NULL)
2857       XClearWindow(dpy, w);
2858     FwinString->win = w;
2859     FwinString->gc = Scr.NormalGC;
2860     FwinString->flags.has_colorset = False;
2861     if (cs >= 0)
2862     {
2863 	    FwinString->colorset = &Colorset[cs];
2864 	    FwinString->flags.has_colorset = True;
2865     }
2866     FwinString->x = label_border;
2867     FwinString->y = FwindowFont->ascent+2;
2868 
2869     label_window_wrap(t);
2870   }
2871 }
2872 
LabelWindow(PagerWindow * t)2873 void LabelWindow(PagerWindow *t)
2874 {
2875   do_label_window(t, t->PagerView);
2876 }
2877 
LabelIconWindow(PagerWindow * t)2878 void LabelIconWindow(PagerWindow *t)
2879 {
2880   do_label_window(t, t->IconView);
2881 }
2882 
do_picture_window(PagerWindow * t,Window w,int width,int height)2883 static void do_picture_window(
2884 	PagerWindow *t, Window w, int width, int height)
2885 {
2886 	int iconX;
2887 	int iconY;
2888 	int src_x = 0;
2889 	int src_y = 0;
2890 	int dest_w, dest_h;
2891 	int cs;
2892 	FvwmRenderAttributes fra;
2893 
2894 	if (MiniIcons)
2895 	{
2896 		if (t->mini_icon.picture && w != None)
2897 		{
2898 			dest_w = t->mini_icon.width;
2899 			dest_h = t->mini_icon.height;
2900 			if (width > t->mini_icon.width)
2901 			{
2902 				iconX = (width - t->mini_icon.width) / 2;
2903 			}
2904 			else if (width < t->mini_icon.width)
2905 			{
2906 				iconX = 0;
2907 				src_x = (t->mini_icon.width - width) / 2;
2908 				dest_w = width;
2909 			}
2910 			else
2911 			{
2912 				iconX = 0;
2913 			}
2914 			if (height > t->mini_icon.height)
2915 			{
2916 				iconY = (height - t->mini_icon.height) / 2;
2917 			}
2918 			else if (height < t->mini_icon.height)
2919 			{
2920 				iconY = 0;
2921 				src_y = (t->mini_icon.height - height) / 2;
2922 				dest_h = height;
2923 			}
2924 			else
2925 			{
2926 				iconY = 0;
2927 			}
2928 			fra.mask = FRAM_DEST_IS_A_WINDOW;
2929 			if (t == FocusWin)
2930 			{
2931 				cs =  activecolorset;
2932 			}
2933 			else
2934 			{
2935 				cs = windowcolorset;
2936 			}
2937 			if (t->mini_icon.alpha != None ||
2938 			    (cs >= 0 &&
2939 			     Colorset[cs].icon_alpha_percent < 100))
2940 			{
2941 				XClearArea(dpy, w, iconX, iconY,
2942 					   t->mini_icon.width,
2943 					   t->mini_icon.height, False);
2944 			}
2945 			if (cs >= 0)
2946 			{
2947 				fra.mask |= FRAM_HAVE_ICON_CSET;
2948 				fra.colorset = &Colorset[cs];
2949 			}
2950 			PGraphicsRenderPicture(
2951 				dpy, w, &t->mini_icon, &fra, w,
2952 				Scr.MiniIconGC, None, None, src_x, src_y,
2953 				t->mini_icon.width - src_x,
2954 				t->mini_icon.height - src_y,
2955 				iconX, iconY, dest_w, dest_h, False);
2956 		}
2957 	}
2958 }
2959 
PictureWindow(PagerWindow * t)2960 void PictureWindow (PagerWindow *t)
2961 {
2962   do_picture_window(t, t->PagerView, t->pager_view_width, t->pager_view_height);
2963 }
2964 
PictureIconWindow(PagerWindow * t)2965 void PictureIconWindow (PagerWindow *t)
2966 {
2967   do_picture_window(t, t->IconView, t->icon_view_width, t->icon_view_height);
2968 }
2969 
IconMoveWindow(XEvent * Event,PagerWindow * t)2970 void IconMoveWindow(XEvent *Event, PagerWindow *t)
2971 {
2972 	int x1, y1, finished = 0, n, x = 0, y = 0, xi = 0, yi = 0;
2973 	Window dumwin;
2974 	int m, n1, m1;
2975 	int moved = 0;
2976 	int KeepMoving = 0;
2977 	Window JunkRoot, JunkChild;
2978 	int JunkX, JunkY;
2979 	unsigned JunkMask;
2980 
2981 	if (t == NULL || !t->allowed_actions.is_movable)
2982 	{
2983 		return;
2984 	}
2985 
2986 	n = Scr.VxMax / Scr.MyDisplayWidth;
2987 	m = Scr.VyMax / Scr.MyDisplayHeight;
2988 	n1 = (Scr.Vx + t->x) / Scr.MyDisplayWidth;
2989 	m1 = (Scr.Vy + t->y) / Scr.MyDisplayHeight;
2990 
2991 	XRaiseWindow(dpy, t->IconView);
2992 
2993 	XTranslateCoordinates(dpy, Event->xany.window, t->IconView,
2994 			      Event->xbutton.x, Event->xbutton.y, &x1, &y1,
2995 			      &dumwin);
2996 	while (!finished)
2997 	{
2998 		FMaskEvent(dpy, ButtonReleaseMask | ButtonMotionMask |
2999 			   ExposureMask, Event);
3000 
3001 		if (Event->type == MotionNotify)
3002 		{
3003 			x = Event->xbutton.x;
3004 			y = Event->xbutton.y;
3005 			if (moved == 0)
3006 			{
3007 				xi = x;
3008 				yi = y;
3009 				moved = 1;
3010 			}
3011 
3012 			XMoveWindow(dpy, t->IconView, x - x1, y - y1);
3013 			if (x < -5 || y < -5 || x > icon_w + 5 ||
3014 			    y > icon_h + 5)
3015 			{
3016 				finished = 1;
3017 				KeepMoving = 1;
3018 			}
3019 		}
3020 		else if (Event->type == ButtonRelease)
3021 		{
3022 			x = Event->xbutton.x;
3023 			y = Event->xbutton.y;
3024 			XMoveWindow(dpy, t->PagerView, x - x1, y - y1);
3025 			finished = 1;
3026 		}
3027 		else if (Event->type == Expose)
3028 		{
3029 			HandleExpose(Event);
3030 		}
3031 	}
3032 
3033 	if (moved)
3034 	{
3035 		if (abs(x - xi) < MoveThreshold &&
3036 		    abs(y - yi) < MoveThreshold)
3037 		{
3038 			moved = 0;
3039 		}
3040 	}
3041 
3042 	if (KeepMoving)
3043 	{
3044 		if (FQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
3045 				  &x, &y, &JunkX, &JunkY, &JunkMask) == False)
3046 		{
3047 			/* pointer is on a different screen */
3048 			x = 0;
3049 			y = 0;
3050 		}
3051 		XUngrabPointer(dpy, CurrentTime);
3052 		XSync(dpy, 0);
3053 		SendText(fd, "Silent Raise", t->w);
3054 		SendText(fd, "Silent Move Pointer", t->w);
3055 	}
3056 	else
3057 	{
3058 		x = x - x1;
3059 		y = y - y1;
3060 		n1 = x * Scr.VWidth / (icon_w * Scr.MyDisplayWidth);
3061 		m1 = y * Scr.VHeight / (icon_h * Scr.MyDisplayHeight);
3062 		x = (x - n1) * Scr.VWidth / (icon_w - n) - Scr.Vx;
3063 		y = (y - m1) * Scr.VHeight / (icon_h - m) - Scr.Vy;
3064 		/* force onto desk */
3065 		if (x + t->icon_width + Scr.Vx < 0 )
3066 		{
3067 			x = - Scr.Vx - t->icon_width;
3068 		}
3069 		if (y + t->icon_height + Scr.Vy < 0)
3070 		{
3071 			y = - Scr.Vy - t->icon_height;
3072 		}
3073 		if (x + Scr.Vx >= Scr.VWidth)
3074 		{
3075 			x = Scr.VWidth - Scr.Vx - 1;
3076 		}
3077 		if (y + Scr.Vy >= Scr.VHeight)
3078 		{
3079 			y = Scr.VHeight - Scr.Vy - 1;
3080 		}
3081 		if ((IS_ICONIFIED(t) && IS_ICON_STICKY_ACROSS_DESKS(t)) ||
3082 		   IS_STICKY_ACROSS_DESKS(t))
3083 		{
3084 			if (x > Scr.MyDisplayWidth - 16)
3085 			{
3086 				x = Scr.MyDisplayWidth - 16;
3087 			}
3088 			if (y > Scr.MyDisplayHeight - 16)
3089 			{
3090 				y = Scr.MyDisplayHeight - 16;
3091 			}
3092 			if (x + t->width < 16)
3093 			{
3094 				x = 16 - t->width;
3095 			}
3096 			if (y + t->height < 16)
3097 			{
3098 				y = 16 - t->height;
3099 			}
3100 		}
3101 		if (moved)
3102 		{
3103 			char buf[64];
3104 			sprintf(buf, "Silent Move +%dp +%dp", x, y);
3105 			SendText(fd, buf, t->w);
3106 			XSync(dpy, 0);
3107 		}
3108 		else
3109 		{
3110 			MoveResizePagerView(t, True);
3111 		}
3112 		SendText(fd, "Silent Raise", t->w);
3113 		SendText(fd, "Silent FlipFocus NoWarp", t->w);
3114 	}
3115 	if (is_transient)
3116 	{
3117 		/* does not return */
3118 		ExitPager();
3119 	}
3120 }
3121 
3122 
setup_balloon_window(int i)3123 void setup_balloon_window(int i)
3124 {
3125 	XSetWindowAttributes xswa;
3126 	unsigned long valuemask;
3127 
3128 	if (!ShowBalloons && Scr.balloon_w == None)
3129 	{
3130 		return;
3131 	}
3132 	XUnmapWindow(dpy, Scr.balloon_w);
3133 	if (Desks[i].ballooncolorset < 0)
3134 	{
3135 		xswa.border_pixel = (!BalloonBorderColor) ?
3136 			fore_pix : GetColor(BalloonBorderColor);
3137 		xswa.background_pixel =
3138 			(!BalloonBack) ? back_pix : GetColor(BalloonBack);
3139 		valuemask = CWBackPixel | CWBorderPixel;
3140 	}
3141 	else
3142 	{
3143 		xswa.border_pixel = Colorset[Desks[i].ballooncolorset].fg;
3144 		xswa.background_pixel = Colorset[Desks[i].ballooncolorset].bg;
3145 		if (Colorset[Desks[i].ballooncolorset].pixmap)
3146 		{
3147 			/* set later */
3148 			xswa.background_pixmap = None;
3149 			valuemask = CWBackPixmap | CWBorderPixel;;
3150 		}
3151 		else
3152 		{
3153 			valuemask = CWBackPixel | CWBorderPixel;
3154 		}
3155 	}
3156 	XChangeWindowAttributes(dpy, Scr.balloon_w, valuemask, &xswa);
3157 
3158 	return;
3159 }
3160 
setup_balloon_gc(int i,PagerWindow * t)3161 void setup_balloon_gc(int i, PagerWindow *t)
3162 {
3163 	XGCValues xgcv;
3164 	unsigned long valuemask;
3165 
3166 	valuemask = GCForeground;
3167 	if (Desks[i].ballooncolorset < 0)
3168 	{
3169 		xgcv.foreground =
3170 			(!BalloonFore) ? fore_pix : GetColor(BalloonFore);
3171 		if (BalloonFore == NULL)
3172 		{
3173 			XSetForeground(dpy, Scr.balloon_gc, t->text);
3174 		}
3175 	}
3176 	else
3177 	{
3178 		xgcv.foreground = Colorset[Desks[i].ballooncolorset].fg;
3179 	}
3180 	if (Desks[i].balloon.Ffont->font != NULL)
3181 	{
3182 		xgcv.font = Desks[i].balloon.Ffont->font->fid;
3183 		valuemask |= GCFont;
3184 	}
3185 	XChangeGC(dpy, Scr.balloon_gc, valuemask, &xgcv);
3186 
3187 	return;
3188 }
3189 
3190 /* Just maps window ... draw stuff in it later after Expose event
3191    -- ric@giccs.georgetown.edu */
MapBalloonWindow(PagerWindow * t,Bool is_icon_view)3192 void MapBalloonWindow(PagerWindow *t, Bool is_icon_view)
3193 {
3194 	extern char *BalloonBack;
3195 	extern int BalloonYOffset;
3196 	extern int BalloonBorderWidth;
3197 	Window view, dummy;
3198 	int view_width, view_height;
3199 	int x, y;
3200 	rectangle new_g;
3201 	int i;
3202 
3203 	if (!is_icon_view)
3204 	{
3205 		view = t->PagerView;
3206 		view_width = t->pager_view_width;
3207 		view_height = t->pager_view_height;
3208 	}
3209 	else
3210 	{
3211 		view = t->IconView;
3212 		view_width = t->icon_view_width;
3213 		view_height = t->icon_view_height;
3214 	}
3215 	BalloonView = view;
3216 	/* associate balloon with its pager window */
3217 	if (fAlwaysCurrentDesk)
3218 	{
3219 		i = 0;
3220 	}
3221 	else
3222 	{
3223 		i = t->desk - desk1;
3224 	}
3225 
3226 	if (i < 0)
3227 		return;
3228 
3229 	Scr.balloon_desk = i;
3230 	/* get the label for this balloon */
3231 	if (Scr.balloon_label)
3232 	{
3233 		free(Scr.balloon_label);
3234 	}
3235 	Scr.balloon_label = GetBalloonLabel(t, BalloonFormatString);
3236 #if 0
3237 	if (Scr.balloon_label == NULL)
3238 	{
3239 		/* dont draw empty labels */
3240 		return;
3241 	}
3242 #endif
3243 	setup_balloon_window(i);
3244 	setup_balloon_gc(i, t);
3245 	/* calculate window width to accommodate string */
3246 	new_g.height = Desks[i].balloon.height;
3247 	new_g.width = 4;
3248 	if (Scr.balloon_label)
3249 	{
3250 		new_g.width += FlocaleTextWidth(
3251 			Desks[i].balloon.Ffont,	 Scr.balloon_label,
3252 			strlen(Scr.balloon_label));
3253 	}
3254 	/* get x and y coords relative to pager window */
3255 	x = (view_width / 2) - (new_g.width / 2) - BalloonBorderWidth;
3256 	if (BalloonYOffset > 0)
3257 	{
3258 		y = view_height + BalloonYOffset - 1;
3259 	}
3260 	else
3261 	{
3262 		y = BalloonYOffset - new_g.height + 1 -
3263 			(2 * BalloonBorderWidth);
3264 	}
3265 	/* balloon is a top-level window, therefore need to
3266 	   translate pager window coords to root window coords */
3267 	XTranslateCoordinates(
3268 		dpy, view, Scr.Root, x, y, &new_g.x, &new_g.y,
3269 		&dummy);
3270 	/* make sure balloon doesn't go off screen
3271 	 * (actually 2 pixels from edge rather than 0 just to be pretty :-) */
3272 	/* too close to top ... make yoffset +ve */
3273 	if ( new_g.y < 2 )
3274 	{
3275 		y = - BalloonYOffset - 1 + view_height;
3276 		XTranslateCoordinates(
3277 			dpy, view, Scr.Root, x, y, &new_g.x, &new_g.y, &dummy);
3278 	}
3279 	/* too close to bottom ... make yoffset -ve */
3280 	else if ( new_g.y + new_g.height >
3281 		  Scr.MyDisplayHeight - (2 * BalloonBorderWidth) - 2 )
3282 	{
3283 		y = - BalloonYOffset + 1 - new_g.height -
3284 			(2 * BalloonBorderWidth);
3285 		XTranslateCoordinates(
3286 			dpy, view, Scr.Root, x, y, &new_g.x, &new_g.y, &dummy);
3287 	}
3288 	/* too close to left */
3289 	if ( new_g.x < 2 )
3290 	{
3291 		new_g.x = 2;
3292 	}
3293 	/* too close to right */
3294 	else if (new_g.x + new_g.width >
3295 		 Scr.MyDisplayWidth - (2 * BalloonBorderWidth) - 2 )
3296 	{
3297 		new_g.x = Scr.MyDisplayWidth - new_g.width -
3298 			(2 * BalloonBorderWidth) - 2;
3299 	}
3300 	/* make changes to window */
3301 	XMoveResizeWindow(
3302 		dpy, Scr.balloon_w, new_g.x, new_g.y, new_g.width,
3303 		new_g.height);
3304 	/* if background not set in config make it match pager window */
3305 	if ( BalloonBack == NULL )
3306 	{
3307 		XSetWindowBackground(dpy, Scr.balloon_w, t->back);
3308 	}
3309 	if (Desks[i].ballooncolorset > -1)
3310 	{
3311 		SetWindowBackground(
3312 			dpy, Scr.balloon_w, new_g.width, new_g.height,
3313 			&Colorset[Desks[i].ballooncolorset], Pdepth,
3314 			Scr.NormalGC, True);
3315 		XSetWindowBorder(
3316 			dpy, Scr.balloon_w,
3317 			Colorset[Desks[i].ballooncolorset].fg);
3318 	}
3319 	XMapRaised(dpy, Scr.balloon_w);
3320 
3321 	return;
3322 }
3323 
3324 
InsertExpand(char ** dest,char * s)3325 static void InsertExpand(char **dest, char *s)
3326 {
3327   int len;
3328   char *tmp = *dest;
3329 
3330   if (!s || !*s)
3331     return;
3332   len = strlen(*dest) + strlen(s) + 1;
3333   *dest = (char *)safemalloc(len);
3334   strcpy(*dest, tmp);
3335   free(tmp);
3336   strcat(*dest, s);
3337   return;
3338 }
3339 
3340 
3341 /* Generate the BallonLabel from the format string
3342    -- disching@fmi.uni-passau.de */
GetBalloonLabel(const PagerWindow * pw,const char * fmt)3343 char *GetBalloonLabel(const PagerWindow *pw,const char *fmt)
3344 {
3345   char *dest = safestrdup("");
3346   const char *pos = fmt;
3347   char buffer[2];
3348 
3349   buffer[1] = '\0';
3350 
3351   while (*pos) {
3352     if (*pos=='%' && *(pos+1)!='\0') {
3353       pos++;
3354       switch (*pos) {
3355       case 'i':
3356 	InsertExpand(&dest, pw->icon_name);
3357 	break;
3358       case 't':
3359 	InsertExpand(&dest, pw->window_name);
3360 	break;
3361       case 'r':
3362 	InsertExpand(&dest, pw->res_name);
3363 	break;
3364       case 'c':
3365 	InsertExpand(&dest, pw->res_class);
3366 	break;
3367       case '%':
3368 	buffer[0] = '%';
3369 	InsertExpand(&dest, buffer);
3370 	break;
3371       default:;
3372       }
3373     } else {
3374       buffer[0] = *pos;
3375       InsertExpand(&dest, buffer);
3376     }
3377     pos++;
3378   }
3379   return dest;
3380 }
3381 
3382 
3383 /* -- ric@giccs.georgetown.edu */
UnmapBalloonWindow(void)3384 void UnmapBalloonWindow (void)
3385 {
3386   XUnmapWindow(dpy, Scr.balloon_w);
3387   BalloonView = None;
3388 }
3389 
3390 
3391 /* Draws string in balloon window -- call after it's received Expose event
3392    -- ric@giccs.georgetown.edu */
DrawInBalloonWindow(int i)3393 void DrawInBalloonWindow (int i)
3394 {
3395 	FwinString->str = Scr.balloon_label;
3396 	FwinString->win = Scr.balloon_w;
3397 	FwinString->gc = Scr.balloon_gc;
3398 	if (Desks[i].ballooncolorset >= 0)
3399 	{
3400 		FwinString->colorset = &Colorset[Desks[i].ballooncolorset];
3401 		FwinString->flags.has_colorset = True;
3402 	}
3403 	else
3404 	{
3405 		FwinString->flags.has_colorset = False;
3406 	}
3407 	FwinString->x = 2;
3408 	FwinString->y = Desks[i].balloon.Ffont->ascent;
3409 	FlocaleDrawString(dpy, Desks[i].balloon.Ffont, FwinString, 0);
3410 
3411 	return;
3412 }
3413 
set_window_colorset_background(PagerWindow * t,colorset_t * csetp)3414 static void set_window_colorset_background(
3415   PagerWindow *t, colorset_t *csetp)
3416 {
3417   if (t->PagerView != None)
3418   {
3419     SetWindowBackground(
3420       dpy, t->PagerView, t->pager_view_width, t->pager_view_height,
3421       csetp, Pdepth, Scr.NormalGC, True);
3422   }
3423   SetWindowBackground(
3424     dpy, t->IconView, t->icon_view_width, t->icon_view_height,
3425     csetp, Pdepth, Scr.NormalGC, True);
3426 
3427   return;
3428 }
3429 
3430 /* should be in sync with  draw_desk_background */
change_colorset(int colorset)3431 void change_colorset(int colorset)
3432 {
3433   int i;
3434   PagerWindow *t;
3435 
3436   /* just in case */
3437   if (colorset < 0)
3438     return;
3439 
3440   XSetWindowBackgroundPixmap(dpy, Scr.Pager_w, default_pixmap);
3441   for(i=0;i<ndesks;i++)
3442   {
3443     if (Desks[i].highcolorset == colorset)
3444     {
3445       XSetForeground(dpy, Desks[i].HiliteGC,Colorset[colorset].bg);
3446       XSetForeground(dpy, Desks[i].rvGC, Colorset[colorset].fg);
3447       if (HilightDesks)
3448       {
3449 	if (uselabel && (i == Scr.CurrentDesk))
3450 	{
3451 	  SetWindowBackground(
3452 	    dpy, Desks[i].title_w, desk_w, desk_h, &Colorset[colorset], Pdepth,
3453 	    Scr.NormalGC, True);
3454 	}
3455 	SetWindowBackground(
3456 	  dpy, Desks[i].CPagerWin, 0, 0, &Colorset[colorset], Pdepth,
3457 	  Scr.NormalGC, True);
3458 	XLowerWindow(dpy,Desks[i].CPagerWin);
3459       }
3460     }
3461 
3462     if (Desks[i].colorset == colorset)
3463     {
3464       XSetWindowBorder(dpy, Desks[i].title_w, Colorset[colorset].fg);
3465       XSetWindowBorder(dpy, Desks[i].w, Colorset[colorset].fg);
3466       XSetForeground(dpy, Desks[i].NormalGC,Colorset[colorset].fg);
3467       XSetForeground(dpy, Desks[i].DashedGC,Colorset[colorset].fg);
3468       if (uselabel)
3469       {
3470 	SetWindowBackground(
3471 	  dpy, Desks[i].title_w, desk_w, desk_h + label_h, &Colorset[colorset],
3472 	  Pdepth, Scr.NormalGC, True);
3473       }
3474       if (label_h != 0 && uselabel && !LabelsBelow &&
3475 	  !CSET_IS_TRANSPARENT_PR(Desks[i].colorset))
3476       {
3477 	SetWindowBackgroundWithOffset(
3478 	  dpy, Desks[i].w, 0, -label_h, desk_w, desk_h + label_h,
3479 	  &Colorset[colorset], Pdepth, Scr.NormalGC, True);
3480       }
3481       else
3482       {
3483 	SetWindowBackground(
3484 	  dpy, Desks[i].w, desk_w, desk_h + label_h,
3485 	  &Colorset[Desks[i].colorset], Pdepth, Scr.NormalGC, True);
3486       }
3487       update_pr_transparent_subwindows(i);
3488     }
3489     else if (Desks[i].highcolorset == colorset && uselabel)
3490     {
3491       SetWindowBackground(
3492 	dpy, Desks[i].title_w, 0, 0, &Colorset[Desks[i].colorset], Pdepth,
3493 	Scr.NormalGC, True);
3494     }
3495   }
3496   if (ShowBalloons && Desks[Scr.balloon_desk].ballooncolorset == colorset)
3497   {
3498     XSetWindowBackground(dpy, Scr.balloon_w, Colorset[colorset].fg);
3499     XSetForeground(dpy,Scr.balloon_gc, Colorset[colorset].fg);
3500     XClearArea(dpy, Scr.balloon_w, 0, 0, 0, 0, True);
3501   }
3502 
3503   if (windowcolorset == colorset)
3504   {
3505     colorset_t *csetp = &Colorset[colorset];
3506 
3507     XSetForeground(dpy, Scr.whGC, csetp->hilite);
3508     XSetForeground(dpy, Scr.wsGC, csetp->shadow);
3509     win_back_pix = csetp->bg;
3510     win_fore_pix = csetp->fg;
3511     win_pix_set = True;
3512     for (t = Start; t != NULL; t = t->next)
3513     {
3514       t->text = Colorset[colorset].fg;
3515       if (t != FocusWin)
3516       {
3517 	set_window_colorset_background(t, csetp);
3518       }
3519     }
3520   }
3521   if (activecolorset == colorset)
3522   {
3523     colorset_t *csetp = &Colorset[colorset];
3524 
3525     focus_fore_pix = csetp->fg;
3526     XSetForeground(dpy, Scr.ahGC, csetp->hilite);
3527     XSetForeground(dpy, Scr.asGC, csetp->shadow);
3528     win_hi_back_pix = csetp->bg;
3529     win_hi_fore_pix = csetp->fg;
3530     win_hi_pix_set = True;
3531     if (FocusWin)
3532     {
3533       set_window_colorset_background(FocusWin, csetp);
3534     }
3535   }
3536 
3537   return;
3538 }
3539