todo-2.6 -- add note for fvwm-menu-desktop (2.6.X release)
[fvwm.git] / modules / FvwmWharf / FvwmWharf.c
blobac2763977941e49597e9152008437a07878206e6
1 /* -*-c-*- */
2 /* Wharf.c. by Bo Yang.
4 * Copyright 1993, Robert Nation.
6 * Modifications: Copyright 1995 by Bo Yang.
8 * modifications made by Frank Fejes for AfterStep Copyright 1996
10 * folder code Copyright 1996 by Beat Christen.
12 * swallowed button actions Copyright 1996 by Kaj Groner
14 * Various enhancements Copyright 1996 Alfredo K. Kojima
16 * button pushing styles
17 * configurable border drawing
18 * Change of icon creation code. Does not use shape extension anymore.
19 * each icon window now contains the whole background
20 * OffiX drop support added
21 * animation added
22 * withdraw on button2 click
23 * icon overlaying
24 * sound bindings
26 * based on GoodStuff.c by Robert Nation
27 * The GoodStuff module, and the entire GoodStuff program, and the concept for
28 * interfacing that module to the Window Manager, are all original work
29 * by Robert Nation
31 * No guarantees or warantees or anything
32 * are provided or implied in any way whatsoever. Use this program at your
33 * own risk. Permission to use this program for any purpose is given,
34 * as long as the copyright is kept intact. */
36 /* This program is free software; you can redistribute it and/or modify
37 * it under the terms of the GNU General Public License as published by
38 * the Free Software Foundation; either version 2 of the License, or
39 * (at your option) any later version.
41 * This program is distributed in the hope that it will be useful,
42 * but WITHOUT ANY WARRANTY; without even the implied warranty of
43 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 * GNU General Public License for more details.
46 * You should have received a copy of the GNU General Public License
47 * along with this program; if not, write to the Free Software
48 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
51 #define DOUBLECLICKTIME 1
53 #include "config.h"
55 #ifdef HAVE_SYS_BSDTYPES_H
56 #include <sys/bsdtypes.h> /* Saul */
57 #endif
59 #include <stdio.h>
60 #include <signal.h>
61 #include <fcntl.h>
62 #include <sys/wait.h>
63 #include "libs/ftime.h"
65 #if HAVE_SYS_SELECT_H
66 #include <sys/select.h>
67 #endif
69 #include <unistd.h>
70 #include <ctype.h>
71 #include "libs/fvwmlib.h"
72 #include "libs/FScreen.h"
73 #include "libs/FShape.h"
74 #include "libs/FRenderInit.h"
75 #include "libs/Module.h"
76 #include "libs/PictureBase.h"
77 #include "libs/Colorset.h"
78 #include "libs/Graphics.h"
79 #include "libs/Parse.h"
80 #include "libs/Strings.h"
81 #include "libs/System.h"
82 #include "libs/XError.h"
83 #include <X11/Xlib.h>
84 #include <X11/Xutil.h>
85 #include <X11/Xproto.h>
86 #include <X11/Xatom.h>
87 #include <X11/Intrinsic.h>
88 #include <syslog.h>
90 #include "Wharf.h"
91 #define AFTER_ICONS 1
92 /*#include "afterstep/asbuttons.h" pdg */
94 #ifdef ENABLE_DND
95 #include "OffiX/DragAndDrop.h"
96 #include "OffiX/DragAndDropTypes.h"
97 #endif
99 #include "stepgfx.h"
102 * You may want to raise the following values if your machine is fast
104 #define ANIM_STEP 2 /* must be >= 1. Greater is smoother and slower */
105 #define ANIM_STEP_MAIN 1 /* same for the main folder */
106 #define ANIM_DELAY 10
108 #ifdef ENABLE_SOUND
109 #define WHEV_PUSH 0
110 #define WHEV_CLOSE_FOLDER 1
111 #define WHEV_OPEN_FOLDER 2
112 #define WHEV_CLOSE_MAIN 3
113 #define WHEV_OPEN_MAIN 4
114 #define WHEV_DROP 5
115 #define MAX_EVENTS 6
117 int SoundActive = 0;
118 char *Sounds[6]={".",".",".",".",".","."};
119 char *SoundPlayer=NULL;
120 char *SoundPath=".";
122 pid_t SoundThread;
123 int PlayerChannel[2];
125 /*char *ModulePath=AFTERDIR; pdg */
126 #endif
128 char *MyName;
130 Display *dpy;
131 int x_fd;
132 fd_set_size_t fd_width;
133 int ROWS = False;
135 Window Root;
136 int screen;
137 int flags;
138 Bool NoBorder=0;
139 Bool Pushed = 0;
140 Bool Pushable = 1;
141 Bool ForceSize=0;
142 Pixel back_pix = 0;
143 Pixel fore_pix = 0;
144 Pixel light_grey = 0;
145 GC NormalGC, HiReliefGC, HiInnerGC;
147 GC MaskGC;
148 int AnimationStyle=0,AnimateMain=0;
149 int PushStyle=0;
150 int AnimationDir=1;
152 Window main_win;
153 int Width, Height,win_x,win_y;
154 int display_width, display_height;
156 #define MW_EVENTS (ExposureMask | ButtonReleaseMask |\
157 ButtonPressMask | LeaveWindowMask | EnterWindowMask)
158 XSizeHints mysizehints;
159 int num_buttons = 0;
160 int num_folderbuttons = MAX_BUTTONS;
161 int num_folders = 0;
162 int num_rows = 0;
163 int num_columns = 0;
164 int max_icon_width = 30,max_icon_height = 0;
165 int BUTTONWIDTH, BUTTONHEIGHT;
166 int x= -100000,y= -100000,w= -1,h= -1,gravity = NorthWestGravity;
167 int new_desk = 0;
168 int pageing_enabled = 1;
169 int ready = 0;
171 int CurrentButton = -1;
172 int fd[2];
174 struct button_info Buttons[BUTTON_ARRAY_LN];
175 struct folder_info Folders[FOLDER_ARRAY_LN];
177 char *imagePath = NULL;
179 static Atom _XA_WM_DEL_WIN;
180 Atom _XA_WM_PROTOCOLS;
181 Atom _XA_WM_NAME;
182 #ifdef ENABLE_DND
183 Atom DndProtocol;
184 Atom DndSelection;
185 #endif
186 int TextureType=TEXTURE_BUILTIN;
187 char *BgPixmapFile=NULL;
188 int FromColor[3]={0x4000,0x4000,0x4000}, ToColor[3]={0x8000,0x8000,0x8000};
189 Pixel BgColor=0;
190 int MaxColors=16;
191 int Withdrawn;
192 static int global_colorset = -1;
194 #define DIR_TOLEFT 1
195 #define DIR_TORIGHT 2
196 #define DIR_TOUP 3
197 #define DIR_TODOWN 4
199 #ifdef ENABLE_SOUND
200 void waitchild(int bullshit)
202 int stat;
204 wait(&stat);
205 SoundActive=0;
207 #endif
209 unsigned int lock_mods[256];
210 void FindLockMods(void);
211 static void configure_all_icon_windows(void);
214 int myErrorHandler(Display *dpy, XErrorEvent *event)
216 if(event->error_code == BadWindow || event->error_code == BadDrawable)
218 return 0;
220 PrintXErrorAndCoredump(dpy, event, MyName);
222 return 0;
227 * Procedure:
228 * main - start of afterstep
231 int main(int argc, char **argv)
233 char *display_name = NULL;
234 int i,j;
235 Window junkroot;
236 int x,y,border_width;
237 int depth;
238 char *temp, *s;
239 temp = argv[0];
241 s=strrchr(argv[0], '/');
242 if (s != NULL)
243 temp = s + 1;
245 MyName = safemalloc(strlen(temp)+1);
246 strcpy(MyName, temp);
248 for(i=0;i<BUTTON_ARRAY_LN;i++)
250 #ifdef ENABLE_DND
251 Buttons[i].drop_action = NULL;
252 #endif
253 Buttons[i].title = NULL;
254 Buttons[i].action = NULL;
255 Buttons[i].iconno = 0;
256 for(j=0;j<MAX_OVERLAY;j++) {
257 Buttons[i].icons[j].file = NULL;
258 Buttons[i].icons[j].w = 0;
259 Buttons[i].icons[j].h = 0;
260 Buttons[i].icons[j].mask = None; /* pixmap for the icon mask */
261 Buttons[i].icons[j].icon = None;
262 Buttons[i].icons[j].alpha = None;
263 Buttons[i].icons[j].depth = 0;
265 Buttons[i].IconWin = None;
266 Buttons[i].completeIcon = None;
267 Buttons[i].up = 1; /* Buttons start up */
268 Buttons[i].hangon = NULL; /* don't wait on anything yet*/
269 Buttons[i].folder = -1;
271 signal (SIGPIPE, DeadPipe);
272 if((argc != 6)&&(argc != 7))
274 fprintf(stderr,"%s Version %s should only be executed by Fvwm!\n",
275 MyName, VERSION);
276 exit(1);
278 fd[0] = atoi(argv[1]);
279 fd[1] = atoi(argv[2]);
281 if (!(dpy = XOpenDisplay(display_name)))
283 fprintf(stderr,"%s: can't open display %s\n", MyName,
284 XDisplayName(display_name));
285 exit (1);
287 flib_init_graphics(dpy);
288 XSetErrorHandler(myErrorHandler);
290 x_fd = XConnectionNumber(dpy);
292 fd_width = GetFdWidth();
294 screen= DefaultScreen(dpy);
295 Root = RootWindow(dpy, screen);
296 if(Root == None)
298 fprintf(stderr,"%s: Screen %d is not valid\n", MyName, screen);
299 exit(1);
301 display_width = DisplayWidth(dpy, screen);
302 display_height = DisplayHeight(dpy, screen);
304 SetMessageMask(fd, M_NEW_DESK | M_END_WINDOWLIST | M_MAP | M_WINDOW_NAME |
305 M_RES_CLASS | M_CONFIG_INFO | M_END_CONFIG_INFO | M_RES_NAME |
306 M_SENDCONFIG);
308 sprintf(set_mask_mesg,"SET_MASK %lu\n",
309 (unsigned long)(M_NEW_DESK |
310 M_END_WINDOWLIST|
311 M_MAP|
312 M_RES_NAME|
313 M_RES_CLASS|
314 M_WINDOW_NAME));
316 SendText(fd,set_mask_mesg,0);
319 /* create a temporary window of the correct visual for the pixmaps */
320 CreateVizWindow();
322 ParseOptions(argv[3]);
323 if(num_buttons == 0)
325 fprintf(stderr,"%s: No Buttons defined. Quitting\n", MyName);
326 exit(0);
329 #ifdef ENABLE_SOUND
330 /* startup sound subsystem */
331 if (SoundActive) {
332 if (pipe(PlayerChannel)<0) {
333 fprintf(stderr,"%s: could not create pipe. Disabling sound\n");
334 SoundActive=0;
335 } else {
336 signal(SIGCHLD,waitchild);
337 SoundThread=fork();
338 if (SoundThread<0) {
339 fprintf(stderr,"%s: could not fork(). Disabling sound\n", MyName);
340 perror(".");
341 SoundActive=0;
342 } else if (SoundThread==0) { /* in the sound player process */
343 char *margv[9], *name;
344 int i;
346 margv[0]="ASSound";
347 name = findImageFile("ASSound",ModulePath,X_OK);
348 if(name == NULL) {
349 fprintf(stderr,"Wharf: couldn't find ASSound\n");
350 SoundActive = 0;
351 } else {
352 margv[1]=safemalloc(16);
353 close(PlayerChannel[1]);
354 sprintf(margv[1],"%x",PlayerChannel[0]);
355 if (SoundPlayer!=NULL)
356 margv[2]=SoundPlayer;
357 else
358 margv[2]="-";
359 for(i=0;i<MAX_EVENTS;i++) {
360 if (Sounds[i][0]=='.') {
361 margv[i+3]=Sounds[i];
362 } else {
363 margv[i+3]=safemalloc(strlen(Sounds[i])
364 +strlen(SoundPath)+4);
365 sprintf(margv[i+3],"%s/%s",SoundPath,Sounds[i]);
368 margv[i+3]=NULL;
369 execvp(name,margv);
370 fprintf(stderr,"Wharf: couldn't spawn ASSound\n");
371 exit(1);
373 } else { /* in parent */
374 close(PlayerChannel[0]);
378 #endif
380 CreateShadowGC();
382 switch (TextureType)
384 case TEXTURE_PIXMAP:
385 if (BgPixmapFile==NULL) {
386 fprintf(stderr,
387 "%s: No Button background pixmap defined.Using default\n",
388 MyName);
389 goto Builtin;
391 Buttons[BACK_BUTTON].icons[0].file=BgPixmapFile;
392 if (LoadIconFile(BACK_BUTTON,0))
393 break;
394 else
395 goto Solid;
396 case TEXTURE_GRADIENT:
397 case TEXTURE_HGRADIENT:
398 case TEXTURE_HCGRADIENT:
399 case TEXTURE_VGRADIENT:
400 case TEXTURE_VCGRADIENT:
401 if (GetXPMGradient(BACK_BUTTON, FromColor, ToColor, MaxColors,TextureType))
402 break;
403 else
404 goto Solid;
406 case TEXTURE_COLORSET:
407 BgColor = Colorset[global_colorset].bg;
408 /* use a colorset */
409 GetXPMColorset(BACK_BUTTON, global_colorset);
410 break;
412 case TEXTURE_BUILTIN:
413 Builtin:
414 TextureType=TEXTURE_BUILTIN;
415 default:
416 Solid:
417 TextureType=TEXTURE_SOLID;
418 if (GetSolidXPM(BACK_BUTTON, BgColor))
419 break;
420 else {
421 fprintf( stderr, "back Wharf button creation\n");
422 exit(-1);
424 } /* switch */
425 for(i=0;i<num_buttons;i++)
427 for(j=0;j<Buttons[i].iconno;j++) {
428 LoadIconFile(i,j);
431 for(i=num_folderbuttons;i<MAX_BUTTONS;i++) {
432 for(j=0;j<Buttons[i].iconno;j++) {
433 LoadIconFile(i,j);
436 #ifdef ENABLE_DND
437 DndProtocol=XInternAtom(dpy,"DndProtocol",False);
438 DndSelection=XInternAtom(dpy,"DndSelection",False);
439 #endif
441 CreateWindow();
442 for(i=0;i<num_buttons;i++) {
443 CreateIconWindow(i, &main_win);
445 for(i=num_folderbuttons;i<MAX_BUTTONS;i++)
446 CreateIconWindow(i, Buttons[i].parent);
447 if (!XGetGeometry(dpy,main_win,&junkroot,&x,&y,
448 (unsigned int *)&Width,(unsigned int *)&Height,
449 (unsigned int *)&border_width,(unsigned int *)&depth))
451 fprintf(stderr, "%s: Failed to get window geometry\n",MyName);
452 exit(0);
455 configure_all_icon_windows();
456 configure_all_icon_windows();
457 XMapSubwindows(dpy,main_win);
458 XMapWindow(dpy,main_win);
459 for(i=0;i<num_folders;i++)
460 XMapSubwindows(dpy, Folders[i].win);
462 FindLockMods();
464 /* request a window list, since this triggers a response which
465 * will tell us the current desktop and paging status, needed to
466 * indent buttons correctly */
467 SendText(fd,"Send_WindowList",0);
469 /* tell fvwm we're running */
470 SendFinishedStartupNotification(fd);
472 Loop();
473 return 0;
478 * Procedure:
479 * Loop - wait for data to process
483 void Loop(void)
485 Window *CurrentWin=None;
486 int x,y,CurrentRow,CurrentColumn,CurrentBase=0;
487 XEvent Event;
488 int NewButton,i=0,j=0,i2, bl=-1;
489 int LastMapped=-1;
490 time_t t, tl = (time_t) 0;
491 int CancelPush=0;
493 while(1)
495 if(My_XNextEvent(dpy,&Event))
497 switch(Event.type)
500 case Expose:
501 for(x=0;x<num_folders;x++)
502 if(Event.xany.window == Folders[x].win )
504 RedrawWindow(&Folders[x].win,num_folderbuttons, -1,
505 Folders[x].cols,Folders[x].rows);
506 for(y=1;y<=Folders[x].count;y++)
507 if(num_columns<num_rows)
508 RedrawUnpushedOutline(&Folders[x].win, 1, y);
509 else
510 RedrawUnpushedOutline(&Folders[x].win, y, 1);
512 if (Pushed)
513 break;
514 if((Event.xexpose.count == 0)&&
515 (Event.xany.window == main_win))
517 if(ready < 1)
518 ready ++;
519 RedrawWindow(&main_win,0, -1, num_rows, num_columns);
521 break;
523 case ButtonPress:
524 if (Event.xbutton.button != Button1) {
525 if (Event.xbutton.button == Button2) {
526 static int LastX, LastY;
527 static int scr_x, scr_y;
528 static int scr_w, scr_h;
530 if (LastMapped != -1) {
531 CloseFolder(LastMapped);
532 Folders[LastMapped].mapped = NOTMAPPED;
533 LastMapped=-1;
535 if (Withdrawn) {
536 #ifdef ENABLE_SOUND
537 PlaySound(WHEV_OPEN_MAIN);
538 #endif
539 if (AnimationStyle>0 && AnimateMain)
540 OpenFolder(-1,LastX,LastY,Width,Height,AnimationDir);
541 else
542 XMoveResizeWindow(dpy,main_win,LastX,LastY,Width,Height);
543 Withdrawn=0;
544 } else {
545 Window junk;
546 unsigned int junk2,junk3,junk4,junk5;
547 int CornerX, CornerY;
548 fscreen_scr_arg fscr;
550 #ifdef ENABLE_SOUND
551 PlaySound(WHEV_CLOSE_MAIN);
552 #endif
553 if (XGetGeometry(
554 dpy,main_win,&junk,&LastX,&LastY,&junk2,&junk3,&junk4,&junk5))
556 LastX = 0;
557 LastY = 0;
559 XTranslateCoordinates(
560 dpy,main_win,Root,LastX,LastY,&LastX,&LastY,&junk);
561 /* Note: maybe it will be better to use (LastX+W/2,LastY+H/2)
562 in ScrRect query? That could help in pathological cases when
563 Wharf is not completely on a single screen. */
564 fscr.xypos.x = LastX;
565 fscr.xypos.y = LastY;
566 FScreenGetScrRect(
567 &fscr, FSCREEN_XYPOS, &scr_x, &scr_y, &scr_w, &scr_h);
568 if (num_rows<num_columns) { /* horizontal */
569 if (LastY > scr_y + scr_h / 2) {
570 CornerY = scr_y+scr_h-BUTTONHEIGHT;
571 } else {
572 CornerY = scr_y;
574 if (Event.xbutton.x>num_columns*BUTTONWIDTH/2) {
575 CornerX = scr_x + scr_w - BUTTONWIDTH;
576 AnimationDir = DIR_TOLEFT;
577 } else {
578 CornerX = scr_x;
579 AnimationDir = DIR_TORIGHT;
581 if (AnimationStyle>0 && AnimateMain) {
582 CloseFolder(-1);
583 XMoveWindow(dpy,main_win, CornerX, CornerY);
584 } else {
585 XMoveResizeWindow(dpy,main_win,
586 CornerX, CornerY,
587 BUTTONWIDTH,BUTTONHEIGHT);
589 } else { /* vertical */
590 if (LastX > scr_x + scr_w/2) {
591 CornerX = scr_x + scr_w - BUTTONWIDTH;
592 } else {
593 CornerX = scr_x;
595 if (Event.xbutton.y>num_rows*BUTTONHEIGHT/2) {
596 CornerY = scr_y + scr_h - BUTTONHEIGHT;
597 AnimationDir = DIR_TOUP;
598 } else {
599 CornerY = scr_y;
600 AnimationDir = DIR_TODOWN;
602 if (AnimationStyle>0 && AnimateMain) {
603 CloseFolder(-1);
604 XMoveWindow(dpy,main_win, CornerX, CornerY);
605 } else {
606 XMoveResizeWindow(dpy,main_win,
607 CornerX, CornerY,
608 BUTTONWIDTH,BUTTONHEIGHT);
611 Withdrawn=1;
614 break;
616 #ifdef ENABLE_SOUND
617 PlaySound(WHEV_PUSH);
618 #endif
619 CancelPush = 0;
620 CurrentWin = &Event.xbutton.window;
621 CurrentBase = 0;
622 CurrentRow = (Event.xbutton.y/BUTTONHEIGHT);
623 CurrentColumn = (Event.xbutton.x/BUTTONWIDTH);
624 if (*CurrentWin!=main_win) {
625 CurrentButton = CurrentBase + CurrentColumn*num_rows
626 + CurrentRow*num_columns;
627 } else {
628 CurrentButton = CurrentBase + CurrentColumn
629 + CurrentRow*num_columns;
630 if (CurrentButton>=num_buttons) {
631 CurrentButton = -1;
632 break;
636 for(x=0;x<num_buttons;x++)
638 if (*CurrentWin == Buttons[x].IconWin)
640 CurrentButton = x;
641 CurrentRow = x / num_columns;
642 CurrentColumn = x % num_columns;
646 for(x=0;x<num_folders;x++)
647 if(*CurrentWin == Folders[x].win)
649 CurrentBase = Folders[x].firstbutton;
650 if (num_rows<num_columns)
651 CurrentButton = CurrentBase + CurrentRow;
652 else
653 CurrentButton = CurrentBase + CurrentColumn;
655 i = CurrentRow+1;
656 j = CurrentColumn +1;
658 if (Buttons[CurrentButton].swallow == 1 ||
659 Buttons[CurrentButton].swallow == 2 ||
660 Buttons[CurrentButton].action == NULL)
661 break;
663 if (Pushable)
665 if (Buttons[CurrentButton].swallow != 3 &&
666 Buttons[CurrentButton].swallow != 4)
668 Pushed = 1;
669 RedrawPushed(CurrentWin, i, j);
672 if (strncasecmp(Buttons[CurrentButton].action,"Folder",6)==0)
674 Window junk;
675 unsigned int junk2,junk3,junk4,junk5;
677 if (!XGetGeometry(
678 dpy,main_win,&junk,&x,&y,&junk2,&junk3,&junk4,&junk5))
680 x = 0;
681 y = 0;
683 XTranslateCoordinates(dpy,main_win,Root,x,y,&x,&y,&junk);
684 /* kludge until Beat takes a look */
685 if ((num_columns == 1) && (num_rows == 1))
686 MapFolder(Buttons[CurrentButton].folder,
687 &LastMapped,
688 x, y,
689 1,1);
690 else
691 MapFolder(Buttons[CurrentButton].folder,
692 &LastMapped,
693 x, y,
694 CurrentRow, CurrentColumn);
696 break;
697 case EnterNotify:
698 CancelPush = 0;
699 break;
700 case LeaveNotify:
701 CancelPush = 1;
702 break;
703 case ClientMessage:
704 if(Event.xclient.format == 32 &&
705 Event.xclient.data.l[0]==_XA_WM_DEL_WIN)
707 DeadPipe(1);
709 #ifdef ENABLE_DND
710 else if (Event.xclient.message_type==DndProtocol) {
711 unsigned long dummy_r,size;
712 Atom dummy_a;
713 int dummy_f;
714 unsigned char *data, *Command;
716 Window dummy_rt, dummy_c;
717 int dummy_x, dummy_y, base, pos_x, pos_y;
718 unsigned int dummy;
720 /* if (Event.xclient.data.l[0]!=DndFile ||
721 Event.xclient.data.l[0]!=DndFiles ||
722 Event.xclient.data.l[0]!=DndExe
724 break; */
726 if (FQueryPointer(
727 dpy, main_win, &dummy_rt, &dummy_c, &dummy_x, &dummy_y,
728 &pos_x, &pos_y, &dummy) == False)
730 /* pointer is on a different screen - that's okay here */
732 base = 0;
733 dummy_y = (pos_y/BUTTONHEIGHT);
734 dummy_x= (pos_x/BUTTONWIDTH);
735 dummy = base + dummy_x + dummy_y*num_columns;
738 for(x=0;x<num_folders;x++) {
739 if(Event.xbutton.window == Folders[x].win) {
740 base = Folders[x].firstbutton;
741 dummy = base + dummy_y + dummy_x -1;
743 } */
744 if (Buttons[dummy].drop_action == NULL)
745 break;
746 dummy_x++;
747 dummy_y++;
748 CurrentWin=Buttons[dummy].parent;
749 if (Pushable) {
750 RedrawPushedOutline(CurrentWin, dummy_y, dummy_x);
751 XSync(dpy, 0);
753 XGetWindowProperty(dpy, Root, DndSelection, 0L,
754 100000L, False, AnyPropertyType,
755 &dummy_a, &dummy_f,
756 &size,&dummy_r,
757 &data);
758 if (Event.xclient.data.l[0]==DndFiles) {
759 for (dummy_r = 0; dummy_r<size-1; dummy_r++) {
760 if (data[dummy_r]==0)
761 data[dummy_r]=' ';
764 #ifdef ENABLE_SOUND
765 PlaySound(WHEV_DROP);
766 #endif
767 Command = (unsigned char *)safemalloc(
768 strlen((char *)data) +
769 strlen((char *)(Buttons[dummy].drop_action)));
770 sprintf((char *)Command,Buttons[dummy].drop_action,
771 data,Event.xclient.data.l[0]);
772 SendInfo(fd,(char *)Command,0);
773 free(Command);
774 if (Pushable) {
775 usleep(50000);
776 XClearWindow(dpy,Buttons[dummy].IconWin);
777 RedrawUnpushedOutline(CurrentWin, dummy_y, dummy_x);
780 break;
781 #endif /* ENABLE_DND */
782 case ButtonRelease:
783 if ((Event.xbutton.button != Button1) ||
784 (Buttons[CurrentButton].swallow == 1) ||
785 (Buttons[CurrentButton].swallow == 2) ||
786 (Buttons[CurrentButton].action == NULL)) {
787 break;
790 CurrentRow = (Event.xbutton.y/BUTTONHEIGHT);
791 CurrentColumn = (Event.xbutton.x/BUTTONWIDTH);
793 if (Pushable)
795 if (Buttons[CurrentButton].swallow != 3 &&
796 Buttons[CurrentButton].swallow != 4)
798 Pushed=0;
799 RedrawUnpushed(CurrentWin, i, j);
802 if (CancelPush)
803 break;
804 if (*CurrentWin!=main_win) {
805 NewButton = CurrentBase + CurrentColumn*num_rows
806 + CurrentRow*num_columns;
807 } else {
808 NewButton = CurrentBase + CurrentColumn
809 + CurrentRow*num_columns;
812 for(x=0;x<num_folders;x++)
813 if(*CurrentWin == Folders[x].win)
815 if (num_rows<num_columns)
816 NewButton = Folders[x].firstbutton + CurrentRow;
817 else
818 NewButton = Folders[x].firstbutton + CurrentColumn;
820 for (x=0;x<num_buttons;x++)
822 if (*CurrentWin == Buttons[x].IconWin)
824 NewButton = x;
825 CurrentRow = x / num_columns;
826 CurrentColumn = x % num_columns;
830 if(NewButton == CurrentButton)
832 t = time( 0);
833 bl = -1;
834 tl = -1;
835 if(strncasecmp(Buttons[CurrentButton].action,"Folder",6)!=0)
837 if (LastMapped != -1 && CurrentWin != &main_win)
839 CloseFolder(LastMapped);
840 Folders[LastMapped].mapped = NOTMAPPED;
841 LastMapped = -1;
843 SendInfo(fd,Buttons[CurrentButton].action,0);
845 if((Buttons[CurrentButton].action)&&
846 (strncasecmp(Buttons[CurrentButton].action,"exec",4)== 0))
848 i=4;
849 while((Buttons[CurrentButton].action[i] != 0)&&
850 (Buttons[CurrentButton].action[i] != '"'))
851 i++;
852 i2=i+1;
854 while((Buttons[CurrentButton].action[i2] != 0)&&
855 (Buttons[CurrentButton].action[i2] != '"'))
856 i2++;
857 if(i2 - i >1)
859 Buttons[CurrentButton].hangon = safemalloc(i2-i);
860 strncpy(Buttons[CurrentButton].hangon,
861 &Buttons[CurrentButton].action[i+1],i2-i-1);
862 Buttons[CurrentButton].hangon[i2-i-1] = 0;
863 Buttons[CurrentButton].up = 0;
864 if (Buttons[CurrentButton].swallow == 3 ||
865 Buttons[CurrentButton].swallow == 4)
866 Buttons[CurrentButton].swallow = 4;
867 else
868 Buttons[CurrentButton].swallow = 0;
872 break;
874 default:
875 break;
881 void OpenFolder(int folder,int x, int y, int w, int h, int direction)
883 int winc, hinc;
884 int cx, cy, cw, ch;
885 Window win;
886 int isize;
888 if (folder<0) {
889 winc = BUTTONWIDTH/ANIM_STEP_MAIN;
890 hinc = BUTTONHEIGHT/ANIM_STEP_MAIN;
891 } else {
892 winc = BUTTONWIDTH/ANIM_STEP;
893 hinc = BUTTONHEIGHT/ANIM_STEP;
896 if (folder>=0) {
897 win = Folders[folder].win;
898 Folders[folder].direction = direction;
899 if (direction == DIR_TOLEFT || direction == DIR_TORIGHT)
900 isize = winc;
901 else
902 isize = hinc;
903 } else {
904 win = main_win;
905 if (direction == DIR_TOLEFT || direction == DIR_TORIGHT)
906 isize = BUTTONWIDTH;
907 else
908 isize = BUTTONHEIGHT;
910 cx = x; cy = y;
911 ch = h; cw = w;
912 if (AnimationStyle==0) {
913 XMapWindow(dpy, win);
914 } else
915 switch (direction) {
916 case DIR_TOLEFT:
917 cx = x+w;
918 XMoveResizeWindow(dpy,win,cx,y, 1, h);
919 XMapWindow(dpy, win);
920 for(cw=isize;cw<=w;cw+=winc) {
921 cx -= winc;
922 usleep(ANIM_DELAY/2);
923 XMoveResizeWindow(dpy,win,cx,y, cw,h);
924 XSync(dpy,0);
926 break;
927 case DIR_TORIGHT:
928 XMoveResizeWindow(dpy,win,x,y, 1, h);
929 XMapWindow(dpy, win);
930 for(cw=isize;cw<=w;cw+=winc) {
931 usleep(ANIM_DELAY/2);
932 XMoveResizeWindow(dpy,win,x,y, cw,h);
933 XSync(dpy,0);
935 break;
936 case DIR_TOUP:
937 cy = y+h;
938 XMoveResizeWindow(dpy,win,x,cy, w, 1);
939 XMapWindow(dpy, win);
940 for(ch=isize;ch<=h;ch+=hinc) {
941 cy -= hinc;
942 usleep(ANIM_DELAY/2);
943 XMoveResizeWindow(dpy,win,x,cy, w, ch);
944 XSync(dpy,0);
946 break;
947 case DIR_TODOWN:
948 XMoveResizeWindow(dpy,win,x,y, w, 1);
949 XMapWindow(dpy, win);
950 for(ch=isize;ch<=h;ch+=hinc) {
951 usleep(ANIM_DELAY/2);
952 XMoveResizeWindow(dpy,win,x,y, w, ch);
953 XSync(dpy,0);
955 break;
956 default:
957 XBell(dpy,100);
958 fprintf(stderr,"WHARF INTERNAL BUG in OpenFolder()\n");
959 exit(-1);
962 if (cw!=w || ch!=h || x != cx || cy != y || AnimationStyle==0)
963 XMoveResizeWindow(dpy,win,x,y,w,h);
968 void CloseFolder(int folder)
970 int winc, hinc;
971 int cx, cy, cw, ch;
972 int x,y;
973 unsigned int w,h, junk_depth, junk_bd;
974 int fsize, direction;
975 Window win, junk_win;
977 #ifdef ENABLE_SOUND
978 PlaySound(WHEV_CLOSE_FOLDER);
979 #endif
980 if (folder<0) {
981 winc = BUTTONWIDTH/ANIM_STEP_MAIN;
982 hinc = BUTTONHEIGHT/ANIM_STEP_MAIN;
983 } else {
984 winc = BUTTONWIDTH/ANIM_STEP;
985 hinc = BUTTONHEIGHT/ANIM_STEP;
987 if (folder < 0) {
988 win = main_win;
989 direction = AnimationDir;
990 if (direction==DIR_TOUP || direction==DIR_TODOWN)
991 fsize=BUTTONHEIGHT;
992 else
993 fsize=BUTTONWIDTH;
994 } else {
995 direction = Folders[folder].direction;
996 win = Folders[folder].win;
997 if (direction==DIR_TOUP || direction==DIR_TODOWN)
998 fsize=hinc;
999 else
1000 fsize=winc;
1002 if (AnimationStyle==0 ||
1003 !XGetGeometry(dpy,win,&junk_win,&x,&y,&w,&h,&junk_bd,&junk_depth))
1005 goto end;
1007 XTranslateCoordinates(dpy,win,Root,x,y,&x,&y,&junk_win);
1008 switch (direction) {
1009 case DIR_TOLEFT:
1010 cx = x;
1011 for(cw=w;cw >= fsize; cw-=winc) {
1012 XMoveResizeWindow(dpy,win,cx,y, cw,h);
1013 XSync(dpy,0);
1014 usleep(ANIM_DELAY);
1015 cx += winc;
1017 break;
1018 case DIR_TORIGHT:
1019 for(cw=w;cw >= fsize; cw-=winc) {
1020 XMoveResizeWindow(dpy,win,x,y, cw,h);
1021 XSync(dpy,0);
1022 usleep(ANIM_DELAY);
1024 break;
1025 case DIR_TOUP:
1026 cy = y;
1027 for(ch=h;ch >= fsize; ch-=hinc) {
1028 XMoveResizeWindow(dpy,win,x,cy, w,ch);
1029 XSync(dpy,0);
1030 usleep(ANIM_DELAY);
1031 cy += hinc;
1033 break;
1034 case DIR_TODOWN:
1035 for(ch=h;ch >= fsize; ch-=hinc) {
1036 XMoveResizeWindow(dpy,win,x,y, w, ch);
1037 XSync(dpy,0);
1038 usleep(ANIM_DELAY);
1040 break;
1041 default:
1042 XBell(dpy,100);
1043 fprintf(stderr,"WHARF INTERNAL BUG in CloseFolder()\n");
1044 exit(-1);
1046 Folders[folder].direction = 0;
1047 end:
1048 if (folder<0) {
1049 XResizeWindow(dpy,win,BUTTONWIDTH,BUTTONHEIGHT);
1050 } else {
1051 XUnmapWindow(dpy,win);
1056 void MapFolder(int folder, int *LastMapped, int base_x, int base_y, int row,
1057 int col)
1059 int dir;
1061 if (Folders[folder].mapped ==ISMAPPED)
1063 CloseFolder(folder);
1064 Folders[folder].mapped = NOTMAPPED;
1065 *LastMapped = -1;
1067 else
1069 int folderx, foldery, folderw, folderh;
1070 int scr_x, scr_y;
1071 int scr_w, scr_h;
1072 fscreen_scr_arg fscr;
1074 fscr.xypos.x = base_x;
1075 fscr.xypos.y = base_y;
1076 FScreenGetScrRect(&fscr, FSCREEN_XYPOS, &scr_x, &scr_y, &scr_w, &scr_h);
1078 if (*LastMapped != -1)
1080 CloseFolder(*LastMapped);
1081 Folders[*LastMapped].mapped = NOTMAPPED;
1082 *LastMapped = -1;
1084 Folders[folder].mapped = ISMAPPED;
1085 if(num_columns < num_rows)
1087 if((base_x % display_width) > scr_x + scr_w / 2 ) {
1088 folderx = base_x+(col-Folders[folder].count)*BUTTONWIDTH-2;
1089 dir = DIR_TOLEFT;
1091 else {
1092 folderx = base_x+(col+1)*BUTTONHEIGHT+1;
1093 dir = DIR_TORIGHT;
1095 foldery = base_y+row*BUTTONHEIGHT;
1096 folderw = Folders[folder].count*BUTTONWIDTH;
1097 folderh = BUTTONHEIGHT;
1099 /* more kludgery */
1100 else if (num_columns == num_rows)
1103 if((base_x % display_width) > display_width / 2 )
1104 folderx = (col-Folders[folder].count)*BUTTONHEIGHT-2;
1105 else
1106 folderx = (col+1)*BUTTONHEIGHT+1;
1108 if (ROWS)
1110 if ((base_y % display_height) > scr_y + scr_h / 2) {
1111 foldery = base_y-(Folders[folder].count)*BUTTONHEIGHT-2;
1112 dir = DIR_TOUP;
1114 else {
1115 foldery = base_y+BUTTONHEIGHT+2;
1116 dir = DIR_TODOWN;
1118 folderx = base_x;
1119 folderw = BUTTONWIDTH;
1120 folderh = (Folders[folder].count)*BUTTONHEIGHT;
1122 else
1124 if((base_x % display_width) > scr_x + scr_w / 2 ) {
1125 folderx = base_x-(Folders[folder].count)*BUTTONWIDTH-2;
1126 dir = DIR_TOLEFT;
1128 else {
1129 folderx = base_x+BUTTONWIDTH+1;
1130 dir = DIR_TORIGHT;
1132 foldery = base_y-1;
1133 folderh = BUTTONHEIGHT;
1134 folderw = (Folders[folder].count)*BUTTONWIDTH;
1137 else
1139 if ((base_y % display_height) < scr_y + scr_h / 2) {
1140 foldery =base_y+(row+1)*BUTTONHEIGHT;
1141 dir = DIR_TODOWN;
1143 else {
1144 foldery = base_y+(row-Folders[folder].count)*BUTTONHEIGHT;
1145 dir = DIR_TOUP;
1147 folderx = base_x+col*BUTTONWIDTH;
1148 folderw = BUTTONWIDTH;
1149 folderh = (Folders[folder].count)*BUTTONHEIGHT;
1152 #ifdef ENABLE_SOUND
1153 PlaySound(WHEV_OPEN_FOLDER);
1154 #endif
1155 XMoveWindow(dpy, Folders[folder].win, folderx, foldery);
1156 OpenFolder(folder,folderx, foldery, folderw, folderh, dir);
1157 *LastMapped = folder;
1161 void
1162 DrawOutline(Drawable d, int w, int h)
1164 if (NoBorder)
1165 return;
1166 /* top */
1167 XDrawLine( dpy, d, HiInnerGC, 0, 0, w-1, 0);
1169 XDrawLine( dpy, d, HiInnerGC, 0, 1, w-1, 1);
1171 /* bottom */
1172 XFillRectangle(dpy, d, NormalGC, 0,h-2,w-1,h-1);
1174 /* left */
1175 XDrawLine( dpy, d, HiInnerGC, 0, 1, 0, h-1);
1177 XDrawLine( dpy, d, HiInnerGC, 1, 2, 1, h-2);
1179 /* right */
1180 XDrawLine( dpy, d, NormalGC, w-1, 1, w-1, h-1);
1181 XDrawLine( dpy, d, NormalGC, w-2, 2, w-2, h-2);
1184 void RedrawUnpushed(Window *win, int i, int j)
1186 if (PushStyle!=0) {
1187 XMoveResizeWindow(dpy, Buttons[CurrentButton].IconWin,
1188 (j-1)*BUTTONWIDTH ,(i-1)*BUTTONHEIGHT,
1189 BUTTONWIDTH, BUTTONHEIGHT);
1190 } else {
1191 XCopyArea( dpy, Buttons[CurrentButton].completeIcon,
1192 Buttons[CurrentButton].IconWin, NormalGC, 0, 0,
1193 Buttons[BACK_BUTTON].icons[0].w,
1194 Buttons[BACK_BUTTON].icons[0].h,
1195 0,0);
1197 RedrawWindow(win,0, CurrentButton, num_rows, num_columns);
1199 RedrawUnpushedOutline(win, i, j);
1202 void RedrawUnpushedOutline(Window *win, int i, int j)
1204 /* top */
1205 if (NoBorder) {
1206 return;
1209 XDrawLine( dpy, *win, HiInnerGC,
1210 j*BUTTONWIDTH-BUTTONWIDTH, i*BUTTONHEIGHT-BUTTONHEIGHT,
1211 j*BUTTONWIDTH,i*BUTTONHEIGHT-BUTTONHEIGHT);
1213 XDrawLine( dpy, *win, HiInnerGC, j*BUTTONWIDTH-BUTTONWIDTH,
1214 i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH,
1215 i*BUTTONHEIGHT-BUTTONHEIGHT+1);
1217 /* left */
1218 XDrawLine( dpy, *win, HiInnerGC, j*BUTTONWIDTH-BUTTONWIDTH,
1219 i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH-BUTTONWIDTH,
1220 i*BUTTONHEIGHT-1);
1222 XDrawLine( dpy, *win, HiInnerGC, j*BUTTONWIDTH
1223 -BUTTONWIDTH+1, i*BUTTONHEIGHT-BUTTONHEIGHT+2,
1224 j*BUTTONWIDTH-BUTTONWIDTH+1 ,i*BUTTONHEIGHT-1);
1226 /* right */
1227 XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH
1228 +BUTTONWIDTH-2, i*BUTTONHEIGHT-BUTTONHEIGHT+2, j*BUTTONWIDTH
1229 -BUTTONWIDTH+BUTTONWIDTH-2 ,i*BUTTONHEIGHT-1);
1231 XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH
1232 +BUTTONWIDTH-1, i*BUTTONHEIGHT-BUTTONHEIGHT+1,
1233 j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-1 ,i*BUTTONHEIGHT-1);
1235 /* bottom */
1236 XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH
1237 -BUTTONWIDTH+1, i*BUTTONHEIGHT-1, j*BUTTONWIDTH-BUTTONWIDTH
1238 +BUTTONWIDTH-2,i*BUTTONHEIGHT-1);
1240 XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH
1241 +1, i*BUTTONHEIGHT-2, j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-2,
1242 i*BUTTONHEIGHT-2);
1245 void RedrawPushed(Window *win, int i,int j)
1247 if (PushStyle!=0) {
1248 XMoveResizeWindow(dpy, Buttons[CurrentButton].IconWin,
1249 2+(j-1)*BUTTONWIDTH,(i-1)*BUTTONHEIGHT+2,
1250 BUTTONWIDTH-2, BUTTONHEIGHT-2);
1251 } else {
1252 XCopyArea( dpy, Buttons[CurrentButton].completeIcon,
1253 Buttons[CurrentButton].IconWin, NormalGC, 2, 2,
1254 Buttons[BACK_BUTTON].icons[0].w-2,
1255 Buttons[BACK_BUTTON].icons[0].h-2, 4, 4);
1256 XCopyArea( dpy, Buttons[BACK_BUTTON].icons[0].icon,
1257 Buttons[CurrentButton].IconWin, NormalGC, 2, 2,
1258 2, BUTTONHEIGHT, 2, 2);
1259 XCopyArea( dpy, Buttons[BACK_BUTTON].icons[0].icon,
1260 Buttons[CurrentButton].IconWin, NormalGC, 2, 2,
1261 BUTTONWIDTH, 2, 2, 2);
1263 RedrawWindow(win,0, CurrentButton, num_rows, num_columns);
1264 RedrawPushedOutline(win, i,j);
1267 void RedrawPushedOutline(Window *win, int i, int j)
1269 GC gc1;
1270 /* Top Hilite */
1271 XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH,
1272 i*BUTTONHEIGHT-BUTTONHEIGHT, j*BUTTONWIDTH,i*BUTTONHEIGHT
1273 -BUTTONHEIGHT);
1275 XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH,
1276 i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH,i*BUTTONHEIGHT
1277 -BUTTONHEIGHT+1);
1279 /* Left Hilite */
1281 XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH,
1282 i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH-BUTTONWIDTH,
1283 i*BUTTONHEIGHT-1);
1285 XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH
1286 +1, i*BUTTONHEIGHT-BUTTONHEIGHT+2, j*BUTTONWIDTH-BUTTONWIDTH+1,
1287 i*BUTTONHEIGHT-1);
1289 if (PushStyle!=0) {
1290 gc1 = HiReliefGC;
1291 } else {
1292 gc1 = HiInnerGC;
1295 /* Right Hilite */
1297 XDrawLine( dpy, *win, HiReliefGC, j*BUTTONWIDTH
1298 -BUTTONWIDTH+BUTTONWIDTH-2, i*BUTTONHEIGHT-BUTTONHEIGHT+2,
1299 j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-2 ,i*BUTTONHEIGHT-1);
1301 XDrawLine( dpy, *win, gc1, j*BUTTONWIDTH
1302 -BUTTONWIDTH+BUTTONWIDTH-1, i*BUTTONHEIGHT-BUTTONHEIGHT+1,
1303 j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-1 ,i*BUTTONHEIGHT-1);
1305 /* Bottom Hilite */
1306 XDrawLine( dpy, *win, gc1, j*BUTTONWIDTH
1307 -BUTTONWIDTH+1, i*BUTTONHEIGHT-1, j*BUTTONWIDTH-BUTTONWIDTH
1308 +BUTTONWIDTH-2,i*BUTTONHEIGHT-1);
1310 XDrawLine( dpy, *win, HiReliefGC, j*BUTTONWIDTH
1311 -BUTTONWIDTH+1, i*BUTTONHEIGHT-2, j*BUTTONWIDTH-BUTTONWIDTH
1312 +BUTTONWIDTH-2,i*BUTTONHEIGHT-2);
1316 * Draw the window
1319 void RedrawWindow(Window *win, int firstbutton, int newbutton,
1320 int num_rows, int num_columns)
1322 int i,j,button;
1323 XEvent dummy;
1325 if(ready < 1)
1326 return;
1328 while (FCheckTypedWindowEvent(dpy, *win, Expose, &dummy));
1330 for(i=0;i<num_rows;i++)
1331 for(j=0;j<num_columns; j++)
1333 button = firstbutton+i*num_columns + j;
1334 if((newbutton == -1)||(newbutton == button))
1336 if(((Buttons[button].swallow == 3)||
1337 (Buttons[button].swallow == 4))&&
1338 (Buttons[button].IconWin != None))
1339 XSetWindowBorderWidth(dpy,Buttons[button].IconWin,0);
1341 RedrawUnpushedOutline(win,i,j);
1348 * Create GC's
1351 void CreateShadowGC(void)
1353 XGCValues gcv;
1354 unsigned long gcm;
1356 if(Pdepth < 2)
1358 back_pix = GetColor("white");
1359 fore_pix = GetColor("black");
1361 else if (global_colorset >= 0)
1363 fore_pix = Colorset[global_colorset].shadow;
1364 light_grey = Colorset[global_colorset].hilite;
1366 else
1368 if (TextureType>0 && TextureType < 128) {
1369 MakeShadowColors(dpy, FromColor, ToColor, &fore_pix, &light_grey);
1370 } else {
1371 back_pix = GetColor("grey40");
1372 fore_pix = GetColor("grey17");
1373 light_grey = GetColor("white");
1376 gcm = GCForeground|GCBackground|GCSubwindowMode;
1377 gcv.subwindow_mode = IncludeInferiors;
1379 gcv.foreground = fore_pix;
1380 gcv.background = back_pix;
1381 NormalGC = fvwmlib_XCreateGC(dpy, main_win, gcm, &gcv);
1382 gcv.foreground = back_pix;
1383 gcv.background = fore_pix;
1384 HiReliefGC = fvwmlib_XCreateGC(dpy, main_win, gcm, &gcv);
1386 gcv.foreground = light_grey;
1387 gcv.background = fore_pix;
1388 HiInnerGC = fvwmlib_XCreateGC(dpy, main_win, gcm, &gcv);
1390 gcm = GCForeground;
1391 gcv.foreground = fore_pix;
1392 MaskGC = fvwmlib_XCreateGC(dpy, main_win, gcm, &gcv);
1397 * Creates a dummy window of the correct visual for the pixmap creation
1400 void CreateVizWindow(void)
1402 XSetWindowAttributes attr;
1404 if (Pdefault)
1405 main_win = Root;
1406 else {
1407 attr.background_pixel = 0;
1408 attr.border_pixel = 0;
1409 attr.colormap = Pcmap;
1410 main_win = XCreateWindow(dpy,Root,-10,-10,10,10,0,Pdepth,InputOutput,
1411 Pvisual,CWBackPixel|CWBorderPixel|CWColormap,
1412 &attr);
1418 * Sizes and creates the window
1421 void CreateWindow(void)
1423 int first_avail_button,i;
1424 XSetWindowAttributes attr;
1425 int wx = 0;
1426 int wy = 0;
1428 _XA_WM_DEL_WIN = XInternAtom(dpy,"WM_DELETE_WINDOW",False);
1429 _XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False);
1431 /* Allow for multi-width/height buttons */
1432 first_avail_button = num_buttons;
1434 if(num_buttons > MAX_BUTTONS)
1436 fprintf(stderr,"%s: Out of Buttons!\n",MyName);
1437 exit(0);
1440 /* size and create the window */
1441 if((num_rows == 0)&&(num_columns == 0))
1442 num_columns = 1;
1443 if(num_columns == 0)
1445 num_columns = num_buttons/num_rows;
1446 while(num_rows * num_columns < num_buttons)
1447 num_columns++;
1449 if(num_rows == 0)
1451 num_rows = num_buttons/num_columns;
1452 while(num_rows * num_columns < num_buttons)
1453 num_rows++;
1456 while(num_rows * num_columns < num_buttons)
1457 num_columns++;
1459 mysizehints.flags = PWinGravity| PResizeInc | PBaseSize;
1460 /* subtract one for the right/bottom border */
1461 mysizehints.width = BUTTONWIDTH*num_columns;
1462 mysizehints.height= BUTTONHEIGHT*num_rows;
1463 mysizehints.width_inc = BUTTONWIDTH;
1464 mysizehints.height_inc = BUTTONHEIGHT;
1465 mysizehints.base_height = 0;
1466 mysizehints.base_width = 0;
1467 if (x > -100000)
1469 if (flags & XNegative)
1471 wx = DisplayWidth(dpy,screen) + x - mysizehints.width;
1472 gravity = NorthEastGravity;
1474 else
1476 wx = x;
1478 if (flags & YNegative)
1480 wy = DisplayHeight(dpy,screen) + y - mysizehints.height;
1481 gravity = SouthWestGravity;
1483 else
1485 wy = y;
1488 if ((flags & XNegative) && (flags & YNegative))
1490 gravity = SouthEastGravity;
1492 mysizehints.flags |= USPosition;
1495 mysizehints.win_gravity = gravity;
1497 attr.background_pixel = back_pix;
1498 attr.border_pixel = 0;
1499 attr.colormap = Pcmap;
1500 XDestroyWindow(dpy, main_win);
1501 main_win = XCreateWindow(dpy,Root,wx,wy,
1502 mysizehints.width,mysizehints.height,
1503 0,Pdepth,InputOutput,Pvisual,
1504 CWBackPixel|CWBorderPixel|CWColormap,&attr);
1506 for(i=0;i<num_folders;i++)
1508 if(num_columns <num_rows)
1510 Folders[i].cols = 1;
1511 Folders[i].rows = Folders[i].count;
1513 else if ((num_columns == num_rows) && (!ROWS))
1515 Folders[i].cols = 1;
1516 Folders[i].rows = Folders[i].count;
1518 else
1520 Folders[i].cols = Folders[i].count;
1521 Folders[i].rows = 1;
1523 Folders[i].win = XCreateWindow(dpy, Root,0,0,BUTTONWIDTH*Folders[i].rows,
1524 BUTTONHEIGHT*Folders[i].cols,0,Pdepth,
1525 InputOutput,Pvisual,
1526 CWBackPixel|CWBorderPixel|CWColormap,&attr);
1527 /* hack to prevent mapping on wrong screen with StartsOnScreen */
1528 FScreenMangleScreenIntoUSPosHints(FSCREEN_XYPOS, &mysizehints);
1529 XSetWMNormalHints(dpy,Folders[i].win,&mysizehints);
1530 XSelectInput(dpy, Folders[i].win, MW_EVENTS);
1533 XSetWMProtocols(dpy,main_win, &_XA_WM_DEL_WIN, 1);
1535 XSetWMNormalHints(dpy,main_win,&mysizehints);
1537 XSelectInput(dpy, main_win, MW_EVENTS);
1538 change_window_name(MyName);
1543 * Dead pipe handler
1546 RETSIGTYPE DeadPipe(int nonsense)
1548 int i,j,button;
1550 #ifdef ENABLE_SOUND
1551 int val=-1;
1552 write(PlayerChannel[1],&val,sizeof(val));
1553 if (SoundThread != 0)
1554 kill(SoundThread,SIGUSR1);
1555 #endif
1556 for(i=0;i<num_rows;i++)
1557 for(j=0;j<num_columns; j++)
1559 button = i*num_columns + j;
1560 /* delete swallowed windows, but not modules
1561 (afterstep handles those) */
1562 if(((Buttons[button].swallow == 3)||(Buttons[button].swallow == 4))&&
1563 (Buttons[button].module == 0))
1565 my_send_clientmessage(Buttons[button].IconWin, _XA_WM_DEL_WIN,
1566 CurrentTime);
1567 XSync(dpy,0);
1570 XSync(dpy,0);
1571 exit(0);
1573 SIGNAL_RETURN;
1576 int TOTHEFOLDER = -1;
1579 * This routine is responsible for reading and parsing the config file
1582 void ParseOptions(char *filename)
1584 char *tline,*orig_tline,*tmp;
1585 int Clength, len;
1587 InitGetConfigLine(fd,CatString3("*", MyName, 0)); /* speedup */
1588 GetConfigLine(fd, &tline);
1589 orig_tline = tline;
1590 Clength = strlen(MyName);
1591 while(tline != NULL && tline[0] != '\0')
1593 int g_x, g_y;
1594 unsigned width,height;
1595 while(isspace(*tline))tline++;
1597 if(strlen(&tline[0]) <= 0)
1599 GetConfigLine(fd, &tline);
1600 orig_tline = tline;
1601 continue;
1604 if((strncasecmp(tline,CatString3("*", MyName, "Geometry"),Clength+9)==0))
1606 w= -1;
1607 h= -1;
1608 x= -100000;
1609 y= -100000;
1610 tmp = &tline[Clength+9];
1611 while(((isspace(*tmp))&&(*tmp != '\n'))&&(*tmp != 0))
1613 tmp++;
1615 if (strlen(tmp) > 0)
1617 if (isspace(tmp[strlen(tmp)-1]))
1618 tmp[strlen(tmp)-1] = 0;
1620 flags = FScreenParseGeometry(tmp,&g_x,&g_y,&width,&height);
1621 if (flags & WidthValue)
1622 w = width;
1623 if (flags & HeightValue)
1624 h = height;
1625 if (flags & XValue)
1626 x = g_x;
1627 if (flags & YValue)
1628 y = g_y;
1631 else if((strncasecmp(tline,CatString3("*",MyName,"Rows"),Clength+5)==0))
1633 len=sscanf(&tline[Clength+5],"%d",&num_rows);
1634 if(len < 1)
1635 num_rows = 0;
1636 ROWS = True;
1638 else if((strncasecmp(tline,CatString3("*",MyName,"Columns"),Clength+8)==0))
1640 len=sscanf(&tline[Clength+8],"%d",&num_columns);
1641 if(len < 1)
1642 num_columns = 0;
1643 ROWS = False;
1645 else if((strncasecmp(tline,CatString3("*",MyName,"NoPush"),Clength+5)==0))
1647 Pushable = 0;
1649 else if((strncasecmp(tline,CatString3("*",MyName,"FullPush"),
1650 Clength+9)==0))
1652 PushStyle = 1;
1654 else if((strncasecmp(tline,CatString3("*",MyName,"NoBorder"),
1655 Clength+9)==0))
1657 NoBorder = 1;
1659 else if ((strncasecmp(tline,CatString3("*",MyName,"ForceSize"),
1660 Clength+10)==0)) {
1661 ForceSize = 1;
1663 else if ((strncasecmp(tline,CatString3("*",MyName,"TextureType"),
1664 Clength+12)==0)) {
1665 if (sscanf(&tline[Clength+12],"%d",&TextureType) >= 1)
1667 /* disable colorset */
1668 global_colorset = -1;
1670 else
1672 TextureType = TEXTURE_BUILTIN;
1675 else if ((strncasecmp(tline,CatString3("*",MyName,"MaxColors"),
1676 Clength+10)==0)) {
1678 if (sscanf(&tline[Clength+10],"%d",&MaxColors)<1)
1679 MaxColors = 16;
1681 else if ((strncasecmp(tline,CatString3("*",MyName,"BgColor"),
1682 Clength+8)==0)) {
1683 char *tmp;
1684 tmp=safemalloc(strlen(tline));
1685 if (sscanf(&tline[Clength+8],"%s",tmp) == 1)
1687 /* disable colorset */
1688 global_colorset = -1;
1690 BgColor=GetColor(tmp);
1691 free(tmp);
1693 else if ((strncasecmp(tline,CatString3("*",MyName,"TextureColor"),
1694 Clength+13)==0)) {
1695 char *c1, *c2;
1696 XColor color;
1698 len = strlen(&tline[Clength+13]);
1699 c1 = safemalloc(len);
1700 c2 = safemalloc(len);
1701 if (sscanf(&tline[Clength+13],"%s %s",c1,c2)!=2) {
1702 fprintf(stderr, "%s:You must specify two colors for the texture\n",
1703 MyName);
1704 FromColor[0]=0;
1705 FromColor[1]=0;
1706 FromColor[2]=0;
1707 ToColor[0]=0;
1708 ToColor[1]=0;
1709 ToColor[2]=0;
1711 if (!XParseColor (dpy, Pcmap, c1, &color))
1713 fprintf(stderr, "Cannot parse %s\n", c1);
1714 TextureType=TEXTURE_BUILTIN;
1715 } else {
1716 FromColor[0]=color.red;
1717 FromColor[1]=color.green;
1718 FromColor[2]=color.blue;
1719 /* disable colorset */
1720 global_colorset = -1;
1722 if (!XParseColor (dpy, Pcmap, c2, &color))
1724 fprintf(stderr, "Cannot parse %s\n", c2);
1725 TextureType=TEXTURE_BUILTIN;
1726 } else {
1727 ToColor[0]=color.red;
1728 ToColor[1]=color.green;
1729 ToColor[2]=color.blue;
1730 /* disable colorset */
1731 global_colorset = -1;
1733 free(c1);
1734 free(c2);
1736 else if ((strncasecmp(tline,CatString3("*",MyName,"Pixmap"),
1737 Clength+7)==0)) {
1738 CopyString(&BgPixmapFile,&tline[Clength+7]);
1740 else if((strncasecmp(tline,CatString3("*",MyName,"AnimateMain"),
1741 Clength+12)==0))
1743 AnimateMain = 1;
1745 else if((strncasecmp(tline,CatString3("*",MyName,"Animate"),Clength+8)==0))
1747 if ((tline[Clength+9]!='M') && (tline[Clength+9]!='m'))
1748 AnimationStyle = 1;
1750 else if((strncasecmp(
1751 tline,CatString3("*",MyName,"Colorset"),Clength+9)==0))
1753 global_colorset = -1;
1754 sscanf(&(tline[Clength + 9]), "%d", &global_colorset);
1755 AllocColorset(global_colorset);
1756 if (global_colorset < 0)
1758 global_colorset = -1;
1759 TextureType=TEXTURE_BUILTIN;
1761 else
1763 /* disable texture, if any */
1764 TextureType=TEXTURE_COLORSET;
1765 if (BgPixmapFile)
1767 free(BgPixmapFile);
1768 BgPixmapFile = NULL;
1772 #ifdef ENABLE_SOUND
1773 else if((strncasecmp(tline,CatString3("*",MyName,"Player"),Clength+7)==0))
1775 CopyString(&SoundPlayer, &tline[Clength+7]);
1777 else if((strncasecmp(tline,CatString3("*",MyName,"Sound"),Clength+6)==0))
1779 bind_sound(&tline[Clength+6]);
1780 SoundActive = 1;
1782 #endif
1783 else if((strncasecmp(tline,CatString3("*", MyName, ""),Clength+1)==0)
1784 && (num_buttons < MAX_BUTTONS))
1786 /* check if this is a invalid option */
1787 if (!isspace(tline[Clength+1]))
1788 fprintf(stderr,"%s:invalid option %s\n",MyName,tline);
1789 else
1790 match_string(&tline[Clength+1]);
1792 else if((strncasecmp(tline,"ImagePath",9)==0))
1794 CopyString(&imagePath,&tline[9]);
1796 #ifdef ENABLE_SOUND
1797 else if((strncasecmp(tline,"*AudioDir",9)==0))
1799 CopyString(&SoundPath,&tline[9]);
1801 else if((strncasecmp(tline,"ModulePath",11)==0))
1803 CopyString(&ModulePath,&tline[11]);
1805 #endif
1806 else if((strncasecmp(tline,"Colorset",8)==0))
1808 /* store colorset sent by fvwm */
1809 LoadColorset(&(tline[8]));
1811 else if((strncasecmp(tline, XINERAMA_CONFIG_STRING,
1812 sizeof(XINERAMA_CONFIG_STRING) - 1)==0))
1814 FScreenConfigureModule(
1815 tline + sizeof(XINERAMA_CONFIG_STRING) - 1);
1817 GetConfigLine(fd, &tline);
1818 orig_tline = tline;
1819 } /* while */
1820 #ifdef ENABLE_DND
1821 /* ignore last button if there's nothing bound to it */
1822 if ((Buttons[num_buttons-1].drop_action!=NULL) &&
1823 (Buttons[num_buttons-1].iconno==0)) {
1824 num_buttons--;
1826 #endif
1827 return;
1831 * Gets a word of a given index in the line, stripping any blanks
1832 * The returned word is newly allocated
1834 #ifdef ENABLE_SOUND
1835 char *get_token(char *tline, int index)
1837 char *start, *end;
1838 int i,c,size;
1839 char *word;
1841 index++; /* index is 0 based */
1842 size = strlen(tline);
1843 i=c=0;
1844 start=end=tline;
1845 while (i<index && c<size) {
1846 start=end;
1847 while(isspace(*start) && c<size) {
1848 start++;
1849 c++;
1851 end=start;
1852 while(!isspace(*end) && c<size) {
1853 end++;
1854 c++;
1856 if (end==start) return NULL;
1857 i++;
1859 if (i<index) return NULL;
1860 word=safemalloc(end-start+1);
1861 strncpy(word, start, end-start);
1862 word[end-start]=0;
1863 return word;
1868 * Parses a sound binding
1871 void bind_sound(char *tline)
1873 char *event, *sound;
1875 event = get_token(tline,0);
1876 if (event==NULL) {
1877 fprintf(stderr,"%s:bad sound binding %s\n",MyName,tline);
1878 return;
1880 sound = get_token(tline,1);
1881 if (sound==NULL) {
1882 free(event);
1883 fprintf(stderr,"%s:bad sound binding %s\n",MyName,tline);
1884 return;
1886 if (strcmp(event,"open_folder")==0) {
1887 Sounds[WHEV_OPEN_FOLDER]=sound;
1888 } else if (strcmp(event,"close_folder")==0) {
1889 Sounds[WHEV_CLOSE_FOLDER]=sound;
1890 } else if (strcmp(event,"open_main")==0) {
1891 Sounds[WHEV_OPEN_MAIN]=sound;
1892 } else if (strcmp(event,"close_main")==0) {
1893 Sounds[WHEV_CLOSE_MAIN]=sound;
1894 } else if (strcmp(event,"push")==0) {
1895 Sounds[WHEV_PUSH]=sound;
1896 } else if (strcmp(event,"drop")==0) {
1897 Sounds[WHEV_DROP]=sound;
1898 } else {
1899 fprintf(stderr,"%s:bad event %s in sound binding\n",MyName,event);
1900 free(sound);
1902 free(event);
1903 return;
1905 #endif /* ENABLE_SOUND */
1909 * Parses a button command line from the config file
1912 void match_string(char *tline)
1914 int len,i,i2,n,j,k;
1915 char *ptr,*start,*end,*tmp;
1916 struct button_info *actual;
1918 /* skip spaces */
1919 while(isspace(*tline)&&(*tline != '\n')&&(*tline != 0))
1920 tline++;
1922 /* read next word. Its the button label. Users can specify ""
1923 * NoIcon, or whatever to skip the label */
1924 /* read to next space */
1925 start = tline;
1926 end = tline;
1927 while((!isspace(*end))&&(*end!='\n')&&(*end!=0))
1928 end++;
1929 len = end - start;
1930 ptr = safemalloc(len+1);
1931 strncpy(ptr,start,len);
1932 ptr[len] = 0;
1934 if (strncmp(ptr,"~Folder",7)==0)
1936 TOTHEFOLDER = -1;
1937 Folders[num_folders].firstbutton = num_folderbuttons;
1938 num_folders++;
1939 free(ptr);
1940 return;
1943 if(TOTHEFOLDER==-1)
1945 actual = &Buttons[num_buttons++];
1946 actual->parent = &main_win;
1948 else
1950 actual = &Buttons[--num_folderbuttons];
1951 actual->folder = num_folders;
1952 actual->parent = &Folders[num_folders].win;
1955 actual->title = ptr;
1957 /* read next word. Its the icon bitmap/pixmap label. Users can specify ""
1958 * NoIcon, or whatever to skip the label */
1959 /* read to next space */
1960 start = end;
1961 /* skip spaces */
1962 while(isspace(*start)&&(*start != '\n')&&(*start != 0))
1963 start++;
1964 end = start;
1965 while((!isspace(*end))&&(*end!='\n')&&(*end!=0))
1966 end++;
1967 len = end - start;
1968 ptr = safemalloc(len+1);
1969 strncpy(ptr,start,len);
1970 ptr[len] = 0;
1971 /* separate icon files to be overlaid */
1972 i2 = len;
1973 j=k=0;
1974 for(i=0;i<MAX_OVERLAY;i++) {
1975 while (ptr[j]!=',' && j<i2) j++;
1976 actual->icons[i].file=safemalloc(j-k+1);
1977 strncpy(actual->icons[i].file,&(ptr[k]),j-k);
1978 actual->icons[i].file[j-k]=0;
1979 actual->iconno++;
1980 j++;
1981 k=j;
1982 if (j>=i2) break;
1984 tline = end;
1985 for (i=num_buttons - 2;i>=0;i--)
1987 if (strcmp(Buttons[i].title, actual->title) == 0)
1989 actual = &Buttons[i];
1990 num_buttons--;
1991 for(i=0;i<actual->iconno;i++) {
1992 free(actual->icons[i].file);
1994 break;
1997 /* skip spaces */
1998 while(isspace(*tline)&&(*tline != '\n')&&(*tline != 0))
1999 tline++;
2000 #ifdef ENABLE_DND
2001 if (strncasecmp(tline,"dropexec",8)==0) {
2002 /* get command to execute for dropped stuff */
2004 if(TOTHEFOLDER==-1) {
2005 num_buttons--; /* make the next parsed thing the button for this */
2006 free(ptr);
2007 for(i=0;i<actual->iconno;i++) {
2008 free(actual->icons[i].file);
2010 actual->iconno=0;
2011 } else {
2012 num_folderbuttons++;
2013 free(ptr);
2014 for(i=0;i<actual->iconno;i++) {
2015 free(actual->icons[i].file);
2017 actual->iconno=0;
2018 fprintf(stderr,"Drop in Folders not supported. Ignoring option\n");
2019 return;
2022 tline=strstr(tline,"Exec");
2023 len = strlen(tline);
2024 tmp = tline + len -1;
2025 while(((isspace(*tmp))||(*tmp == '\n'))&&(tmp >=tline)) {
2026 tmp--;
2027 len--;
2029 ptr = safemalloc(len+1);
2030 actual->drop_action=ptr;
2031 strncpy(ptr,tline,len);
2032 ptr[len]=0;
2033 } else
2034 #endif
2035 if(strncasecmp(tline,"swallow",7)==0 ||
2036 strncasecmp(tline,"maxswallow",10)==0)
2038 /* Look for swallow "identifier", in which
2039 case Wharf spawns and gobbles up window */
2040 i=7;
2041 while((tline[i] != 0)&&
2042 (tline[i] != '"'))
2043 i++;
2044 i2=i+1;
2045 while((tline[i2] != 0)&&
2046 (tline[i2] != '"'))
2047 i2++;
2048 actual->maxsize =
2049 strncasecmp(tline,"maxswallow",10) == 0 ? 1 : 0;
2050 if(i2 - i >1)
2052 actual->hangon = safemalloc(i2-i);
2053 strncpy(actual->hangon,&tline[i+1],i2-i-1);
2054 actual->hangon[i2-i-1] = 0;
2055 actual->swallow = 1;
2057 n = 7;
2058 n = i2+1;
2059 while((isspace(tline[n]))&&(tline[n]!=0))
2060 n++;
2061 len = strlen(&tline[n]);
2062 tmp = tline + n + len -1;
2063 while(((isspace(*tmp))||(*tmp == '\n'))&&(tmp >=(tline + n)))
2065 tmp--;
2066 len--;
2068 ptr = safemalloc(len+6);
2069 if(strncasecmp(&tline[n],"Module",6)==0)
2071 ptr[0] = 0;
2072 actual->module = 1;
2074 else
2075 strcpy(ptr,"Exec ");
2076 i2 = strlen(ptr);
2077 strncat(ptr,&tline[n],len);
2078 ptr[i2+len]=0;
2079 SendText(fd,ptr,0);
2080 free(ptr);
2081 actual->action = NULL;
2083 else
2085 if(!TOTHEFOLDER)
2087 Folders[num_folders].count++;
2090 len = strlen(tline);
2091 tmp = tline + len -1;
2092 while(((isspace(*tmp))||(*tmp == '\n'))&&(tmp >=tline))
2094 tmp--;
2095 len--;
2097 ptr = safemalloc(len+1);
2098 strncpy(ptr,tline,len);
2099 ptr[len]=0;
2101 if (strncmp(ptr,"Folder",6)==0)
2103 TOTHEFOLDER = 0;
2104 Folders[num_folders].count = 0;
2105 actual->folder = num_folders;
2106 Folders[num_folders].mapped = NOTMAPPED;
2108 actual->action = ptr;
2110 return;
2114 * Change the window name displayed in the title bar.
2116 void change_window_name(char *str)
2118 XTextProperty name;
2119 XClassHint myclasshints;
2120 int i;
2122 if (XStringListToTextProperty(&str,1,&name) == 0)
2124 fprintf(stderr,"%s: cannot allocate window name\n",MyName);
2125 return;
2127 XSetWMName(dpy,main_win,&name);
2128 XSetWMIconName(dpy,main_win,&name);
2129 for(i=0;i<num_folders;i++)
2131 XSetWMName(dpy, Folders[i].win,&name);
2132 XSetWMIconName(dpy, Folders[i].win,&name);
2134 XFree(name.value);
2135 myclasshints.res_name = str;
2136 myclasshints.res_class = "FvwmWharf";
2137 XSetClassHint(dpy,main_win,&myclasshints);
2144 * Waits for next X event, or for an auto-raise timeout.
2147 int My_XNextEvent(Display *dpy, XEvent *event)
2149 fd_set in_fdset;
2150 static int miss_counter = 0;
2152 if(FPending(dpy))
2154 FNextEvent(dpy,event);
2155 return 1;
2158 FD_ZERO(&in_fdset);
2159 FD_SET(x_fd,&in_fdset);
2160 FD_SET(fd[1],&in_fdset);
2162 select( fd_width, SELECT_FD_SET_CAST &in_fdset, 0, 0, NULL );
2165 if(FD_ISSET(x_fd, &in_fdset))
2167 if(FPending(dpy))
2169 FNextEvent(dpy,event);
2170 miss_counter = 0;
2171 return 1;
2173 else
2174 miss_counter++;
2175 if(miss_counter > 100)
2176 DeadPipe(0);
2179 if(FD_ISSET(fd[1], &in_fdset))
2181 FvwmPacket* packet = ReadFvwmPacket(fd[1]);
2182 if ( packet == NULL )
2183 DeadPipe(0);
2184 else
2185 process_message( packet->type, packet->body );
2187 return 0;
2190 void CheckForHangon(unsigned long *body)
2192 int button,i,j;
2193 char *cbody;
2195 cbody = (char *)&body[3];
2196 for(i=0;i<num_rows;i++)
2197 for(j=0;j<num_columns; j++)
2199 button = i*num_columns + j;
2200 if(Buttons[button].hangon != NULL)
2202 if(strcmp(cbody,Buttons[button].hangon)==0)
2204 if(Buttons[button].swallow == 1)
2206 Buttons[button].swallow = 2;
2207 if(Buttons[button].IconWin != None)
2209 XDestroyWindow(dpy,Buttons[button].IconWin);
2211 Buttons[button].IconWin = (Window)body[0];
2212 free(Buttons[button].hangon);
2213 Buttons[button].hangon = NULL;
2215 else
2217 if (Buttons[button].swallow == 4)
2218 Buttons[button].swallow = 3;
2219 Buttons[button].up = 1;
2220 free(Buttons[button].hangon);
2221 Buttons[button].hangon = NULL;
2222 RedrawWindow(&main_win,0, button, num_rows, num_columns);
2229 static void configure_all_icon_windows(void)
2231 int i;
2232 int j;
2233 int button;
2235 for(i=0;i<num_rows;i++)
2236 for(j=0;j<num_columns; j++)
2238 button = i*num_columns + j;
2239 ConfigureIconWindow(button,i,j,global_colorset);
2241 for(i=0;i<num_folders;i++)
2242 for(j=0;j<Folders[i].count;j++)
2243 if(num_columns < num_rows) {
2244 ConfigureIconWindow(Folders[i].firstbutton+j,0, j, global_colorset);
2245 } else {
2246 ConfigureIconWindow(Folders[i].firstbutton+j,j, 0, global_colorset);
2248 /* dirty hack to make swallowed app background be textured */
2249 XSetWindowBackgroundPixmap(
2250 dpy, main_win, Buttons[BACK_BUTTON].icons[0].icon);
2253 static void change_colorset(int colorset)
2255 if (colorset != global_colorset || colorset < 0)
2257 return;
2260 BgColor = Colorset[global_colorset].bg;
2261 /* update GCs */
2262 XFreeGC(dpy, NormalGC);
2263 XFreeGC(dpy, HiReliefGC);
2264 XFreeGC(dpy, HiInnerGC);
2265 XFreeGC(dpy, MaskGC);
2266 CreateShadowGC();
2267 /* update background pixmap */
2268 GetXPMColorset(BACK_BUTTON, global_colorset);
2269 /* activate changes */
2270 configure_all_icon_windows();
2271 for (x = 0; x < num_folders; x++)
2273 XClearWindow(dpy, Folders[x].win);
2274 RedrawWindow(&Folders[x].win,num_folderbuttons, -1,
2275 Folders[x].cols, Folders[x].rows);
2276 for(y = 1; y <= Folders[x].count; y++)
2278 if(num_columns < num_rows)
2279 RedrawUnpushedOutline(&Folders[x].win, 1, y);
2280 else
2281 RedrawUnpushedOutline(&Folders[x].win, y, 1);
2284 XClearWindow(dpy, main_win);
2285 RedrawWindow(&main_win,0, -1, num_rows, num_columns);
2286 XSync(dpy, 0);
2288 return;
2291 static void handle_config_info_packet(unsigned long *body)
2293 char *tline, *token;
2294 int colorset;
2296 tline = (char*)&(body[3]);
2297 token = PeekToken(tline, &tline);
2298 if (StrEquals(token, "Colorset"))
2300 colorset = LoadColorset(tline);
2301 change_colorset(colorset);
2303 else if (StrEquals(token, XINERAMA_CONFIG_STRING))
2305 FScreenConfigureModule(tline);
2308 return;
2314 * Process window list messages
2317 void process_message(unsigned long type,unsigned long *body)
2319 switch(type)
2321 /* case M_TOGGLE_PAGING:
2322 pageing_enabled = body[0];
2323 RedrawWindow(&main_win,0, -1, num_rows, num_columns);
2324 break;
2325 pdg */
2326 case M_NEW_DESK:
2327 new_desk = body[0];
2328 RedrawWindow(&main_win,0, -1, num_rows, num_columns);
2329 break;
2330 case M_END_WINDOWLIST:
2331 RedrawWindow(&main_win,0, -1, num_rows, num_columns);
2332 case M_MAP:
2333 swallow(body);
2334 case M_RES_NAME:
2335 case M_RES_CLASS:
2336 case M_WINDOW_NAME:
2337 CheckForHangon(body);
2338 break;
2339 case M_CONFIG_INFO:
2340 handle_config_info_packet((unsigned long*)body);
2341 break;
2342 default:
2343 break;
2353 * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all
2354 * client messages will have the following form:
2356 * event type ClientMessage
2357 * message type _XA_WM_PROTOCOLS
2358 * window tmp->w
2359 * format 32
2360 * data[0] message atom
2361 * data[1] time stamp
2364 void my_send_clientmessage (Window w, Atom a, Time timestamp)
2366 XClientMessageEvent ev;
2368 ev.type = ClientMessage;
2369 ev.window = w;
2370 ev.message_type = _XA_WM_PROTOCOLS;
2371 ev.format = 32;
2372 ev.data.l[0] = a;
2373 ev.data.l[1] = timestamp;
2374 FSendEvent(dpy, w, False, 0L, (XEvent *) &ev);
2378 void swallow(unsigned long *body)
2380 char *temp;
2381 int button,i,j;
2382 long supplied;
2384 for(i=0;i<num_rows;i++)
2386 for(j=0;j<num_columns; j++)
2388 button = i*num_columns + j;
2389 if((Buttons[button].IconWin == (Window)body[0])&&
2390 (Buttons[button].swallow == 2))
2392 Buttons[button].swallow = 3;
2393 /* "Swallow" the window! */
2395 XReparentWindow(dpy,Buttons[button].IconWin, main_win,
2396 j*BUTTONWIDTH+4, i*BUTTONHEIGHT+4);
2397 XMapWindow(dpy,Buttons[button].IconWin);
2398 XSelectInput(dpy,(Window)body[0],
2399 PropertyChangeMask);
2400 if (Buttons[button].action)
2403 XGrabButton(dpy, Button1Mask | Button2Mask, None,
2404 (Window)body[0],
2405 False, ButtonPressMask | ButtonReleaseMask,
2406 GrabModeAsync, GrabModeAsync, None, None);
2407 XGrabButton(dpy, Button1Mask | Button2Mask, LockMask,
2409 unsigned *mods = lock_mods;
2410 do XGrabButton(dpy, Button1Mask | Button2Mask, *mods,
2412 (Window)body[0],
2413 False, ButtonPressMask | ButtonReleaseMask,
2414 GrabModeAsync, GrabModeAsync, None, None);
2415 while (*mods++);
2418 if (Buttons[button].maxsize) {
2419 unsigned int width, height;
2420 int junk1, junk2;
2421 unsigned int junk3, junk4;
2422 Window root;
2423 if (XGetGeometry(dpy, Buttons[button].IconWin, &root,
2424 &junk1, &junk2, &width, &height, &junk3,
2425 &junk4))
2427 if (width > BUTTONWIDTH)
2428 width = BUTTONWIDTH;
2429 if (height > BUTTONHEIGHT)
2430 height = BUTTONHEIGHT;
2432 else
2434 width = BUTTONWIDTH;
2435 height = BUTTONHEIGHT;
2437 Buttons[button].icons[0].w = width;
2438 Buttons[button].icons[0].h = height;
2440 else {
2441 Buttons[button].icons[0].w = ICON_WIN_WIDTH;
2442 Buttons[button].icons[0].h = ICON_WIN_HEIGHT;
2444 if (!XGetWMNormalHints (dpy, Buttons[button].IconWin,
2445 &Buttons[button].hints,
2446 &supplied))
2448 Buttons[button].hints.flags = 0;
2451 XResizeWindow(dpy,(Window)body[0], Buttons[button].icons[0].w,
2452 Buttons[button].icons[0].h);
2453 XMoveWindow(dpy,Buttons[button].IconWin,
2454 j*BUTTONWIDTH +
2455 (BUTTONWIDTH - Buttons[button].icons[0].w)/2,
2456 i*BUTTONHEIGHT +
2457 (BUTTONHEIGHT - Buttons[button].icons[0].h)/2);
2459 if (XFetchName(dpy, Buttons[button].IconWin, &temp))
2461 if(strcmp(Buttons[button].title,"-")!=0)
2462 CopyString(&Buttons[button].title, temp);
2464 else
2466 CopyString(&Buttons[button].title, "");
2468 XClearArea(dpy, main_win,j*BUTTONWIDTH, i*BUTTONHEIGHT,
2469 BUTTONWIDTH,BUTTONHEIGHT,0);
2470 RedrawWindow(&main_win,0, -1, num_rows, num_columns);
2471 XFree(temp);
2479 void FindLockMods(void)
2481 int m, i, knl;
2482 char* kn;
2483 KeySym ks;
2484 KeyCode kc, *kp;
2485 unsigned lockmask, *mp;
2486 XModifierKeymap* mm = XGetModifierMapping(dpy);
2487 lockmask = LockMask;
2488 if (mm)
2490 kp = mm->modifiermap;
2491 for (m = 0; m < 8; m++)
2493 for (i = 0; i < mm->max_keypermod; i++)
2495 if ((kc = *kp++) &&
2496 ((ks = XKeycodeToKeysym(dpy, kc, 0)) != NoSymbol))
2498 kn = XKeysymToString(ks);
2499 knl = strlen(kn);
2500 if ((knl > 6) && (strcasecmp(kn + knl - 4, "lock") == 0))
2501 lockmask |= (1 << m);
2505 XFreeModifiermap(mm);
2507 lockmask &= ~(ShiftMask | ControlMask);
2509 mp = lock_mods;
2510 for (m = 0, i = 1; i < 256; i++)
2512 if ((i & lockmask) > m)
2513 m = *mp++ = (i & lockmask);
2515 *mp = 0;
2521 * Procedure:
2522 * ConstrainSize - adjust the given width and height to account for the
2523 * constraints imposed by size hints
2525 * The general algorithm, especially the aspect ratio stuff, is
2526 * borrowed from uwm's CheckConsistency routine.
2529 void ConstrainSize (XSizeHints *hints, int *widthp, int *heightp)
2531 #define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) )
2532 #define _min(a,b) (((a) < (b)) ? (a) : (b))
2535 int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta;
2536 int baseWidth, baseHeight;
2537 int dwidth = *widthp, dheight = *heightp;
2539 if(hints->flags & PMinSize)
2541 minWidth = hints->min_width;
2542 minHeight = hints->min_height;
2543 if(hints->flags & PBaseSize)
2545 baseWidth = hints->base_width;
2546 baseHeight = hints->base_height;
2548 else
2550 baseWidth = hints->min_width;
2551 baseHeight = hints->min_height;
2554 else if(hints->flags & PBaseSize)
2556 minWidth = hints->base_width;
2557 minHeight = hints->base_height;
2558 baseWidth = hints->base_width;
2559 baseHeight = hints->base_height;
2561 else
2563 minWidth = 1;
2564 minHeight = 1;
2565 baseWidth = 1;
2566 baseHeight = 1;
2569 if(hints->flags & PMaxSize)
2571 maxWidth = hints->max_width;
2572 maxHeight = hints->max_height;
2574 else
2576 maxWidth = 10000;
2577 maxHeight = 10000;
2579 if(hints->flags & PResizeInc)
2581 xinc = hints->width_inc;
2582 yinc = hints->height_inc;
2584 else
2586 xinc = 1;
2587 yinc = 1;
2591 * First, clamp to min and max values
2593 if (dwidth < minWidth) dwidth = minWidth;
2594 if (dheight < minHeight) dheight = minHeight;
2596 if (dwidth > maxWidth) dwidth = maxWidth;
2597 if (dheight > maxHeight) dheight = maxHeight;
2601 * Second, fit to base + N * inc
2603 dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth;
2604 dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight;
2608 * Third, adjust for aspect ratio
2610 #define maxAspectX hints->max_aspect.x
2611 #define maxAspectY hints->max_aspect.y
2612 #define minAspectX hints->min_aspect.x
2613 #define minAspectY hints->min_aspect.y
2615 * The math looks like this:
2617 * minAspectX dwidth maxAspectX
2618 * ---------- <= ------- <= ----------
2619 * minAspectY dheight maxAspectY
2621 * If that is multiplied out, then the width and height are
2622 * invalid in the following situations:
2624 * minAspectX * dheight > minAspectY * dwidth
2625 * maxAspectX * dheight < maxAspectY * dwidth
2629 if (hints->flags & PAspect)
2631 if (minAspectX * dheight > minAspectY * dwidth)
2633 delta = makemult(minAspectX * dheight / minAspectY - dwidth,
2634 xinc);
2635 if (dwidth + delta <= maxWidth)
2636 dwidth += delta;
2637 else
2639 delta = makemult(dheight - dwidth*minAspectY/minAspectX,
2640 yinc);
2641 if (dheight - delta >= minHeight) dheight -= delta;
2645 if (maxAspectX * dheight < maxAspectY * dwidth)
2647 delta = makemult(dwidth * maxAspectY / maxAspectX - dheight,
2648 yinc);
2649 if (dheight + delta <= maxHeight)
2650 dheight += delta;
2651 else
2653 delta = makemult(dwidth - maxAspectX*dheight/maxAspectY,
2654 xinc);
2655 if (dwidth - delta >= minWidth) dwidth -= delta;
2660 *widthp = dwidth;
2661 *heightp = dheight;
2662 return;
2666 #ifdef ENABLE_SOUND
2667 void PlaySound(int event)
2669 int timestamp;
2671 if (!SoundActive)
2672 return;
2673 if (Sounds[event]==NULL) return;
2674 write(PlayerChannel[1],&event,sizeof(event));
2675 timestamp = clock();
2676 write(PlayerChannel[1],&timestamp,sizeof(timestamp));
2678 kill(SoundThread,SIGUSR1);
2681 #endif