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],×tamp,sizeof(timestamp));
2451 /*
2452 kill(SoundThread,SIGUSR1);
2453 */
2454 }
2455 #endif
2456