1 /* Wharf.c. by Bo Yang.
2  * Modifications: Copyright 1995 by Bo Yang.
3  *
4  * modifications made by Frank Fejes for AfterStep
5  * Copyright 1996
6  *
7  * folder code Copyright 1996 by Beat Christen.
8  *
9  * swallowed button actions Copyright 1996 by Kaj Groner
10  *
11  * based on GoodStuff.c by Robert Nation
12  * The GoodStuff module, and the entire GoodStuff program, and the concept for
13  * interfacing that module to the Window Manager, are all original work
14  * by Robert Nation
15  *
16  * Copyright 1993, Robert Nation.
17  * No guarantees or warantees or anything
18  * are provided or implied in any way whatsoever. Use this program at your
19  * own risk. Permission to use this program for any purpose is given,
20  * as long as the copyright is kept intact.  */
21 
22 /*
23  * Various enhancements Copyright 1996 Alfredo K. Kojima
24  *
25  * button pushing styles
26  * configurable border drawing
27  * Change of icon creation code. Does not use shape extension anymore.
28  * 	each icon window now contains the whole background
29  * OffiX drop support added
30  * animation added
31  * withdraw on button2 click
32  * icon overlaying
33  * sound bindings
34  */
35 
36 #define TRUE 1
37 #define FALSE 0
38 #define DOUBLECLICKTIME 1
39 
40 #include "../../configure.h"
41 
42 #ifdef ISC
43 #include <sys/bsdtypes.h> /* Saul */
44 #endif
45 
46 #include <stdio.h>
47 #include <signal.h>
48 #include <fcntl.h>
49 #include <string.h>
50 #include <sys/wait.h>
51 #include <sys/time.h>
52 #if defined ___AIX || defined _AIX || defined __QNX__ || defined ___AIXV3 || defined AIXV3 || defined _SEQUENT_
53 #include <sys/select.h>
54 #endif
55 #include <unistd.h>
56 #include <ctype.h>
57 #include <stdlib.h>
58 #include "../../afterstep/module.h"
59 #include <X11/Xlib.h>
60 #include <X11/Xutil.h>
61 #include <X11/Xproto.h>
62 #include <X11/Xatom.h>
63 #include <X11/Intrinsic.h>
64 
65 #include "Wharf.h"
66 #include "../../version.h"
67 #define AFTER_ICONS 1
68 #include "../../afterstep/asbuttons.h"
69 
70 #ifdef ENABLE_DND
71 #include "OffiX/DragAndDrop.h"
72 #include "OffiX/DragAndDropTypes.h"
73 #endif
74 
75 #include "stepgfx.h"
76 
77 /*
78  * You may want to raise the following values if your machine is fast
79  */
80 #define ANIM_STEP	2   /* must be >= 1. Greater is smoother and slower */
81 #define ANIM_STEP_MAIN	1   /* same for the main folder */
82 #define ANIM_DELAY	10
83 
84 #ifdef ENABLE_SOUND
85 #define WHEV_PUSH		0
86 #define WHEV_CLOSE_FOLDER	1
87 #define WHEV_OPEN_FOLDER	2
88 #define WHEV_CLOSE_MAIN		3
89 #define WHEV_OPEN_MAIN		4
90 #define WHEV_DROP		5
91 #define MAX_EVENTS		6
92 
93 int SoundActive = 0;
94 char *Sounds[6]={".",".",".",".",".","."};
95 char *SoundPlayer=NULL;
96 char *SoundPath=".";
97 
98 pid_t SoundThread;
99 int PlayerChannel[2];
100 
101 char *ModulePath=AFTERDIR;
102 #endif
103 
104 char *MyName;
105 
106 Display *dpy;
107 int x_fd,fd_width;
108 int ROWS = FALSE;
109 
110 Window Root;
111 int screen;
112 int flags;
113 long d_depth;
114 Bool NoBorder=0;
115 Bool Pushed = 0;
116 Bool Pushable = 1;
117 Bool ForceSize=0;
118 Pixel back_pix, fore_pix, light_grey;
119 GC  NormalGC, HiReliefGC, HiInnerGC;
120 
121 GC MaskGC, DefGC;
122 int AnimationStyle=0,AnimateMain=0;
123 int PushStyle=0;
124 int AnimationDir=1;
125 
126 Window main_win;
127 int Width, Height,win_x,win_y;
128 unsigned int display_width, display_height;
129 
130 #define MW_EVENTS   (ExposureMask | ButtonReleaseMask |\
131 		     ButtonPressMask | LeaveWindowMask | EnterWindowMask)
132 XSizeHints mysizehints;
133 int num_buttons = 0;
134 int num_folderbuttons = MAX_BUTTONS;
135 int num_folders = 0;
136 int num_rows = 0;
137 int num_columns = 0;
138 int max_icon_width = 30,max_icon_height = 0;
139 int BUTTONWIDTH, BUTTONHEIGHT;
140 int x= -100000,y= -100000,w= -1,h= -1,gravity = NorthWestGravity;
141 int new_desk = 0;
142 int pageing_enabled = 1;
143 int ready = 0;
144 
145 int CurrentButton = -1;
146 int fd[2];
147 
148 struct button_info Buttons[BUTTON_ARRAY_LN];
149 struct folder_info Folders[FOLDER_ARRAY_LN];
150 
151 char *iconPath = NULL;
152 char *pixmapPath = NULL;
153 
154 static Atom wm_del_win;
155 Atom _XA_WM_PROTOCOLS;
156 Atom _XA_WM_NAME;
157 #ifdef ENABLE_DND
158 Atom DndProtocol;
159 Atom DndSelection;
160 #endif
161 int TextureType=TEXTURE_BUILTIN;
162 char *BgPixmapFile=NULL;
163 int FromColor[3]={0x4000,0x4000,0x4000}, ToColor[3]={0x8000,0x8000,0x8000};
164 Pixel BgColor=0;
165 int MaxColors=16;
166 int Withdrawn;
167 
168 #define DIR_TOLEFT	1
169 #define DIR_TORIGHT	2
170 #define DIR_TOUP	3
171 #define DIR_TODOWN	4
172 
173 #ifdef ENABLE_SOUND
waitchild(int bullshit)174 void waitchild(int bullshit)
175 {
176     int stat;
177 
178     wait(&stat);
179     SoundActive=0;
180 }
181 #endif
182 
183 unsigned int lock_mods[256];
184 void FindLockMods(void);
185 
186 
187 /***********************************************************************
188  *
189  *  Procedure:
190  *	main - start of afterstep
191  *
192  ***********************************************************************
193  */
main(int argc,char ** argv)194 int main(int argc, char **argv)
195 {
196   char *display_name = NULL;
197   int i,j;
198   Window root;
199   int x,y,border_width,button;
200   int depth;
201   char *temp, *s;
202   char set_mask_mesg[50];
203   temp = argv[0];
204 
205   s=strrchr(argv[0], '/');
206   if (s != NULL)
207     temp = s + 1;
208 
209   MyName = safemalloc(strlen(temp)+1);
210   strcpy(MyName, temp);
211 
212   for(i=0;i<BUTTON_ARRAY_LN;i++)
213     {
214 #ifdef ENABLE_DND
215       Buttons[i].drop_action = NULL;
216 #endif
217       Buttons[i].title = NULL;
218       Buttons[i].action = NULL;
219       Buttons[i].iconno = 0;
220       for(j=0;j<MAX_OVERLAY;j++) {
221 	  Buttons[i].icons[j].file = NULL;
222 	  Buttons[i].icons[j].w = 0;
223 	  Buttons[i].icons[j].h = 0;
224 	  Buttons[i].icons[j].mask = None;	/* pixmap for the icon mask */
225 	  Buttons[i].icons[j].icon = None;
226 	  Buttons[i].icons[j].depth = 0;
227       }
228       Buttons[i].IconWin = None;
229       Buttons[i].completeIcon = None;
230       Buttons[i].up = 1;                        /* Buttons start up */
231       Buttons[i].hangon = NULL;                 /* don't wait on anything yet*/
232       Buttons[i].folder = -1;
233     }
234   signal (SIGPIPE, DeadPipe);
235   if((argc != 6)&&(argc != 7))
236     {
237       fprintf(stderr,"%s Version %s should only be executed by AfterStep!\n",
238 		MyName, VERSION);
239       exit(1);
240     }
241   fd[0] = atoi(argv[1]);
242   fd[1] = atoi(argv[2]);
243 
244   if (!(dpy = XOpenDisplay(display_name)))
245     {
246       fprintf(stderr,"%s: can't open display %s", MyName,
247 	      XDisplayName(display_name));
248       exit (1);
249     }
250   x_fd = XConnectionNumber(dpy);
251 
252   fd_width = GetFdWidth();
253 
254   screen= DefaultScreen(dpy);
255   Root = RootWindow(dpy, screen);
256   if(Root == None)
257     {
258       fprintf(stderr,"%s: Screen %d is not valid ", MyName, screen);
259       exit(1);
260     }
261   display_width = DisplayWidth(dpy, screen);
262   display_height = DisplayHeight(dpy, screen);
263 
264   d_depth = DefaultDepth(dpy, screen);
265 
266   sprintf(set_mask_mesg,"SET_MASK %lu\n",
267 	  (unsigned long)(M_TOGGLE_PAGING|
268 			  M_NEW_DESK |
269 			  M_END_WINDOWLIST|
270 			  M_MAP|
271 			  M_RES_NAME|
272 			  M_RES_CLASS|
273 			  M_WINDOW_NAME));
274   SendText(fd,set_mask_mesg,0);
275   ParseOptions(argv[3]);
276   if(num_buttons == 0)
277     {
278       fprintf(stderr,"%s: No Buttons defined. Quitting\n", MyName);
279       exit(0);
280     }
281 
282 #ifdef ENABLE_SOUND
283     /* startup sound subsystem */
284      if (SoundActive) {
285 	if (pipe(PlayerChannel)<0) {
286 	    fprintf(stderr,"%s: could not create pipe. Disabling sound\n");
287 	    SoundActive=0;
288 	} else {
289 	    signal(SIGCHLD,waitchild);
290 	    SoundThread=fork();
291 	    if (SoundThread<0) {
292 		fprintf(stderr,"%s: could not fork(). Disabling sound",
293 			MyName);
294 		perror(".");
295 		SoundActive=0;
296 	    } else if (SoundThread==0) { /* in the sound player process */
297 		char *margv[9], *name;
298 		int i;
299 
300 		margv[0]="ASSound";
301 		name = findIconFile("ASSound",ModulePath,X_OK);
302 		if(name == NULL) {
303 		    fprintf(stderr,"Wharf: couldn't find ASSound\n");
304 		    SoundActive = 0;
305 		} else {
306 		    margv[1]=safemalloc(16);
307 		    close(PlayerChannel[1]);
308 		    sprintf(margv[1],"%x",PlayerChannel[0]);
309 		    if (SoundPlayer!=NULL)
310 		      margv[2]=SoundPlayer;
311 		    else
312 		      margv[2]="-";
313 		    for(i=0;i<MAX_EVENTS;i++) {
314 			if (Sounds[i][0]=='.') {
315 			    margv[i+3]=Sounds[i];
316 			} else {
317 			    margv[i+3]=safemalloc(strlen(Sounds[i])
318 						  +strlen(SoundPath)+4);
319 			    sprintf(margv[i+3],"%s/%s",SoundPath,Sounds[i]);
320 			}
321 		    }
322 		    margv[i+3]=NULL;
323 		    execvp(name,margv);
324 		    fprintf(stderr,"Wharf: couldn't spawn ASSound\n");
325 		    exit(1);
326 		}
327 	    } else { /* in parent */
328 		close(PlayerChannel[0]);
329 	    }
330 	}
331      }
332 #endif
333 
334     CreateShadowGC();
335     switch (TextureType) {
336      case TEXTURE_PIXMAP:
337 	if (BgPixmapFile==NULL) {
338 	    fprintf(stderr,"%s: No Button background pixmap defined.Using default\n", MyName);
339 	    goto Builtin;
340 	}
341 	Buttons[BACK_BUTTON].icons[0].file=BgPixmapFile;
342 	if (GetXPMFile(BACK_BUTTON,0))
343 	  break;
344 	else goto Solid;
345      case TEXTURE_GRADIENT:
346      case TEXTURE_HGRADIENT:
347      case TEXTURE_HCGRADIENT:
348      case TEXTURE_VGRADIENT:
349      case TEXTURE_VCGRADIENT:
350 	if (GetXPMGradient(BACK_BUTTON, FromColor, ToColor, MaxColors,TextureType))
351 	  break;
352 	else goto Solid;
353 
354      case TEXTURE_BUILTIN:
355 	Builtin:
356 	TextureType=TEXTURE_BUILTIN;
357 	if (GetXPMData( BACK_BUTTON, button_xpm))
358 	  break;
359 
360      default:
361 Solid:
362 	TextureType=TEXTURE_SOLID;
363 	if (GetSolidXPM(BACK_BUTTON, BgColor))
364 	  break;
365 	else {
366 	    fprintf( stderr, "back Wharf button creation\n");
367 	    exit(-1);
368 	}
369     }
370   for(i=0;i<num_buttons;i++)
371     {
372 	for(j=0;j<Buttons[i].iconno;j++) {
373 	    LoadIconFile(i,j);
374 	}
375     }
376   for(i=num_folderbuttons;i<MAX_BUTTONS;i++) {
377      	for(j=0;j<Buttons[i].iconno;j++) {
378 	    LoadIconFile(i,j);
379 	}
380   }
381 #ifdef ENABLE_DND
382   DndProtocol=XInternAtom(dpy,"DndProtocol",False);
383   DndSelection=XInternAtom(dpy,"DndSelection",False);
384 #endif
385 
386 
387   CreateWindow();
388   for(i=0;i<num_buttons;i++) {
389       CreateIconWindow(i, &main_win);
390   }
391   for(i=num_folderbuttons;i<MAX_BUTTONS;i++)
392     CreateIconWindow(i, Buttons[i].parent);
393   XGetGeometry(dpy,main_win,&root,&x,&y,
394 	       (unsigned int *)&Width,(unsigned int *)&Height,
395  	       (unsigned int *)&border_width,(unsigned int *)&depth);
396 
397   for(i=0;i<num_rows;i++)
398     for(j=0;j<num_columns; j++)
399       {
400 	button = i*num_columns + j;
401 	ConfigureIconWindow(button,i,j);
402       };
403   for(i=0;i<num_folders;i++)
404     for(j=0;j<Folders[i].count;j++)
405       if(num_columns < num_rows) {
406 	ConfigureIconWindow(Folders[i].firstbutton+j,0, j);
407       } else {
408 	ConfigureIconWindow(Folders[i].firstbutton+j,j, 0);
409       }
410   /* dirty hack to make swallowed app background be textured */
411   XSetWindowBackgroundPixmap(dpy, main_win, Buttons[BACK_BUTTON].icons[0].icon);
412   XMapSubwindows(dpy,main_win);
413   XMapWindow(dpy,main_win);
414   for(i=0;i<num_folders;i++)
415       XMapSubwindows(dpy, Folders[i].win);
416 
417   FindLockMods();
418 
419   /* request a window list, since this triggers a response which
420    * will tell us the current desktop and paging status, needed to
421    * indent buttons correctly */
422   SendText(fd,"Send_WindowList",0);
423   Loop();
424 
425 }
426 
427 /***********************************************************************
428  *
429  *  Procedure:
430  *	Loop - wait for data to process
431  *
432  ***********************************************************************/
433 
Loop(void)434 void Loop(void)
435 {
436   Window *CurrentWin=None;
437   int x,y,w,h,xoff,yoff,border_width,CurrentRow,CurrentColumn,CurrentBase=0;
438   long depth;
439   XEvent Event;
440   int NewButton,i,j,button,tw,th,i2, bl=-1;
441   int LastMapped=-1;
442   char *temp;
443   time_t t, tl = (time_t) 0;
444   int CancelPush=0;
445 
446   while(1)
447     {
448       if(My_XNextEvent(dpy,&Event))
449 	{
450 	  switch(Event.type)
451 	    {
452 
453 	    case Expose:
454 	      for(x=0;x<num_folders;x++)
455 		if(Event.xany.window == Folders[x].win )
456 		  {
457 		    RedrawWindow(&Folders[x].win,num_folderbuttons, -1, Folders[x].cols,Folders[x].rows);
458 		    for(y=1;y<=Folders[x].count;y++)
459 		    if(num_columns<num_rows)
460 		      RedrawUnpushedOutline(&Folders[x].win, 1, y);
461 		    else
462 		      RedrawUnpushedOutline(&Folders[x].win, y, 1);
463 		  }
464 		    if (Pushed)
465                 break;
466 	      if((Event.xexpose.count == 0)&&
467 		 (Event.xany.window == main_win))
468 		{
469 		    if(ready < 1)
470 		      ready ++;
471 		    RedrawWindow(&main_win,0, -1, num_rows, num_columns);
472 		}
473 	      break;
474 
475 	    case ButtonPress:
476 	      if (Event.xbutton.button != Button1) {
477 		  if (Event.xbutton.button == Button2) {
478 		      static int LastX, LastY;
479 
480 		      if (LastMapped != -1) {
481 			  CloseFolder(LastMapped);
482 			  Folders[LastMapped].mapped = NOTMAPPED;
483 			  LastMapped=-1;
484 		      }
485 		      if (Withdrawn) {
486 #ifdef ENABLE_SOUND
487 			  PlaySound(WHEV_OPEN_MAIN);
488 #endif
489 			  if (AnimationStyle>0 && AnimateMain)
490 			    OpenFolder(-1,LastX,LastY,Width,Height,
491 				       AnimationDir);
492 			  else
493 			    XMoveResizeWindow(dpy,main_win,LastX,LastY,
494 					      Width,Height);
495 			  Withdrawn=0;
496 		      } else {
497 			  Window junk;
498 			  int junk2,junk3,junk4,junk5;
499 			  int CornerX, CornerY;
500 
501 #ifdef ENABLE_SOUND
502 			  PlaySound(WHEV_CLOSE_MAIN);
503 #endif
504 			  XGetGeometry(dpy,main_win,&junk,&LastX,&LastY,
505 				       &junk2,&junk3,&junk4,&junk5);
506 			  XTranslateCoordinates(dpy,main_win,Root,
507 						LastX,LastY,
508 						&LastX,&LastY,&junk);
509 			  if (num_rows<num_columns) { /* horizontal */
510 			      if (LastY > display_height/2) {
511 				  CornerY = display_height-BUTTONHEIGHT;
512 			      } else {
513 				  CornerY = 0;
514 			      }
515 			      if (Event.xbutton.x>num_columns*BUTTONWIDTH/2) {
516 				  CornerX = display_width - BUTTONWIDTH;
517 				  AnimationDir = DIR_TOLEFT;
518 			      } else {
519 				  CornerX = 0;
520 				  AnimationDir = DIR_TORIGHT;
521 			      }
522 			      if (AnimationStyle>0 && AnimateMain) {
523 				  CloseFolder(-1);
524 				  XMoveWindow(dpy,main_win, CornerX, CornerY);
525 			      } else {
526 				  XMoveResizeWindow(dpy,main_win,
527 						    CornerX, CornerY,
528 						    BUTTONWIDTH,BUTTONHEIGHT);
529 			      }
530 			  } else {	/* vertical */
531 			      if (LastX > display_width/2) {
532 				  CornerX = display_width - BUTTONWIDTH;
533 			      } else {
534 				  CornerX = 0;
535 			      }
536 			      if (Event.xbutton.y>num_rows*BUTTONHEIGHT/2) {
537 				  CornerY = display_height-BUTTONHEIGHT;
538 				  AnimationDir = DIR_TOUP;
539 			      } else {
540 				  CornerY = 0;
541 				  AnimationDir = DIR_TODOWN;
542 			      }
543 			      if (AnimationStyle>0 && AnimateMain) {
544 				  CloseFolder(-1);
545 				  XMoveWindow(dpy,main_win, CornerX, CornerY);
546 			      } else {
547 				  XMoveResizeWindow(dpy,main_win,
548 						    CornerX, CornerY,
549 						    BUTTONWIDTH,BUTTONHEIGHT);
550 			      }
551 			  }
552 			  Withdrawn=1;
553 		      }
554 		  }
555 		  break;
556 	      }
557 #ifdef ENABLE_SOUND
558 		PlaySound(WHEV_PUSH);
559 #endif
560 	      CancelPush = 0;
561 	      CurrentWin = &Event.xbutton.window;
562 	      CurrentBase = 0;
563 	      CurrentRow = (Event.xbutton.y/BUTTONHEIGHT);
564 	      CurrentColumn = (Event.xbutton.x/BUTTONWIDTH);
565 	      if (*CurrentWin!=main_win) {
566 		  CurrentButton = CurrentBase + CurrentColumn*num_rows
567 		    + CurrentRow*num_columns;
568 	      }	else {
569 		  CurrentButton = CurrentBase + CurrentColumn
570 		    + CurrentRow*num_columns;
571 		  if (CurrentButton>=num_buttons) {
572 		      CurrentButton = -1;
573 		      break;
574 		  }
575 	      }
576 
577               for(x=0;x<num_buttons;x++)
578                 {
579                   if (*CurrentWin == Buttons[x].IconWin)
580                     {
581                       CurrentButton = x;
582                       CurrentRow = x / num_columns;
583                       CurrentColumn = x % num_columns;
584                     }
585                 }
586 
587 	      for(x=0;x<num_folders;x++)
588 		if(*CurrentWin == Folders[x].win)
589 		  {
590 		    CurrentBase = Folders[x].firstbutton;
591 		    if (num_rows<num_columns)
592 			CurrentButton = CurrentBase + CurrentRow;
593 		     else
594 			CurrentButton = CurrentBase + CurrentColumn;
595 		  }
596 	      i = CurrentRow+1;
597 	      j = CurrentColumn +1;
598 
599               if (Buttons[CurrentButton].swallow == 1 ||
600                   Buttons[CurrentButton].swallow == 2 ||
601                   Buttons[CurrentButton].action == NULL)
602 		break;
603 
604 	      if (Pushable)
605 		{
606                   if (Buttons[CurrentButton].swallow != 3 &&
607                       Buttons[CurrentButton].swallow != 4)
608                     {
609                       Pushed = 1;
610                       RedrawPushed(CurrentWin, i, j);
611                     }
612 		}
613 	      if (mystrncasecmp(Buttons[CurrentButton].action,"Folder",6)==0) {
614                 Window junk;
615                 int junk2,junk3,junk4,junk5;
616                 XGetGeometry(dpy,main_win,&junk,&x,&y,
617                           &junk2,&junk3,&junk4,&junk5);
618                 XTranslateCoordinates(dpy,main_win,Root,
619                           x,y,
620                           &x,&y,&junk);
621 /* kludge until Beat takes a look */
622 if ((num_columns == 1) && (num_rows == 1))
623 		MapFolder(Buttons[CurrentButton].folder,
624 			  &LastMapped,
625                           x, y,
626 			  1,1);
627 else
628 		MapFolder(Buttons[CurrentButton].folder,
629 			  &LastMapped,
630                           x, y,
631 			  CurrentRow, CurrentColumn);
632 	      }
633               break;
634 	     case EnterNotify:
635 		CancelPush = 0;
636 		break;
637 	     case LeaveNotify:
638 		CancelPush = 1;
639 		break;
640 #ifdef ENABLE_DND
641 	     case ClientMessage:
642 		if (Event.xclient.message_type==DndProtocol) {
643 		    unsigned long  dummy_r,size;
644 		    Atom dummy_a;
645 		    int dummy_f;
646 		    unsigned char *data, *Command;
647 
648 		    Window dummy_rt, dummy_c;
649 		    int dummy_x, dummy_y, base, pos_x, pos_y;
650 		    unsigned int dummy;
651 
652 /*		    if (Event.xclient.data.l[0]!=DndFile ||
653 			Event.xclient.data.l[0]!=DndFiles ||
654 			Event.xclient.data.l[0]!=DndExe
655 			)
656 		      break; */
657 
658 		    XQueryPointer(dpy,main_win,
659 				  &dummy_rt,&dummy_c,
660 				  &dummy_x,&dummy_y,
661 				  &pos_x,&pos_y,
662 				  &dummy);
663 		    base = 0;
664 		    dummy_y = (pos_y/BUTTONHEIGHT);
665 		    dummy_x= (pos_x/BUTTONWIDTH);
666 		    dummy = base + dummy_x + dummy_y*num_columns;
667 
668 		    /*
669 		    for(x=0;x<num_folders;x++) {
670 			if(Event.xbutton.window == Folders[x].win) {
671 			    base = Folders[x].firstbutton;
672 			    dummy = base + dummy_y + dummy_x -1;
673 			}
674 		    } */
675 		    if (Buttons[dummy].drop_action == NULL)
676 		      break;
677 		    dummy_x++;
678 		    dummy_y++;
679 		    CurrentWin=Buttons[dummy].parent;
680 		    if (Pushable) {
681 			RedrawPushedOutline(CurrentWin, dummy_y, dummy_x);
682 			XSync(dpy, 0);
683 		    }
684 		    XGetWindowProperty(dpy, Root, DndSelection, 0L,
685 				       100000L, False, AnyPropertyType,
686 				       &dummy_a, &dummy_f,
687 				       &size,&dummy_r,
688 				       &data);
689 		    if (Event.xclient.data.l[0]==DndFiles) {
690 			for (dummy_r = 0; dummy_r<size-1; dummy_r++) {
691 			    if (data[dummy_r]==0)
692 			      data[dummy_r]=' ';
693 			}
694 		    }
695 #ifdef ENABLE_SOUND
696 		    PlaySound(WHEV_DROP);
697 #endif
698 		    Command=safemalloc(strlen(data)
699 				    + strlen(Buttons[dummy].drop_action));
700 		    sprintf(Command,Buttons[dummy].drop_action,
701 			    data,Event.xclient.data.l[0]);
702 		    SendInfo(fd,Command,0);
703 		    free(Command);
704 		    if (Pushable) {
705 			sleep_a_little(50000);
706 			XClearWindow(dpy,Buttons[dummy].IconWin);
707 			RedrawUnpushedOutline(CurrentWin, dummy_y, dummy_x);
708 		    }
709 		}
710 		break;
711 #endif /* ENABLE_DND */
712             case ButtonRelease:
713 	      if ((Event.xbutton.button != Button1) ||
714 		  (Buttons[CurrentButton].swallow == 1) ||
715 		  (Buttons[CurrentButton].swallow == 2) ||
716 		  (Buttons[CurrentButton].action == NULL)) {
717 		  break;
718 	      }
719 
720               CurrentRow = (Event.xbutton.y/BUTTONHEIGHT);
721               CurrentColumn = (Event.xbutton.x/BUTTONWIDTH);
722 
723               if (Pushable)
724               {
725 		if (Buttons[CurrentButton].swallow != 3 &&
726 		    Buttons[CurrentButton].swallow != 4)
727 		  {
728 		    Pushed=0;
729 		    RedrawUnpushed(CurrentWin, i, j);
730 		  }
731               }
732 	      if (CancelPush)
733 		  break;
734 	      if (*CurrentWin!=main_win) {
735 		  NewButton = CurrentBase + CurrentColumn*num_rows
736 		    + CurrentRow*num_columns;
737 	      }	else {
738 		  NewButton = CurrentBase + CurrentColumn
739 		    + CurrentRow*num_columns;
740 	      }
741 
742  	      for(x=0;x<num_folders;x++)
743 		if(*CurrentWin == Folders[x].win)
744 		  {
745 		    if (num_rows<num_columns)
746 			NewButton = Folders[x].firstbutton + CurrentRow;
747 		     else
748 			NewButton = Folders[x].firstbutton + CurrentColumn;
749 		  }
750 	      for (x=0;x<num_buttons;x++)
751 	        {
752 		  if (*CurrentWin == Buttons[x].IconWin)
753 		    {
754 		      NewButton = x;
755 		      CurrentRow = x / num_columns;
756 		      CurrentColumn = x % num_columns;
757 		    }
758 		}
759 
760               if(NewButton == CurrentButton)
761                 {
762 		  t = time( 0);
763 		  bl = -1;
764 		  tl = -1;
765 		  if(mystrncasecmp(Buttons[CurrentButton].action,"Folder",6)!=0)
766 		    {
767 		      if (LastMapped != -1 && CurrentWin != &main_win)
768 			{
769 			  CloseFolder(LastMapped);
770 			  Folders[LastMapped].mapped = NOTMAPPED;
771 			  LastMapped = -1;
772 			}
773 		      SendInfo(fd,Buttons[CurrentButton].action,0);
774 		    }
775 		  if((Buttons[CurrentButton].action)&&
776 		     (mystrncasecmp(Buttons[CurrentButton].action,"exec",4)== 0))
777 		    {
778 		      i=4;
779 		      while((Buttons[CurrentButton].action[i] != 0)&&
780 			    (Buttons[CurrentButton].action[i] != '"'))
781 			i++;
782 		      i2=i+1;
783 
784 		      while((Buttons[CurrentButton].action[i2] != 0)&&
785 			    (Buttons[CurrentButton].action[i2] != '"'))
786 			i2++;
787 		      if(i2 - i >1)
788 			{
789                           Buttons[CurrentButton].hangon = safemalloc(i2-i);
790                           strncpy(Buttons[CurrentButton].hangon,
791 				  &Buttons[CurrentButton].action[i+1],i2-i-1);
792                           Buttons[CurrentButton].hangon[i2-i-1] = 0;
793                           Buttons[CurrentButton].up = 0;
794 			  if (Buttons[CurrentButton].swallow == 3 ||
795 			      Buttons[CurrentButton].swallow == 4)
796                             Buttons[CurrentButton].swallow = 4;
797 			  else
798                             Buttons[CurrentButton].swallow = 0;
799 			}
800 		    }
801                 }
802               break;
803 
804 	      /*
805 		case ClientMessage:
806 		if ((Event.xclient.format==32) &&
807 		(Event.xclient.data.l[0]==wm_del_win))
808 		{
809 		DeadPipe(1);
810 		}
811 		break;
812 		case PropertyNotify:
813 		if (Pushed)
814 		break;
815 		for(i=0;i<num_rows;i++)
816 		for(j=0;j<num_columns; j++)
817 		{
818 		button = i*num_columns + j;
819 		if(((Buttons[button].swallow == 3)||
820 		(Buttons[button.swallow == 4))&&
821 		(Event.xany.window == Buttons[button].IconWin)&&
822 		(Event.xproperty.atom == XA_WM_NAME))
823 		{
824 		XFetchName(dpy, Buttons[button].IconWin, &temp);
825 		if(strcmp(Buttons[button].title,"-")!=0)
826 		CopyString(&Buttons[button].title, temp);
827 		XFree(temp);
828 		XClearArea(dpy,main_win,j*BUTTONWIDTH,
829 		i*BUTTONHEIGHT, BUTTONWIDTH,BUTTONHEIGHT,0);
830 		RedrawWindow(&main_win,0, button, num_rows, num_columns);
831 		}
832 		}
833 		break;
834 		*/
835 	    default:
836 	      break;
837 	    }
838 	}
839     }
840   return;
841 }
842 
OpenFolder(int folder,int x,int y,int w,int h,int direction)843 void OpenFolder(int folder,int x, int y, int w, int h,  int direction)
844 {
845     int winc, hinc;
846     int cx, cy, cw, ch;
847     Window win;
848     int isize;
849 
850     if (folder<0) {
851 	    winc = BUTTONWIDTH/ANIM_STEP_MAIN;
852 	    hinc = BUTTONHEIGHT/ANIM_STEP_MAIN;
853     } else {
854 	    winc = BUTTONWIDTH/ANIM_STEP;
855 	    hinc = BUTTONHEIGHT/ANIM_STEP;
856     }
857 
858     if (folder>=0) {
859 	win = Folders[folder].win;
860 	Folders[folder].direction = direction;
861 	if (direction == DIR_TOLEFT || direction == DIR_TORIGHT)
862 	  isize = winc;
863 	else
864 	  isize = hinc;
865     } else {
866 	win = main_win;
867 	if (direction == DIR_TOLEFT || direction == DIR_TORIGHT)
868 	  isize = BUTTONWIDTH;
869 	else
870 	  isize = BUTTONHEIGHT;
871     }
872     cx = x;    cy = y;
873     ch = h;    cw = w;
874     if (AnimationStyle==0) {
875  	XMapWindow(dpy, win);
876     } else
877     switch (direction) {
878      case DIR_TOLEFT:
879 	cx = x+w;
880 	XMoveResizeWindow(dpy,win,cx,y, 1, h);
881 	XMapWindow(dpy, win);
882 	for(cw=isize;cw<=w;cw+=winc) {
883 	    cx -= winc;
884 	    sleep_a_little(ANIM_DELAY/2);
885 	    XMoveResizeWindow(dpy,win,cx,y, cw,h);
886 	    XSync(dpy,0);
887 	}
888 	break;
889      case DIR_TORIGHT:
890 	XMoveResizeWindow(dpy,win,x,y, 1, h);
891 	XMapWindow(dpy, win);
892 	for(cw=isize;cw<=w;cw+=winc) {
893 	    sleep_a_little(ANIM_DELAY/2);
894 	    XMoveResizeWindow(dpy,win,x,y, cw,h);
895 	    XSync(dpy,0);
896 	}
897 	break;
898      case DIR_TOUP:
899 	cy = y+h;
900 	XMoveResizeWindow(dpy,win,x,cy, w, 1);
901 	XMapWindow(dpy, win);
902 	for(ch=isize;ch<=h;ch+=hinc) {
903 	    cy -= hinc;
904 	    sleep_a_little(ANIM_DELAY/2);
905 	    XMoveResizeWindow(dpy,win,x,cy, w, ch);
906 	    XSync(dpy,0);
907 	}
908 	break;
909      case DIR_TODOWN:
910 	XMoveResizeWindow(dpy,win,x,y, w, 1);
911 	XMapWindow(dpy, win);
912 	for(ch=isize;ch<=h;ch+=hinc) {
913 	    sleep_a_little(ANIM_DELAY/2);
914 	    XMoveResizeWindow(dpy,win,x,y, w, ch);
915 	    XSync(dpy,0);
916 	}
917 	break;
918      default:
919 	XBell(dpy,100);
920 	fprintf(stderr,"WHARF INTERNAL BUG in OpenFolder()\n");
921 	exit(-1);
922     }
923 
924     if (cw!=w || ch!=h || x != cx || cy != y || AnimationStyle==0)
925       XMoveResizeWindow(dpy,win,x,y,w,h);
926 }
927 
928 
929 
CloseFolder(int folder)930 void CloseFolder(int folder)
931 {
932     int winc, hinc;
933     int cx, cy, cw, ch;
934     int x,y,w,h, junk_depth, junk_bd;
935     int fsize, direction;
936     Window win, junk_win;
937 
938 #ifdef ENABLE_SOUND
939 	PlaySound(WHEV_CLOSE_FOLDER);
940 #endif
941     if (folder<0) {
942 	winc = BUTTONWIDTH/ANIM_STEP_MAIN;
943 	hinc = BUTTONHEIGHT/ANIM_STEP_MAIN;
944     } else {
945 	winc = BUTTONWIDTH/ANIM_STEP;
946 	hinc = BUTTONHEIGHT/ANIM_STEP;
947     }
948     if (folder < 0)  {
949 	win = main_win;
950 	direction = AnimationDir;
951 	if (direction==DIR_TOUP || direction==DIR_TODOWN)
952 	  fsize=BUTTONHEIGHT;
953 	else
954 	  fsize=BUTTONWIDTH;
955     } else {
956 	direction = Folders[folder].direction;
957 	win = Folders[folder].win;
958 	if (direction==DIR_TOUP || direction==DIR_TODOWN)
959 	  fsize=hinc;
960 	else
961 	  fsize=winc;
962     }
963     if (AnimationStyle==0) {
964 	goto end;
965     }
966     XGetGeometry(dpy,win,&junk_win,&x,&y,&w,&h,&junk_bd,&junk_depth);
967     XTranslateCoordinates(dpy,win,Root,x,y,&x,&y,&junk_win);
968     switch (direction) {
969      case DIR_TOLEFT:
970 	cx = x;
971 	for(cw=w;cw >= fsize; cw-=winc) {
972 	    XMoveResizeWindow(dpy,win,cx,y, cw,h);
973 	    XSync(dpy,0);
974 	    sleep_a_little(ANIM_DELAY);
975 	    cx += winc;
976 	}
977 	break;
978      case DIR_TORIGHT:
979 	for(cw=w;cw >= fsize; cw-=winc) {
980 	    XMoveResizeWindow(dpy,win,x,y, cw,h);
981 	    XSync(dpy,0);
982 	    sleep_a_little(ANIM_DELAY);
983 	}
984 	break;
985      case DIR_TOUP:
986 	cy = y;
987 	for(ch=h;ch >= fsize; ch-=hinc) {
988 	    XMoveResizeWindow(dpy,win,x,cy, w,ch);
989 	    XSync(dpy,0);
990 	    sleep_a_little(ANIM_DELAY);
991 	    cy += hinc;
992 	}
993 	break;
994      case DIR_TODOWN:
995 	for(ch=h;ch >= fsize; ch-=hinc) {
996 	    XMoveResizeWindow(dpy,win,x,y, w, ch);
997 	    XSync(dpy,0);
998 	    sleep_a_little(ANIM_DELAY);
999 	}
1000 	break;
1001      default:
1002 	XBell(dpy,100);
1003 	fprintf(stderr,"WHARF INTERNAL BUG in CloseFolder()\n");
1004 	exit(-1);
1005     }
1006     Folders[folder].direction = 0;
1007  end:
1008     if (folder<0) {
1009 	XResizeWindow(dpy,win,BUTTONWIDTH,BUTTONHEIGHT);
1010     } else {
1011 	XUnmapWindow(dpy,win);
1012     }
1013 }
1014 
1015 
MapFolder(int folder,int * LastMapped,int base_x,int base_y,int row,int col)1016 void MapFolder(int folder, int *LastMapped, int base_x, int base_y, int row, int col)
1017 {
1018     int dir;
1019 
1020   if (Folders[folder].mapped ==ISMAPPED)
1021     {
1022       CloseFolder(folder);
1023       Folders[folder].mapped = NOTMAPPED;
1024       *LastMapped = -1;
1025     }
1026   else
1027     {
1028       int folderx, foldery, folderw, folderh;
1029       if (*LastMapped != -1)
1030 	{
1031 	  CloseFolder(*LastMapped);
1032 	  Folders[*LastMapped].mapped = NOTMAPPED;
1033 	  *LastMapped = -1;
1034 	}
1035       Folders[folder].mapped = ISMAPPED;
1036       if(num_columns < num_rows)
1037 	{
1038 	  if((base_x % display_width) > display_width / 2 ) {
1039 	      folderx = base_x+(col-Folders[folder].count)*BUTTONWIDTH-2;
1040 	      dir = DIR_TOLEFT;
1041 	  }
1042 	  else {
1043 	      folderx = base_x+(col+1)*BUTTONHEIGHT+1;
1044 	      dir = DIR_TORIGHT;
1045 	  }
1046 	  foldery = base_y+row*BUTTONHEIGHT;
1047 	  folderw = Folders[folder].count*BUTTONWIDTH;
1048 	  folderh = BUTTONHEIGHT;
1049 	}
1050 /* more kludgery */
1051       else if (num_columns == num_rows)
1052         {
1053 /*
1054 	  if((base_x % display_width) > display_width / 2 )
1055 	    folderx = (col-Folders[folder].count)*BUTTONHEIGHT-2;
1056 	  else
1057 	    folderx = (col+1)*BUTTONHEIGHT+1;
1058 */
1059           if (ROWS)
1060           {
1061             if ((base_y % display_height) > display_height / 2) {
1062 		foldery = base_y-(Folders[folder].count)*BUTTONHEIGHT-2;
1063 		dir = DIR_TOUP;
1064 	    }
1065             else {
1066 		foldery = base_y+BUTTONHEIGHT+2;
1067 		dir = DIR_TODOWN;
1068 	    }
1069             folderx = base_x;
1070 	    folderw = BUTTONWIDTH;
1071 	    folderh = (Folders[folder].count)*BUTTONHEIGHT;
1072           }
1073           else
1074           {
1075 	    if((base_x % display_width) > display_width / 2 ) {
1076 		folderx = base_x-(Folders[folder].count)*BUTTONWIDTH-2;
1077 		dir = DIR_TOLEFT;
1078 	    }
1079             else {
1080 		folderx = base_x+BUTTONWIDTH+1;
1081 		dir = DIR_TORIGHT;
1082 	    }
1083             foldery = base_y-1;
1084 	    folderh = BUTTONHEIGHT;
1085 	    folderw = (Folders[folder].count)*BUTTONWIDTH;
1086           }
1087         }
1088       else
1089 	{
1090 	  if ((base_y % display_height) < display_height / 2) {
1091 	    foldery  =base_y+(row+1)*BUTTONHEIGHT;
1092 	    dir = DIR_TODOWN;
1093 	  }
1094 	  else {
1095 	    foldery = base_y+(row-Folders[folder].count)*BUTTONHEIGHT;
1096 	    dir = DIR_TOUP;
1097 	  }
1098 	  folderx = base_x+col*BUTTONWIDTH;
1099 	  folderw = BUTTONWIDTH;
1100 	  folderh = (Folders[folder].count)*BUTTONHEIGHT;
1101        	}
1102 
1103 #ifdef ENABLE_SOUND
1104 	PlaySound(WHEV_OPEN_FOLDER);
1105 #endif
1106 	XMoveWindow(dpy, Folders[folder].win, folderx, foldery);
1107 	OpenFolder(folder,folderx, foldery, folderw, folderh, dir);
1108 	*LastMapped = folder;
1109     }
1110 }
1111 
1112 void
DrawOutline(Drawable d,int w,int h)1113 DrawOutline(Drawable d, int w, int h)
1114 {
1115     if (NoBorder)
1116       return;
1117 /* top */
1118     XDrawLine( dpy, d, HiInnerGC, 0, 0, w-1, 0);
1119     /*
1120     XDrawLine( dpy, d, HiInnerGC, 0, 1, w-1, 1);
1121 */
1122 /* bottom */
1123     XFillRectangle(dpy, d, NormalGC, 0,h-2,w-1,h-1);
1124 
1125 /* left */
1126     XDrawLine( dpy, d, HiInnerGC, 0, 1, 0, h-1);
1127     /*
1128     XDrawLine( dpy, d, HiInnerGC, 1, 2, 1, h-2);
1129      */
1130 /* right */
1131     XDrawLine( dpy, d, NormalGC, w-1, 1, w-1, h-1);
1132     XDrawLine( dpy, d, NormalGC, w-2, 2, w-2, h-2);
1133 }
1134 
RedrawUnpushed(Window * win,int i,int j)1135 void RedrawUnpushed(Window *win, int i, int j)
1136 {
1137     if (PushStyle!=0) {
1138 	XMoveResizeWindow(dpy, Buttons[CurrentButton].IconWin,
1139 			  (j-1)*BUTTONWIDTH ,(i-1)*BUTTONHEIGHT,
1140 			  BUTTONWIDTH, BUTTONHEIGHT);
1141     } else {
1142 	XCopyArea( dpy, Buttons[CurrentButton].completeIcon,
1143 		  Buttons[CurrentButton].IconWin, NormalGC, 0, 0,
1144 		  Buttons[BACK_BUTTON].icons[0].w,
1145 		  Buttons[BACK_BUTTON].icons[0].h,
1146 		  0,0);
1147     }
1148     RedrawWindow(win,0, CurrentButton, num_rows, num_columns);
1149 
1150     RedrawUnpushedOutline(win, i, j);
1151 }
1152 
RedrawUnpushedOutline(Window * win,int i,int j)1153 void RedrawUnpushedOutline(Window *win, int i, int j)
1154 {
1155 /* top */
1156     if (NoBorder) {
1157       return;
1158     }
1159 
1160     XDrawLine( dpy, *win, HiInnerGC,
1161 	      j*BUTTONWIDTH-BUTTONWIDTH, i*BUTTONHEIGHT-BUTTONHEIGHT,
1162 	      j*BUTTONWIDTH,i*BUTTONHEIGHT-BUTTONHEIGHT);
1163 /*
1164     XDrawLine( dpy, *win, HiInnerGC, j*BUTTONWIDTH-BUTTONWIDTH,
1165 	      i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH,
1166 	      i*BUTTONHEIGHT-BUTTONHEIGHT+1);
1167  */
1168     /* left */
1169     XDrawLine( dpy, *win, HiInnerGC, j*BUTTONWIDTH-BUTTONWIDTH,
1170 	      i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH-BUTTONWIDTH,
1171 	      i*BUTTONHEIGHT-1);
1172    /*
1173     XDrawLine( dpy, *win, HiInnerGC, j*BUTTONWIDTH
1174 	      -BUTTONWIDTH+1, i*BUTTONHEIGHT-BUTTONHEIGHT+2,
1175 	      j*BUTTONWIDTH-BUTTONWIDTH+1 ,i*BUTTONHEIGHT-1);
1176     */
1177     /* right */
1178     XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH
1179 	      +BUTTONWIDTH-2, i*BUTTONHEIGHT-BUTTONHEIGHT+2, j*BUTTONWIDTH
1180 	      -BUTTONWIDTH+BUTTONWIDTH-2 ,i*BUTTONHEIGHT-1);
1181 
1182     XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH
1183 	      +BUTTONWIDTH-1, i*BUTTONHEIGHT-BUTTONHEIGHT+1,
1184 	      j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-1 ,i*BUTTONHEIGHT-1);
1185 
1186     /* bottom */
1187     XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH
1188 	      -BUTTONWIDTH+1, i*BUTTONHEIGHT-1, j*BUTTONWIDTH-BUTTONWIDTH
1189 	      +BUTTONWIDTH-2,i*BUTTONHEIGHT-1);
1190 
1191     XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH
1192 	      +1, i*BUTTONHEIGHT-2, j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-2,
1193 	      i*BUTTONHEIGHT-2);
1194 }
1195 
RedrawPushed(Window * win,int i,int j)1196 void RedrawPushed(Window *win, int i,int j)
1197 {
1198     if (PushStyle!=0) {
1199 	XMoveResizeWindow(dpy, Buttons[CurrentButton].IconWin,
1200 			  2+(j-1)*BUTTONWIDTH,(i-1)*BUTTONHEIGHT+2,
1201 			  BUTTONWIDTH-2, BUTTONHEIGHT-2);
1202     } else {
1203 	XCopyArea( dpy, Buttons[CurrentButton].completeIcon,
1204 		  Buttons[CurrentButton].IconWin, NormalGC, 2, 2,
1205 		  Buttons[BACK_BUTTON].icons[0].w-2,
1206 		  Buttons[BACK_BUTTON].icons[0].h-2, 4, 4);
1207 	XCopyArea( dpy, Buttons[BACK_BUTTON].icons[0].icon,
1208 		  Buttons[CurrentButton].IconWin, NormalGC, 2, 2,
1209 		  2, BUTTONHEIGHT, 2, 2);
1210 	XCopyArea( dpy, Buttons[BACK_BUTTON].icons[0].icon,
1211 		  Buttons[CurrentButton].IconWin, NormalGC, 2, 2,
1212 		  BUTTONWIDTH, 2, 2, 2);
1213     }
1214     RedrawWindow(win,0, CurrentButton, num_rows, num_columns);
1215     RedrawPushedOutline(win, i,j);
1216 }
1217 
RedrawPushedOutline(Window * win,int i,int j)1218 void RedrawPushedOutline(Window *win, int i, int j)
1219 {
1220     GC gc1;
1221     /* Top Hilite */
1222     XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH,
1223 	      i*BUTTONHEIGHT-BUTTONHEIGHT, j*BUTTONWIDTH,i*BUTTONHEIGHT
1224 	      -BUTTONHEIGHT);
1225 /*
1226     XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH,
1227 	      i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH,i*BUTTONHEIGHT
1228 	      -BUTTONHEIGHT+1);
1229  */
1230     /* Left Hilite */
1231 
1232     XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH,
1233 	      i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH-BUTTONWIDTH,
1234 	      i*BUTTONHEIGHT-1);
1235    /*
1236     XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH
1237 	      +1, i*BUTTONHEIGHT-BUTTONHEIGHT+2, j*BUTTONWIDTH-BUTTONWIDTH+1,
1238 	      i*BUTTONHEIGHT-1);
1239     */
1240     if (PushStyle!=0) {
1241 	gc1 = HiReliefGC;
1242     } else {
1243 	gc1 = HiInnerGC;
1244     }
1245 
1246     /* Right Hilite */
1247 
1248     XDrawLine( dpy, *win, HiReliefGC, j*BUTTONWIDTH
1249 	      -BUTTONWIDTH+BUTTONWIDTH-2, i*BUTTONHEIGHT-BUTTONHEIGHT+2,
1250 	      j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-2 ,i*BUTTONHEIGHT-1);
1251 
1252     XDrawLine( dpy, *win, gc1, j*BUTTONWIDTH
1253 	      -BUTTONWIDTH+BUTTONWIDTH-1, i*BUTTONHEIGHT-BUTTONHEIGHT+1,
1254 	      j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-1 ,i*BUTTONHEIGHT-1);
1255 
1256     /* Bottom Hilite */
1257     XDrawLine( dpy, *win, gc1, j*BUTTONWIDTH
1258 	      -BUTTONWIDTH+1, i*BUTTONHEIGHT-1, j*BUTTONWIDTH-BUTTONWIDTH
1259 	      +BUTTONWIDTH-2,i*BUTTONHEIGHT-1);
1260 
1261     XDrawLine( dpy, *win, HiReliefGC, j*BUTTONWIDTH
1262 	      -BUTTONWIDTH+1, i*BUTTONHEIGHT-2, j*BUTTONWIDTH-BUTTONWIDTH
1263 	      +BUTTONWIDTH-2,i*BUTTONHEIGHT-2);
1264 }
1265 /************************************************************************
1266  *
1267  * Draw the window
1268  *
1269  ***********************************************************************/
RedrawWindow(Window * win,int firstbutton,int newbutton,int num_rows,int num_columns)1270 void RedrawWindow(Window *win, int firstbutton, int newbutton,
1271 		  int num_rows, int num_columns)
1272 {
1273   int i,j,button;
1274   XEvent dummy;
1275 
1276   if(ready < 1)
1277     return;
1278 
1279   while (XCheckTypedWindowEvent (dpy, *win, Expose, &dummy));
1280 
1281   for(i=0;i<num_rows;i++)
1282     for(j=0;j<num_columns; j++)
1283       {
1284 	button = firstbutton+i*num_columns + j;
1285 	if((newbutton == -1)||(newbutton == button))
1286 	  {
1287 	      if(((Buttons[button].swallow == 3)||
1288 	          (Buttons[button].swallow == 4))&&
1289 		  (Buttons[button].IconWin != None))
1290 		XSetWindowBorderWidth(dpy,Buttons[button].IconWin,0);
1291 	  }
1292 	  RedrawUnpushedOutline(win,i,j);
1293       }
1294 }
1295 
1296 
1297 /*******************************************************************
1298  *
1299  * Create GC's
1300  *
1301  ******************************************************************/
CreateShadowGC(void)1302 void CreateShadowGC(void)
1303 {
1304   XGCValues gcv;
1305   unsigned long gcm;
1306 
1307     if(d_depth < 2)
1308     {
1309       back_pix = GetColor("white");
1310       fore_pix = GetColor("black");
1311     }
1312   else
1313     {
1314       if (TextureType>0 && TextureType < 128) {
1315 	  MakeShadowColors(dpy, FromColor, ToColor, &fore_pix, &light_grey);
1316       } else {
1317 	  back_pix = GetColor("grey40");
1318 	  fore_pix = GetColor("grey17");
1319 	  light_grey = GetColor("white");
1320       }
1321     }
1322   gcm = GCForeground|GCBackground|GCSubwindowMode;
1323   gcv.subwindow_mode = IncludeInferiors;
1324 
1325   gcv.foreground = fore_pix;
1326   gcv.background = back_pix;
1327   NormalGC = XCreateGC(dpy, Root, gcm, &gcv);
1328 
1329   gcv.foreground = back_pix;
1330   gcv.background = fore_pix;
1331   HiReliefGC = XCreateGC(dpy, Root, gcm, &gcv);
1332 
1333   gcv.foreground = light_grey;
1334   gcv.background = fore_pix;
1335   HiInnerGC = XCreateGC(dpy, Root, gcm, &gcv);
1336 
1337   gcm = GCForeground;
1338   gcv.foreground = fore_pix;
1339   MaskGC = XCreateGC(dpy, Root, gcm, &gcv);
1340 
1341   DefGC = DefaultGC(dpy, screen);
1342 }
1343 
1344 /************************************************************************
1345  *
1346  * Sizes and creates the window
1347  *
1348  ***********************************************************************/
CreateWindow(void)1349 void CreateWindow(void)
1350 {
1351   int first_avail_button,i;
1352 
1353   wm_del_win = XInternAtom(dpy,"WM_DELETE_WINDOW",False);
1354   _XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False);
1355 
1356   /* Allow for multi-width/height buttons */
1357   first_avail_button = num_buttons;
1358 
1359   if(num_buttons > MAX_BUTTONS)
1360     {
1361       fprintf(stderr,"%s: Out of Buttons!\n",MyName);
1362       exit(0);
1363     }
1364 
1365   /* size and create the window */
1366   if((num_rows == 0)&&(num_columns == 0))
1367     num_columns = 1;
1368   if(num_columns == 0)
1369     {
1370       num_columns = num_buttons/num_rows;
1371       while(num_rows * num_columns < num_buttons)
1372 	num_columns++;
1373     }
1374   if(num_rows == 0)
1375     {
1376       num_rows = num_buttons/num_columns;
1377       while(num_rows * num_columns < num_buttons)
1378 	num_rows++;
1379     }
1380 
1381   while(num_rows * num_columns < num_buttons)
1382     num_columns++;
1383 
1384   mysizehints.flags = PWinGravity| PResizeInc | PBaseSize;
1385   /* subtract one for the right/bottom border */
1386   mysizehints.width = BUTTONWIDTH*num_columns;
1387   mysizehints.height= BUTTONHEIGHT*num_rows;
1388   mysizehints.width_inc = num_columns;
1389   mysizehints.height_inc = num_rows;
1390   mysizehints.base_height = num_rows - 1;
1391   mysizehints.base_width = num_columns - 1;
1392 
1393   if(x > -100000)
1394     {
1395       if (x <= -1)
1396 	{
1397           mysizehints.x = DisplayWidth(dpy,screen) + x - mysizehints.width-1;
1398 	  gravity = NorthEastGravity;
1399 	}
1400       else if ((x == 0) && (flags & 16))
1401         mysizehints.x = DisplayWidth(dpy,screen) - mysizehints.width-2;
1402       else
1403 	mysizehints.x = x;
1404       if ( y<0)
1405 	{
1406 	  mysizehints.y = DisplayHeight(dpy,screen) + y - mysizehints.height-2;
1407 	  gravity = SouthWestGravity;
1408 	}
1409       else
1410 	mysizehints.y = y;
1411 
1412       if((x < 0) && (y < 0))
1413 	gravity = SouthEastGravity;
1414       mysizehints.flags |= USPosition;
1415     }
1416 
1417   mysizehints.win_gravity = gravity;
1418 
1419   main_win = XCreateSimpleWindow(dpy,Root,mysizehints.x,mysizehints.y,
1420 				 mysizehints.width,mysizehints.height,
1421 				 0,0,back_pix);
1422 
1423   for(i=0;i<num_folders;i++)
1424     {
1425       if(num_columns <num_rows)
1426 	{
1427 	  Folders[i].cols = 1;
1428 	  Folders[i].rows = Folders[i].count;
1429 	}
1430       else if ((num_columns == num_rows) && (!ROWS))
1431       {
1432 	  Folders[i].cols = 1;
1433 	  Folders[i].rows = Folders[i].count;
1434       }
1435       else
1436 	{
1437 	  Folders[i].cols = Folders[i].count;
1438 	  Folders[i].rows = 1;
1439 	}
1440       Folders[i].win = XCreateSimpleWindow(dpy, Root, 0,0,
1441 					   BUTTONWIDTH*Folders[i].rows,BUTTONHEIGHT*Folders[i].cols,
1442 					   0,0,back_pix);
1443       XSetWMNormalHints(dpy,Folders[i].win,&mysizehints);
1444       XSelectInput(dpy, Folders[i].win, MW_EVENTS);
1445      }
1446 
1447   XSetWMProtocols(dpy,main_win,&wm_del_win,1);
1448 
1449   XSetWMNormalHints(dpy,main_win,&mysizehints);
1450 
1451   XSelectInput(dpy, main_win, MW_EVENTS);
1452   change_window_name(MyName);
1453 }
1454 
1455 
nocolor(char * a,char * b)1456 void nocolor(char *a, char *b)
1457 {
1458  fprintf(stderr,"%s: can't %s %s\n", MyName, a,b);
1459 }
1460 
1461 /****************************************************************************
1462  *
1463  * Loads a single color
1464  *
1465  ****************************************************************************/
GetColor(char * name)1466 Pixel GetColor(char *name)
1467 {
1468   XColor color;
1469   XWindowAttributes attributes;
1470 
1471   XGetWindowAttributes(dpy,Root,&attributes);
1472   color.pixel = 0;
1473    if (!XParseColor (dpy, attributes.colormap, name, &color))
1474      {
1475        nocolor("parse",name);
1476      }
1477    else if(!XAllocColor (dpy, attributes.colormap, &color))
1478      {
1479        nocolor("alloc",name);
1480      }
1481   return color.pixel;
1482 }
1483 
1484 /************************************************************************
1485  *
1486  * Dead pipe handler
1487  *
1488  ***********************************************************************/
DeadPipe(int nonsense)1489 void DeadPipe(int nonsense)
1490 {
1491   int i,j,button;
1492 
1493 #ifdef ENABLE_SOUND
1494     int val=-1;
1495     write(PlayerChannel[1],&val,sizeof(val));
1496     if (SoundThread != 0)
1497       kill(SoundThread,SIGUSR1);
1498 #endif
1499   for(i=0;i<num_rows;i++)
1500     for(j=0;j<num_columns; j++)
1501       {
1502 	button = i*num_columns + j;
1503         /* delete swallowed windows, but not modules (afterstep handles those) */
1504 	if(((Buttons[button].swallow == 3)||(Buttons[button].swallow == 4))&&
1505 	    (Buttons[button].module == 0))
1506 	  {
1507 	    send_clientmessage(Buttons[button].IconWin,wm_del_win,CurrentTime);
1508 	    XSync(dpy,0);
1509 	  }
1510       }
1511   XSync(dpy,0);
1512   exit(0);
1513 }
1514 
1515 int TOTHEFOLDER = -1;
1516 /*****************************************************************************
1517  *
1518  * This routine is responsible for reading and parsing the config file
1519  *
1520  ****************************************************************************/
ParseOptions(char * filename)1521 void ParseOptions(char *filename)
1522 {
1523   FILE *fd = (FILE *)0;
1524   char line[256];
1525   char *tline,*orig_tline,*tmp;
1526   int Clength, len;
1527 
1528   fd = fopen(filename,"r");
1529   if(fd == (FILE *)0)
1530     {
1531       fprintf(stderr,"%s: can't open config file %s",MyName,filename);
1532       exit(1);
1533     }
1534 
1535   tline = fgets(line,(sizeof line)-1,fd);
1536   orig_tline = tline;
1537   Clength = strlen(MyName);
1538   while(tline != (char *)0)
1539     {
1540       int g_x, g_y;
1541       unsigned width,height;
1542 
1543       while(isspace(*tline))tline++;
1544 
1545       if((strlen(&tline[0])>1)&&
1546 	 (mystrncasecmp(tline,CatString3("*", MyName, "Geometry"),Clength+9)==0))
1547 	{
1548 	  tmp = &tline[Clength+9];
1549 	  while(((isspace(*tmp))&&(*tmp != '\n'))&&(*tmp != 0))
1550 	    {
1551 	      tmp++;
1552 	    }
1553 	  tmp[strlen(tmp)-1] = 0;
1554 
1555 	  flags = XParseGeometry(tmp,&g_x,&g_y,&width,&height);
1556 	  if (flags & WidthValue)
1557 	    w = width;
1558 	  if (flags & HeightValue)
1559 	    h = height;
1560 	  if (flags & XValue)
1561 	    x = g_x;
1562 	  if (flags & YValue)
1563 	    y = g_y;
1564 	}
1565       else if((strlen(&tline[0])>1)&&
1566 	      (mystrncasecmp(tline,CatString3("*",MyName,"Rows"),Clength+5)==0))
1567 	{
1568 	  len=sscanf(&tline[Clength+5],"%d",&num_rows);
1569 	  if(len < 1)
1570 	    num_rows = 0;
1571             ROWS = TRUE;
1572 	}
1573       else if((strlen(&tline[0])>1)&&
1574 	      (mystrncasecmp(tline,CatString3("*",MyName,"Columns"),Clength+8)==0))
1575 	{
1576 	  len=sscanf(&tline[Clength+8],"%d",&num_columns);
1577 	  if(len < 1)
1578 	    num_columns = 0;
1579             ROWS = FALSE;
1580 	}
1581       else if((strlen(&tline[0])>1)&&
1582               (mystrncasecmp(tline,CatString3("*",MyName,"NoPush"),Clength+5)==0))
1583         {
1584 	  Pushable = 0;
1585         } else if((strlen(&tline[0])>1)&&
1586               (mystrncasecmp(tline,CatString3("*",MyName,"FullPush"),Clength+9)==0))
1587         {
1588 	  PushStyle = 1;
1589         } else if((strlen(&tline[0])>1)&&
1590               (mystrncasecmp(tline,CatString3("*",MyName,"NoBorder"),Clength+9)==0))
1591         {
1592 	  NoBorder = 1;
1593         } else if ((strlen(&tline[0])>1)
1594 	  &&(mystrncasecmp(tline,CatString3("*",MyName,"ForceSize"),Clength+10)==0)) {
1595 	    ForceSize = 1;
1596         } else if ((strlen(&tline[0])>1)
1597 	  &&(mystrncasecmp(tline,CatString3("*",MyName,"TextureType"),Clength+12)==0)) {
1598 	    if (sscanf(&tline[Clength+12],"%d",&TextureType)<1)
1599 	      TextureType = TEXTURE_BUILTIN;
1600 	} else if ((strlen(&tline[0])>1)
1601 	  &&(mystrncasecmp(tline,CatString3("*",MyName,"MaxColors"),Clength+10)==0)) {
1602 
1603 	    if (sscanf(&tline[Clength+10],"%d",&MaxColors)<1)
1604 	      MaxColors = 16;
1605 	} else if ((strlen(&tline[0])>1)
1606 	  &&(mystrncasecmp(tline,CatString3("*",MyName,"BgColor"),Clength+8)==0)) {
1607 	    char *tmp;
1608 	    tmp=safemalloc(strlen(tline));
1609 	    sscanf(&tline[Clength+8],"%s",tmp);
1610 	    BgColor=GetColor(tmp);
1611 	    free(tmp);
1612 	} else if ((strlen(&tline[0])>1)
1613 	  &&(mystrncasecmp(tline,CatString3("*",MyName,"TextureColor"),Clength+13)==0)) {
1614 	    char *c1, *c2;
1615 	    XColor color;
1616 	    XWindowAttributes attributes;
1617 
1618 	    XGetWindowAttributes(dpy,Root,&attributes);
1619 	    len = strlen(&tline[Clength+13]);
1620 	    c1 = safemalloc(len);
1621 	    c2 = safemalloc(len);
1622 	    if (sscanf(&tline[Clength+13],"%s %s",c1,c2)!=2) {
1623 		fprintf(stderr,"%s:You must specify two colors for the texture\n",MyName);
1624 		FromColor[0]=0;
1625 		FromColor[1]=0;
1626 		FromColor[2]=0;
1627 		ToColor[0]=0;
1628 		ToColor[1]=0;
1629 		ToColor[2]=0;
1630 	    }
1631 	    if (!XParseColor (dpy, attributes.colormap, c1, &color))
1632 	    {
1633 		nocolor("parse",c1);
1634 		TextureType=TEXTURE_BUILTIN;
1635 	    } else {
1636 		FromColor[0]=color.red;
1637 		FromColor[1]=color.green;
1638 		FromColor[2]=color.blue;
1639 	    }
1640 	    if (!XParseColor (dpy, attributes.colormap, c2, &color))
1641 	    {
1642 		nocolor("parse",c2);
1643 		TextureType=TEXTURE_BUILTIN;
1644 	    } else {
1645 		ToColor[0]=color.red;
1646 		ToColor[1]=color.green;
1647 		ToColor[2]=color.blue;
1648 	    }
1649 	    free(c1);
1650 	    free(c2);
1651 	} else if ((strlen(&tline[0])>1)
1652 	  &&(mystrncasecmp(tline,CatString3("*",MyName,"Pixmap"),Clength+7)==0)) {
1653 	    CopyString(&BgPixmapFile,&tline[Clength+7]);
1654 	} else if((strlen(&tline[0])>1)&&
1655 		  (mystrncasecmp(tline,CatString3("*",MyName,"AnimateMain"),Clength+12)==0))
1656         {
1657 	    AnimateMain = 1;
1658         }
1659 	else if((strlen(&tline[0])>1)&&
1660 		(mystrncasecmp(tline,CatString3("*",MyName,"Animate"),Clength+8)==0))
1661         {
1662 	    if ((tline[Clength+9]!='M') && (tline[Clength+9]!='m'))
1663 	      AnimationStyle = 1;
1664         }
1665 #ifdef ENABLE_SOUND
1666 	else if((strlen(&tline[0])>1)&&
1667 		(mystrncasecmp(tline,CatString3("*",MyName,"Player"),Clength+7)==0))
1668         {
1669 	    CopyString(&SoundPlayer, &tline[Clength+7]);
1670         } else if((strlen(&tline[0])>1)&&
1671 		(mystrncasecmp(tline,CatString3("*",MyName,"Sound"),Clength+6)==0))
1672         {
1673 	    bind_sound(&tline[Clength+6]);
1674 	    SoundActive = 1;
1675         }
1676 #endif
1677 	 else if((strlen(&tline[0])>1)
1678 		  &&(mystrncasecmp(tline,CatString3("*", MyName, ""),Clength+1)==0)
1679 		  && (num_buttons < MAX_BUTTONS))
1680 	{
1681 	    /* check if this is a invalid option */
1682 	    if (!isspace(tline[Clength+1]))
1683 	      fprintf(stderr,"%s:invalid option %s\n",MyName,tline);
1684 	    else
1685 	      match_string(&tline[Clength+1]);
1686 	}
1687       else if((strlen(&tline[0])>1)&&(mystrncasecmp(tline,"IconPath",8)==0))
1688 	{
1689 	  CopyString(&iconPath,&tline[8]);
1690 	}
1691       else if((strlen(&tline[0])>1)&&(mystrncasecmp(tline,"PixmapPath",10)==0))
1692 	{
1693 	  CopyString(&pixmapPath,&tline[10]);
1694 	}
1695 #ifdef ENABLE_SOUND
1696       else if((strlen(&tline[0])>1)&&(mystrncasecmp(tline,"*AudioDir",9)==0))
1697 	{
1698 	  CopyString(&SoundPath,&tline[9]);
1699 	}
1700       else if((strlen(&tline[0])>1)&&(mystrncasecmp(tline,"ModulePath",11)==0))
1701 	{
1702 	  CopyString(&ModulePath,&tline[11]);
1703 	}
1704 #endif
1705       tline = fgets(line,(sizeof line)-1,fd);
1706       orig_tline = tline;
1707     }
1708 #ifdef ENABLE_DND
1709     /* ignore last button if there's nothing bound to it */
1710     if ((Buttons[num_buttons-1].drop_action!=NULL) &&
1711 	(Buttons[num_buttons-1].iconno==0)) {
1712 	num_buttons--;
1713     }
1714 #endif
1715   return;
1716 }
1717 
1718 /*
1719  * Gets a word of a given index in the line, stripping any blanks
1720  * The returned word is newly allocated
1721  */
1722 #ifdef ENABLE_SOUND
get_token(char * tline,int index)1723 char *get_token(char *tline, int index)
1724 {
1725     char *start, *end;
1726     int i,c,size;
1727     char *word;
1728 
1729     index++; /* index is 0 based */
1730     size = strlen(tline);
1731     i=c=0;
1732     start=end=tline;
1733     while (i<index && c<size) {
1734 	start=end;
1735 	while(isspace(*start) && c<size) {
1736 	    start++;
1737 	    c++;
1738 	}
1739 	end=start;
1740 	while(!isspace(*end) && c<size) {
1741 	    end++;
1742 	    c++;
1743 	}
1744 	if (end==start) return NULL;
1745 	i++;
1746     }
1747     if (i<index) return NULL;
1748     word=safemalloc(end-start+1);
1749     strncpy(word, start, end-start);
1750     word[end-start]=0;
1751     return word;
1752 }
1753 
1754 /**************************************************************************
1755  *
1756  * Parses a sound binding
1757  *
1758  **************************************************************************/
bind_sound(char * tline)1759 void bind_sound(char *tline)
1760 {
1761     char *event, *sound;
1762 
1763     event = get_token(tline,0);
1764     if (event==NULL) {
1765 	fprintf(stderr,"%s:bad sound binding %s\n",MyName,tline);
1766 	return;
1767     }
1768     sound = get_token(tline,1);
1769     if (sound==NULL) {
1770 	free(event);
1771 	fprintf(stderr,"%s:bad sound binding %s\n",MyName,tline);
1772 	return;
1773     }
1774     if (strcmp(event,"open_folder")==0) {
1775 	Sounds[WHEV_OPEN_FOLDER]=sound;
1776     } else if (strcmp(event,"close_folder")==0) {
1777 	Sounds[WHEV_CLOSE_FOLDER]=sound;
1778     } else if (strcmp(event,"open_main")==0) {
1779 	Sounds[WHEV_OPEN_MAIN]=sound;
1780     } else if (strcmp(event,"close_main")==0) {
1781 	Sounds[WHEV_CLOSE_MAIN]=sound;
1782     } else if (strcmp(event,"push")==0) {
1783 	Sounds[WHEV_PUSH]=sound;
1784     } else if (strcmp(event,"drop")==0) {
1785 	Sounds[WHEV_DROP]=sound;
1786     } else {
1787 	fprintf(stderr,"%s:bad event %s in sound binding\n",MyName,event);
1788 	free(sound);
1789     }
1790     free(event);
1791     return;
1792 }
1793 #endif /* ENABLE_SOUND */
1794 
1795 /**************************************************************************
1796  *
1797  * Parses a button command line from the config file
1798  *
1799  *************************************************************************/
match_string(char * tline)1800 void match_string(char *tline)
1801 {
1802   int len,i,i2,n,j,k;
1803   char *ptr,*start,*end,*tmp;
1804   struct button_info *actual;
1805 
1806   /* skip spaces */
1807   while(isspace(*tline)&&(*tline != '\n')&&(*tline != 0))
1808     tline++;
1809 
1810   /* read next word. Its the button label. Users can specify ""
1811    * NoIcon, or whatever to skip the label */
1812   /* read to next space */
1813   start = tline;
1814   end = tline;
1815   while((!isspace(*end))&&(*end!='\n')&&(*end!=0))
1816     end++;
1817   len = end - start;
1818   ptr = safemalloc(len+1);
1819   strncpy(ptr,start,len);
1820   ptr[len] = 0;
1821 
1822   if (strncmp(ptr,"~Folder",7)==0)
1823     {
1824       TOTHEFOLDER = -1;
1825       Folders[num_folders].firstbutton = num_folderbuttons;
1826       num_folders++;
1827       free(ptr);
1828       return;
1829     }
1830 
1831   if(TOTHEFOLDER==-1)
1832     {
1833       actual = &Buttons[num_buttons++];
1834       actual->parent = &main_win;
1835     }
1836   else
1837     {
1838       actual = &Buttons[--num_folderbuttons];
1839       actual->folder = num_folders;
1840       actual->parent = &Folders[num_folders].win;
1841     };
1842 
1843   actual->title = ptr;
1844 
1845   /* read next word. Its the icon bitmap/pixmap label. Users can specify ""
1846    * NoIcon, or whatever to skip the label */
1847   /* read to next space */
1848   start = end;
1849   /* skip spaces */
1850   while(isspace(*start)&&(*start != '\n')&&(*start != 0))
1851     start++;
1852   end = start;
1853   while((!isspace(*end))&&(*end!='\n')&&(*end!=0))
1854     end++;
1855   len = end - start;
1856   ptr = safemalloc(len+1);
1857   strncpy(ptr,start,len);
1858   ptr[len] = 0;
1859   /* separate icon files to be overlaid */
1860   i2 = len;
1861   j=k=0;
1862   for(i=0;i<MAX_OVERLAY;i++) {
1863       while (ptr[j]!=',' && j<i2) j++;
1864       actual->icons[i].file=safemalloc(j-k+1);
1865       strncpy(actual->icons[i].file,&(ptr[k]),j-k);
1866       actual->icons[i].file[j-k]=0;
1867       actual->iconno++;
1868       j++;
1869       k=j;
1870       if (j>=i2) break;
1871   }
1872   tline = end;
1873   for (i=num_buttons - 2;i>=0;i--)
1874     {
1875       if (strcmp(Buttons[i].title, actual->title) == 0)
1876         {
1877           actual = &Buttons[i];
1878           num_buttons--;
1879           for(i=0;i<actual->iconno;i++) {
1880           free(actual->icons[i].file);
1881         }
1882       break;
1883     }
1884   }
1885   /* skip spaces */
1886   while(isspace(*tline)&&(*tline != '\n')&&(*tline != 0))
1887     tline++;
1888 #ifdef ENABLE_DND
1889   if (mystrncasecmp(tline,"dropexec",8)==0) {
1890       /* get command to execute for dropped stuff */
1891 
1892       if(TOTHEFOLDER==-1) {
1893 	  num_buttons--; /* make the next parsed thing the button for this */
1894 	  free(ptr);
1895 	  for(i=0;i<actual->iconno;i++) {
1896 	      free(actual->icons[i].file);
1897 	  }
1898 	  actual->iconno=0;
1899       } else {
1900 	  num_folderbuttons++;
1901 	  free(ptr);
1902 	  for(i=0;i<actual->iconno;i++) {
1903 	      free(actual->icons[i].file);
1904 	  }
1905 	  actual->iconno=0;
1906 	  fprintf(stderr,"Drop in Folders not supported. Ignoring option\n");
1907 	  return;
1908       }
1909 
1910       tline=strstr(tline,"Exec");
1911       len = strlen(tline);
1912       tmp = tline + len -1;
1913       while(((isspace(*tmp))||(*tmp == '\n'))&&(tmp >=tline)) {
1914 	  tmp--;
1915 	  len--;
1916       }
1917       ptr = safemalloc(len+1);
1918       actual->drop_action=ptr;
1919       strncpy(ptr,tline,len);
1920       ptr[len]=0;
1921   } else
1922 #endif
1923   if(mystrncasecmp(tline,"swallow",7)==0 || mystrncasecmp(tline,"maxswallow",10)==0)
1924     {
1925       /* Look for swallow "identifier", in which
1926 	 case Wharf spawns and gobbles up window */
1927       i=7;
1928       while((tline[i] != 0)&&
1929 	    (tline[i] != '"'))
1930 	i++;
1931       i2=i+1;
1932       while((tline[i2] != 0)&&
1933 	    (tline[i2] != '"'))
1934 	i2++;
1935       actual->maxsize =
1936                  mystrncasecmp(tline,"maxswallow",10) == 0 ? 1 : 0;
1937       if(i2 - i >1)
1938 	{
1939 	  actual->hangon = safemalloc(i2-i);
1940 	  strncpy(actual->hangon,&tline[i+1],i2-i-1);
1941 	  actual->hangon[i2-i-1] = 0;
1942 	  actual->swallow = 1;
1943 	}
1944       n = 7;
1945       while((isspace(tline[n]))&&(tline[n]!=0))
1946 	n++;
1947       len = strlen(&tline[n]);
1948       tmp = tline + n + len -1;
1949       while(((isspace(*tmp))||(*tmp == '\n'))&&(tmp >=(tline + n)))
1950 	{
1951 	  tmp--;
1952 	  len--;
1953 	}
1954       ptr = safemalloc(len+6);
1955       if(mystrncasecmp(&tline[n],"Module",6)==0)
1956 	{
1957 	  ptr[0] = 0;
1958           actual->module = 1;
1959 	}
1960       else
1961 	strcpy(ptr,"Exec ");
1962       i2 = strlen(ptr);
1963       strncat(ptr,&tline[n],len);
1964       ptr[i2+len]=0;
1965       SendText(fd,ptr,0);
1966       free(ptr);
1967       actual->action = NULL;
1968     }
1969   else
1970     {
1971       if(!TOTHEFOLDER)
1972 	{
1973 	  Folders[num_folders].count++;
1974 	}
1975 
1976       len = strlen(tline);
1977       tmp = tline + len -1;
1978       while(((isspace(*tmp))||(*tmp == '\n'))&&(tmp >=tline))
1979 	{
1980 	  tmp--;
1981 	  len--;
1982 	}
1983       ptr = safemalloc(len+1);
1984       strncpy(ptr,tline,len);
1985       ptr[len]=0;
1986 
1987       if (strncmp(ptr,"Folder",6)==0)
1988 	{
1989 	  TOTHEFOLDER = 0;
1990 	  Folders[num_folders].count = 0;
1991 	  actual->folder = num_folders;
1992 	  Folders[num_folders].mapped = NOTMAPPED;
1993 	}
1994       actual->action = ptr;
1995     }
1996   return;
1997 }
1998 
1999 /**************************************************************************
2000  *  Change the window name displayed in the title bar.
2001  **************************************************************************/
change_window_name(char * str)2002 void change_window_name(char *str)
2003 {
2004   XTextProperty name;
2005   int i;
2006 
2007   if (XStringListToTextProperty(&str,1,&name) == 0)
2008     {
2009       fprintf(stderr,"%s: cannot allocate window name",MyName);
2010       return;
2011     }
2012   XSetWMName(dpy,main_win,&name);
2013   XSetWMIconName(dpy,main_win,&name);
2014   for(i=0;i<num_folders;i++)
2015     {
2016       XSetWMName(dpy, Folders[i].win,&name);
2017       XSetWMIconName(dpy, Folders[i].win,&name);
2018     }
2019   XFree(name.value);
2020 }
2021 
2022 
2023 
2024 /***************************************************************************
2025  *
2026  * Waits for next X event, or for an auto-raise timeout.
2027  *
2028  ****************************************************************************/
My_XNextEvent(Display * dpy,XEvent * event)2029 int My_XNextEvent(Display *dpy, XEvent *event)
2030 {
2031   fd_set in_fdset;
2032   unsigned long header[3];
2033   int count;
2034   static int miss_counter = 0;
2035   unsigned long *body;
2036 
2037   if(XPending(dpy))
2038     {
2039       XNextEvent(dpy,event);
2040       return 1;
2041     }
2042 
2043   FD_ZERO(&in_fdset);
2044   FD_SET(x_fd,&in_fdset);
2045   FD_SET(fd[1],&in_fdset);
2046 
2047 #ifdef __hpux
2048   select(fd_width,(int *)&in_fdset, 0, 0, NULL);
2049 #else
2050   select(fd_width,&in_fdset, 0, 0, NULL);
2051 #endif
2052 
2053 
2054   if(FD_ISSET(x_fd, &in_fdset))
2055     {
2056       if(XPending(dpy))
2057 	{
2058 	  XNextEvent(dpy,event);
2059 	  miss_counter = 0;
2060 	  return 1;
2061 	}
2062       else
2063 	miss_counter++;
2064       if(miss_counter > 100)
2065 	DeadPipe(0);
2066     }
2067 
2068   if(FD_ISSET(fd[1], &in_fdset))
2069     {
2070       if((count = ReadASPacket(fd[1], header, &body)) > 0)
2071 	{
2072 	  process_message(header[1],body);
2073 	  free(body);
2074 	}
2075     }
2076   return 0;
2077 }
2078 
CheckForHangon(unsigned long * body)2079 void CheckForHangon(unsigned long *body)
2080 {
2081   int button,i,j;
2082   char *cbody;
2083 
2084   cbody = (char *)&body[3];
2085   for(i=0;i<num_rows;i++)
2086     for(j=0;j<num_columns; j++)
2087       {
2088 	button = i*num_columns + j;
2089 	if(Buttons[button].hangon != NULL)
2090 	  {
2091 	    if(strcmp(cbody,Buttons[button].hangon)==0)
2092 	      {
2093 		if(Buttons[button].swallow == 1)
2094 		  {
2095 		    Buttons[button].swallow = 2;
2096 		    if(Buttons[button].IconWin != None)
2097 		      {
2098 			XDestroyWindow(dpy,Buttons[button].IconWin);
2099 		      }
2100 		    Buttons[button].IconWin = (Window)body[0];
2101 		    free(Buttons[button].hangon);
2102 		    Buttons[button].hangon = NULL;
2103 		  }
2104 		else
2105 		  {
2106 		    if (Buttons[button].swallow == 4)
2107 		      Buttons[button].swallow = 3;
2108 		    Buttons[button].up = 1;
2109 		    free(Buttons[button].hangon);
2110 		    Buttons[button].hangon = NULL;
2111 		    RedrawWindow(&main_win,0, button, num_rows, num_columns);
2112 		  }
2113 	      }
2114 	  }
2115       }
2116 }
2117 
2118 /**************************************************************************
2119  *
2120  * Process window list messages
2121  *
2122  *************************************************************************/
process_message(unsigned long type,unsigned long * body)2123 void process_message(unsigned long type,unsigned long *body)
2124 {
2125   switch(type)
2126     {
2127     case M_TOGGLE_PAGING:
2128       pageing_enabled = body[0];
2129       RedrawWindow(&main_win,0, -1, num_rows, num_columns);
2130       break;
2131     case M_NEW_DESK:
2132       new_desk = body[0];
2133       RedrawWindow(&main_win,0, -1, num_rows, num_columns);
2134       break;
2135     case M_END_WINDOWLIST:
2136       RedrawWindow(&main_win,0, -1, num_rows, num_columns);
2137     case M_MAP:
2138       swallow(body);
2139     case M_RES_NAME:
2140     case M_RES_CLASS:
2141     case M_WINDOW_NAME:
2142       CheckForHangon(body);
2143       break;
2144     default:
2145       break;
2146     }
2147 }
2148 
2149 
2150 
2151 
2152 
2153 /***************************************************************************
2154  *
2155  * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
2156  * client messages will have the following form:
2157  *
2158  *     event type	ClientMessage
2159  *     message type	_XA_WM_PROTOCOLS
2160  *     window		tmp->w
2161  *     format		32
2162  *     data[0]		message atom
2163  *     data[1]		time stamp
2164  *
2165  ****************************************************************************/
send_clientmessage(Window w,Atom a,Time timestamp)2166 void send_clientmessage (Window w, Atom a, Time timestamp)
2167 {
2168   XClientMessageEvent ev;
2169 
2170   ev.type = ClientMessage;
2171   ev.window = w;
2172   ev.message_type = _XA_WM_PROTOCOLS;
2173   ev.format = 32;
2174   ev.data.l[0] = a;
2175   ev.data.l[1] = timestamp;
2176   XSendEvent (dpy, w, False, 0L, (XEvent *) &ev);
2177 }
2178 
2179 
swallow(unsigned long * body)2180 void swallow(unsigned long *body)
2181 {
2182   char *temp;
2183   int button,i,j;
2184   long supplied;
2185 
2186   for(i=0;i<num_rows;i++)
2187     for(j=0;j<num_columns; j++)
2188       {
2189 	button = i*num_columns + j;
2190 	if((Buttons[button].IconWin == (Window)body[0])&&
2191 	   (Buttons[button].swallow == 2))
2192 	  {
2193 	    Buttons[button].swallow = 3;
2194 	    /* "Swallow" the window! */
2195 
2196 	    XReparentWindow(dpy,Buttons[button].IconWin, main_win,
2197 			    j*BUTTONWIDTH+4, i*BUTTONHEIGHT+4);
2198 	    XMapWindow(dpy,Buttons[button].IconWin);
2199 	    XSelectInput(dpy,(Window)body[0],
2200 			 PropertyChangeMask);
2201 	    if (Buttons[button].action)
2202 	      {
2203 		/*
2204 	        XGrabButton(dpy, Button1Mask | Button2Mask, None,
2205 		            (Window)body[0],
2206 	                    False, ButtonPressMask | ButtonReleaseMask,
2207 			    GrabModeAsync, GrabModeAsync, None, None);
2208 	        XGrabButton(dpy, Button1Mask | Button2Mask, LockMask,
2209 		*/
2210      unsigned *mods = lock_mods;
2211      do XGrabButton(dpy, Button1Mask | Button2Mask, *mods,
2212 
2213 			    (Window)body[0],
2214 	                    False, ButtonPressMask | ButtonReleaseMask,
2215 			    GrabModeAsync, GrabModeAsync, None, None);
2216      while (*mods++);
2217 
2218 	      }
2219 	    if (Buttons[button].maxsize) {
2220 	      Buttons[button].icons[0].w = 55;
2221 	      Buttons[button].icons[0].h = 57;
2222 	    }
2223 	    else {
2224 	      Buttons[button].icons[0].w = ICON_WIN_WIDTH;
2225 	      Buttons[button].icons[0].h = ICON_WIN_HEIGHT;
2226 	    }
2227 	    if (!XGetWMNormalHints (dpy, Buttons[button].IconWin,
2228 				    &Buttons[button].hints,
2229 				    &supplied))
2230 	      Buttons[button].hints.flags = 0;
2231 
2232 	    XResizeWindow(dpy,(Window)body[0], Buttons[button].icons[0].w,
2233 			  Buttons[button].icons[0].h);
2234 	    XMoveWindow(dpy,Buttons[button].IconWin,
2235 			j*BUTTONWIDTH +
2236 			(BUTTONWIDTH - Buttons[button].icons[0].w)/2,
2237 			i*BUTTONHEIGHT +
2238 			(BUTTONHEIGHT - Buttons[button].icons[0].h)/2);
2239 
2240 	    XFetchName(dpy, Buttons[button].IconWin, &temp);
2241 	    XClearArea(dpy, main_win,j*BUTTONWIDTH, i*BUTTONHEIGHT,
2242 		       BUTTONWIDTH,BUTTONHEIGHT,0);
2243 	    if(strcmp(Buttons[button].title,"-")!=0)
2244 	      CopyString(&Buttons[button].title, temp);
2245 	    RedrawWindow(&main_win,0, -1, num_rows, num_columns);
2246 	    XFree(temp);
2247 	  }
2248       }
2249 }
2250 
2251 
2252 
FindLockMods(void)2253 void FindLockMods(void)
2254 {
2255   int m, i, knl;
2256   char* kn;
2257   KeySym ks;
2258   KeyCode kc, *kp;
2259   unsigned lockmask, *mp;
2260   XModifierKeymap* mm = XGetModifierMapping(dpy);
2261   lockmask = LockMask;
2262   if (mm)
2263     {
2264       kp = mm->modifiermap;
2265       for (m = 0; m < 8; m++)
2266         {
2267           for (i = 0; i < mm->max_keypermod; i++)
2268             {
2269       	if ((kc = *kp++) &&
2270       	    ((ks = XkbKeycodeToKeysym(dpy, kc, 0, 0)) != NoSymbol))
2271       	  {
2272       	    kn = XKeysymToString(ks);
2273       	    knl = strlen(kn);
2274       	    if ((knl > 6) && (strcasecmp(kn + knl - 4, "lock") == 0))
2275       		lockmask |= (1 << m);
2276       	  }
2277             }
2278         }
2279       XFreeModifiermap(mm);
2280     }
2281   lockmask &= ~(ShiftMask | ControlMask);
2282 
2283   mp = lock_mods;
2284   for (m = 0, i = 1; i < 256; i++)
2285     {
2286       if ((i & lockmask) > m)
2287           m = *mp++ = (i & lockmask);
2288     }
2289   *mp = 0;
2290 }
2291 
2292 
2293 /***********************************************************************
2294  *
2295  *  Procedure:
2296  *      ConstrainSize - adjust the given width and height to account for the
2297  *              constraints imposed by size hints
2298  *
2299  *      The general algorithm, especially the aspect ratio stuff, is
2300  *      borrowed from uwm's CheckConsistency routine.
2301  *
2302  ***********************************************************************/
ConstrainSize(XSizeHints * hints,int * widthp,int * heightp)2303 void ConstrainSize (XSizeHints *hints, int *widthp, int *heightp)
2304 {
2305 #define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
2306 #define _min(a,b) (((a) < (b)) ? (a) : (b))
2307 
2308 
2309   int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
2310   int baseWidth, baseHeight;
2311   int dwidth = *widthp, dheight = *heightp;
2312 
2313   if(hints->flags & PMinSize)
2314     {
2315       minWidth = hints->min_width;
2316       minHeight = hints->min_height;
2317       if(hints->flags & PBaseSize)
2318 	{
2319 	  baseWidth = hints->base_width;
2320 	  baseHeight = hints->base_height;
2321 	}
2322       else
2323 	{
2324 	  baseWidth = hints->min_width;
2325 	  baseHeight = hints->min_height;
2326 	}
2327     }
2328   else if(hints->flags & PBaseSize)
2329     {
2330       minWidth = hints->base_width;
2331       minHeight = hints->base_height;
2332       baseWidth = hints->base_width;
2333       baseHeight = hints->base_height;
2334     }
2335   else
2336     {
2337       minWidth = 1;
2338       minHeight = 1;
2339       baseWidth = 1;
2340       baseHeight = 1;
2341     }
2342 
2343   if(hints->flags & PMaxSize)
2344     {
2345       maxWidth = hints->max_width;
2346       maxHeight = hints->max_height;
2347     }
2348   else
2349     {
2350       maxWidth = 10000;
2351       maxHeight = 10000;
2352     }
2353   if(hints->flags & PResizeInc)
2354     {
2355       xinc = hints->width_inc;
2356       yinc = hints->height_inc;
2357     }
2358   else
2359     {
2360       xinc = 1;
2361       yinc = 1;
2362     }
2363 
2364   /*
2365    * First, clamp to min and max values
2366    */
2367   if (dwidth < minWidth) dwidth = minWidth;
2368   if (dheight < minHeight) dheight = minHeight;
2369 
2370   if (dwidth > maxWidth) dwidth = maxWidth;
2371   if (dheight > maxHeight) dheight = maxHeight;
2372 
2373 
2374   /*
2375    * Second, fit to base + N * inc
2376    */
2377   dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
2378   dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
2379 
2380 
2381   /*
2382    * Third, adjust for aspect ratio
2383    */
2384 #define maxAspectX hints->max_aspect.x
2385 #define maxAspectY hints->max_aspect.y
2386 #define minAspectX hints->min_aspect.x
2387 #define minAspectY hints->min_aspect.y
2388   /*
2389    * The math looks like this:
2390    *
2391    * minAspectX    dwidth     maxAspectX
2392    * ---------- <= ------- <= ----------
2393    * minAspectY    dheight    maxAspectY
2394    *
2395    * If that is multiplied out, then the width and height are
2396    * invalid in the following situations:
2397    *
2398    * minAspectX * dheight > minAspectY * dwidth
2399    * maxAspectX * dheight < maxAspectY * dwidth
2400    *
2401    */
2402 
2403   if (hints->flags & PAspect)
2404     {
2405       if (minAspectX * dheight > minAspectY * dwidth)
2406 	{
2407 	  delta = makemult(minAspectX * dheight / minAspectY - dwidth,
2408 			   xinc);
2409 	  if (dwidth + delta <= maxWidth)
2410 	    dwidth += delta;
2411 	  else
2412 	    {
2413 	      delta = makemult(dheight - dwidth*minAspectY/minAspectX,
2414 			       yinc);
2415 	      if (dheight - delta >= minHeight) dheight -= delta;
2416 	    }
2417 	}
2418 
2419       if (maxAspectX * dheight < maxAspectY * dwidth)
2420 	{
2421 	  delta = makemult(dwidth * maxAspectY / maxAspectX - dheight,
2422 			   yinc);
2423 	  if (dheight + delta <= maxHeight)
2424 	    dheight += delta;
2425 	  else
2426 	    {
2427 	      delta = makemult(dwidth - maxAspectX*dheight/maxAspectY,
2428 			       xinc);
2429 	      if (dwidth - delta >= minWidth) dwidth -= delta;
2430 	    }
2431 	}
2432     }
2433 
2434   *widthp = dwidth;
2435   *heightp = dheight;
2436   return 0;
2437 }
2438 
2439 
2440 #ifdef ENABLE_SOUND
PlaySound(int event)2441 void   PlaySound(int event)
2442 {
2443     int timestamp;
2444 
2445     if (!SoundActive)
2446       return;
2447     if (Sounds[event]==NULL) return;
2448     write(PlayerChannel[1],&event,sizeof(event));
2449     timestamp = clock();
2450     write(PlayerChannel[1],&timestamp,sizeof(timestamp));
2451     /*
2452     kill(SoundThread,SIGUSR1);
2453      */
2454 }
2455 #endif
2456