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
22 * withdraw on button2 click
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
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
55 #ifdef HAVE_SYS_BSDTYPES_H
56 #include <sys/bsdtypes.h> /* Saul */
63 #include "libs/ftime.h"
66 #include <sys/select.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"
84 #include <X11/Xutil.h>
85 #include <X11/Xproto.h>
86 #include <X11/Xatom.h>
87 #include <X11/Intrinsic.h>
92 /*#include "afterstep/asbuttons.h" pdg */
95 #include "OffiX/DragAndDrop.h"
96 #include "OffiX/DragAndDropTypes.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
110 #define WHEV_CLOSE_FOLDER 1
111 #define WHEV_OPEN_FOLDER 2
112 #define WHEV_CLOSE_MAIN 3
113 #define WHEV_OPEN_MAIN 4
118 char *Sounds
[6]={".",".",".",".",".","."};
119 char *SoundPlayer
=NULL
;
123 int PlayerChannel
[2];
125 /*char *ModulePath=AFTERDIR; pdg */
132 fd_set_size_t fd_width
;
144 Pixel light_grey
= 0;
145 GC NormalGC
, HiReliefGC
, HiInnerGC
;
148 int AnimationStyle
=0,AnimateMain
=0;
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
;
160 int num_folderbuttons
= MAX_BUTTONS
;
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
;
168 int pageing_enabled
= 1;
171 int CurrentButton
= -1;
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
;
186 int TextureType
=TEXTURE_BUILTIN
;
187 char *BgPixmapFile
=NULL
;
188 int FromColor
[3]={0x4000,0x4000,0x4000}, ToColor
[3]={0x8000,0x8000,0x8000};
192 static int global_colorset
= -1;
195 #define DIR_TORIGHT 2
200 void waitchild(int bullshit
)
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
)
220 PrintXErrorAndCoredump(dpy
, event
, MyName
);
228 * main - start of afterstep
231 int main(int argc
, char **argv
)
233 char *display_name
= NULL
;
236 int x
,y
,border_width
;
241 s
=strrchr(argv
[0], '/');
245 MyName
= safemalloc(strlen(temp
)+1);
246 strcpy(MyName
, temp
);
248 for(i
=0;i
<BUTTON_ARRAY_LN
;i
++)
251 Buttons
[i
].drop_action
= NULL
;
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",
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
));
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
);
298 fprintf(stderr
,"%s: Screen %d is not valid\n", MyName
, screen
);
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
|
308 sprintf(set_mask_mesg,"SET_MASK %lu\n",
309 (unsigned long)(M_NEW_DESK |
316 SendText(fd,set_mask_mesg,0);
319 /* create a temporary window of the correct visual for the pixmaps */
322 ParseOptions(argv
[3]);
325 fprintf(stderr
,"%s: No Buttons defined. Quitting\n", MyName
);
330 /* startup sound subsystem */
332 if (pipe(PlayerChannel
)<0) {
333 fprintf(stderr
,"%s: could not create pipe. Disabling sound\n");
336 signal(SIGCHLD
,waitchild
);
339 fprintf(stderr
,"%s: could not fork(). Disabling sound\n", MyName
);
342 } else if (SoundThread
==0) { /* in the sound player process */
343 char *margv
[9], *name
;
347 name
= findImageFile("ASSound",ModulePath
,X_OK
);
349 fprintf(stderr
,"Wharf: couldn't find ASSound\n");
352 margv
[1]=safemalloc(16);
353 close(PlayerChannel
[1]);
354 sprintf(margv
[1],"%x",PlayerChannel
[0]);
355 if (SoundPlayer
!=NULL
)
356 margv
[2]=SoundPlayer
;
359 for(i
=0;i
<MAX_EVENTS
;i
++) {
360 if (Sounds
[i
][0]=='.') {
361 margv
[i
+3]=Sounds
[i
];
363 margv
[i
+3]=safemalloc(strlen(Sounds
[i
])
364 +strlen(SoundPath
)+4);
365 sprintf(margv
[i
+3],"%s/%s",SoundPath
,Sounds
[i
]);
370 fprintf(stderr
,"Wharf: couldn't spawn ASSound\n");
373 } else { /* in parent */
374 close(PlayerChannel
[0]);
385 if (BgPixmapFile
==NULL
) {
387 "%s: No Button background pixmap defined.Using default\n",
391 Buttons
[BACK_BUTTON
].icons
[0].file
=BgPixmapFile
;
392 if (LoadIconFile(BACK_BUTTON
,0))
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
))
406 case TEXTURE_COLORSET
:
407 BgColor
= Colorset
[global_colorset
].bg
;
409 GetXPMColorset(BACK_BUTTON
, global_colorset
);
412 case TEXTURE_BUILTIN
:
414 TextureType
=TEXTURE_BUILTIN
;
417 TextureType
=TEXTURE_SOLID
;
418 if (GetSolidXPM(BACK_BUTTON
, BgColor
))
421 fprintf( stderr
, "back Wharf button creation\n");
425 for(i
=0;i
<num_buttons
;i
++)
427 for(j
=0;j
<Buttons
[i
].iconno
;j
++) {
431 for(i
=num_folderbuttons
;i
<MAX_BUTTONS
;i
++) {
432 for(j
=0;j
<Buttons
[i
].iconno
;j
++) {
437 DndProtocol
=XInternAtom(dpy
,"DndProtocol",False
);
438 DndSelection
=XInternAtom(dpy
,"DndSelection",False
);
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
);
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
);
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
);
479 * Loop - wait for data to process
485 Window
*CurrentWin
=None
;
486 int x
,y
,CurrentRow
,CurrentColumn
,CurrentBase
=0;
488 int NewButton
,i
=0,j
=0,i2
, bl
=-1;
490 time_t t
, tl
= (time_t) 0;
495 if(My_XNextEvent(dpy
,&Event
))
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
);
510 RedrawUnpushedOutline(&Folders
[x
].win
, y
, 1);
514 if((Event
.xexpose
.count
== 0)&&
515 (Event
.xany
.window
== main_win
))
519 RedrawWindow(&main_win
,0, -1, num_rows
, num_columns
);
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
;
537 PlaySound(WHEV_OPEN_MAIN
);
539 if (AnimationStyle
>0 && AnimateMain
)
540 OpenFolder(-1,LastX
,LastY
,Width
,Height
,AnimationDir
);
542 XMoveResizeWindow(dpy
,main_win
,LastX
,LastY
,Width
,Height
);
546 unsigned int junk2
,junk3
,junk4
,junk5
;
547 int CornerX
, CornerY
;
548 fscreen_scr_arg fscr
;
551 PlaySound(WHEV_CLOSE_MAIN
);
554 dpy
,main_win
,&junk
,&LastX
,&LastY
,&junk2
,&junk3
,&junk4
,&junk5
))
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
;
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
;
574 if (Event
.xbutton
.x
>num_columns
*BUTTONWIDTH
/2) {
575 CornerX
= scr_x
+ scr_w
- BUTTONWIDTH
;
576 AnimationDir
= DIR_TOLEFT
;
579 AnimationDir
= DIR_TORIGHT
;
581 if (AnimationStyle
>0 && AnimateMain
) {
583 XMoveWindow(dpy
,main_win
, CornerX
, CornerY
);
585 XMoveResizeWindow(dpy
,main_win
,
587 BUTTONWIDTH
,BUTTONHEIGHT
);
589 } else { /* vertical */
590 if (LastX
> scr_x
+ scr_w
/2) {
591 CornerX
= scr_x
+ scr_w
- BUTTONWIDTH
;
595 if (Event
.xbutton
.y
>num_rows
*BUTTONHEIGHT
/2) {
596 CornerY
= scr_y
+ scr_h
- BUTTONHEIGHT
;
597 AnimationDir
= DIR_TOUP
;
600 AnimationDir
= DIR_TODOWN
;
602 if (AnimationStyle
>0 && AnimateMain
) {
604 XMoveWindow(dpy
,main_win
, CornerX
, CornerY
);
606 XMoveResizeWindow(dpy
,main_win
,
608 BUTTONWIDTH
,BUTTONHEIGHT
);
617 PlaySound(WHEV_PUSH
);
620 CurrentWin
= &Event
.xbutton
.window
;
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
;
628 CurrentButton
= CurrentBase
+ CurrentColumn
629 + CurrentRow
*num_columns
;
630 if (CurrentButton
>=num_buttons
) {
636 for(x
=0;x
<num_buttons
;x
++)
638 if (*CurrentWin
== Buttons
[x
].IconWin
)
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
;
653 CurrentButton
= CurrentBase
+ CurrentColumn
;
656 j
= CurrentColumn
+1;
658 if (Buttons
[CurrentButton
].swallow
== 1 ||
659 Buttons
[CurrentButton
].swallow
== 2 ||
660 Buttons
[CurrentButton
].action
== NULL
)
665 if (Buttons
[CurrentButton
].swallow
!= 3 &&
666 Buttons
[CurrentButton
].swallow
!= 4)
669 RedrawPushed(CurrentWin
, i
, j
);
672 if (strncasecmp(Buttons
[CurrentButton
].action
,"Folder",6)==0)
675 unsigned int junk2
,junk3
,junk4
,junk5
;
678 dpy
,main_win
,&junk
,&x
,&y
,&junk2
,&junk3
,&junk4
,&junk5
))
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
,
691 MapFolder(Buttons
[CurrentButton
].folder
,
694 CurrentRow
, CurrentColumn
);
704 if(Event
.xclient
.format
== 32 &&
705 Event
.xclient
.data
.l
[0]==_XA_WM_DEL_WIN
)
710 else if (Event
.xclient
.message_type
==DndProtocol
) {
711 unsigned long dummy_r
,size
;
714 unsigned char *data
, *Command
;
716 Window dummy_rt
, dummy_c
;
717 int dummy_x
, dummy_y
, base
, pos_x
, pos_y
;
720 /* if (Event.xclient.data.l[0]!=DndFile ||
721 Event.xclient.data.l[0]!=DndFiles ||
722 Event.xclient.data.l[0]!=DndExe
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 */
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;
744 if (Buttons
[dummy
].drop_action
== NULL
)
748 CurrentWin
=Buttons
[dummy
].parent
;
750 RedrawPushedOutline(CurrentWin
, dummy_y
, dummy_x
);
753 XGetWindowProperty(dpy
, Root
, DndSelection
, 0L,
754 100000L, False
, AnyPropertyType
,
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)
765 PlaySound(WHEV_DROP
);
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);
776 XClearWindow(dpy
,Buttons
[dummy
].IconWin
);
777 RedrawUnpushedOutline(CurrentWin
, dummy_y
, dummy_x
);
781 #endif /* ENABLE_DND */
783 if ((Event
.xbutton
.button
!= Button1
) ||
784 (Buttons
[CurrentButton
].swallow
== 1) ||
785 (Buttons
[CurrentButton
].swallow
== 2) ||
786 (Buttons
[CurrentButton
].action
== NULL
)) {
790 CurrentRow
= (Event
.xbutton
.y
/BUTTONHEIGHT
);
791 CurrentColumn
= (Event
.xbutton
.x
/BUTTONWIDTH
);
795 if (Buttons
[CurrentButton
].swallow
!= 3 &&
796 Buttons
[CurrentButton
].swallow
!= 4)
799 RedrawUnpushed(CurrentWin
, i
, j
);
804 if (*CurrentWin
!=main_win
) {
805 NewButton
= CurrentBase
+ CurrentColumn
*num_rows
806 + CurrentRow
*num_columns
;
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
;
818 NewButton
= Folders
[x
].firstbutton
+ CurrentColumn
;
820 for (x
=0;x
<num_buttons
;x
++)
822 if (*CurrentWin
== Buttons
[x
].IconWin
)
825 CurrentRow
= x
/ num_columns
;
826 CurrentColumn
= x
% num_columns
;
830 if(NewButton
== CurrentButton
)
835 if(strncasecmp(Buttons
[CurrentButton
].action
,"Folder",6)!=0)
837 if (LastMapped
!= -1 && CurrentWin
!= &main_win
)
839 CloseFolder(LastMapped
);
840 Folders
[LastMapped
].mapped
= NOTMAPPED
;
843 SendInfo(fd
,Buttons
[CurrentButton
].action
,0);
845 if((Buttons
[CurrentButton
].action
)&&
846 (strncasecmp(Buttons
[CurrentButton
].action
,"exec",4)== 0))
849 while((Buttons
[CurrentButton
].action
[i
] != 0)&&
850 (Buttons
[CurrentButton
].action
[i
] != '"'))
854 while((Buttons
[CurrentButton
].action
[i2
] != 0)&&
855 (Buttons
[CurrentButton
].action
[i2
] != '"'))
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;
868 Buttons
[CurrentButton
].swallow
= 0;
881 void OpenFolder(int folder
,int x
, int y
, int w
, int h
, int direction
)
889 winc
= BUTTONWIDTH
/ANIM_STEP_MAIN
;
890 hinc
= BUTTONHEIGHT
/ANIM_STEP_MAIN
;
892 winc
= BUTTONWIDTH
/ANIM_STEP
;
893 hinc
= BUTTONHEIGHT
/ANIM_STEP
;
897 win
= Folders
[folder
].win
;
898 Folders
[folder
].direction
= direction
;
899 if (direction
== DIR_TOLEFT
|| direction
== DIR_TORIGHT
)
905 if (direction
== DIR_TOLEFT
|| direction
== DIR_TORIGHT
)
908 isize
= BUTTONHEIGHT
;
912 if (AnimationStyle
==0) {
913 XMapWindow(dpy
, win
);
918 XMoveResizeWindow(dpy
,win
,cx
,y
, 1, h
);
919 XMapWindow(dpy
, win
);
920 for(cw
=isize
;cw
<=w
;cw
+=winc
) {
922 usleep(ANIM_DELAY
/2);
923 XMoveResizeWindow(dpy
,win
,cx
,y
, cw
,h
);
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
);
938 XMoveResizeWindow(dpy
,win
,x
,cy
, w
, 1);
939 XMapWindow(dpy
, win
);
940 for(ch
=isize
;ch
<=h
;ch
+=hinc
) {
942 usleep(ANIM_DELAY
/2);
943 XMoveResizeWindow(dpy
,win
,x
,cy
, w
, ch
);
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
);
958 fprintf(stderr
,"WHARF INTERNAL BUG in OpenFolder()\n");
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
)
973 unsigned int w
,h
, junk_depth
, junk_bd
;
974 int fsize
, direction
;
975 Window win
, junk_win
;
978 PlaySound(WHEV_CLOSE_FOLDER
);
981 winc
= BUTTONWIDTH
/ANIM_STEP_MAIN
;
982 hinc
= BUTTONHEIGHT
/ANIM_STEP_MAIN
;
984 winc
= BUTTONWIDTH
/ANIM_STEP
;
985 hinc
= BUTTONHEIGHT
/ANIM_STEP
;
989 direction
= AnimationDir
;
990 if (direction
==DIR_TOUP
|| direction
==DIR_TODOWN
)
995 direction
= Folders
[folder
].direction
;
996 win
= Folders
[folder
].win
;
997 if (direction
==DIR_TOUP
|| direction
==DIR_TODOWN
)
1002 if (AnimationStyle
==0 ||
1003 !XGetGeometry(dpy
,win
,&junk_win
,&x
,&y
,&w
,&h
,&junk_bd
,&junk_depth
))
1007 XTranslateCoordinates(dpy
,win
,Root
,x
,y
,&x
,&y
,&junk_win
);
1008 switch (direction
) {
1011 for(cw
=w
;cw
>= fsize
; cw
-=winc
) {
1012 XMoveResizeWindow(dpy
,win
,cx
,y
, cw
,h
);
1019 for(cw
=w
;cw
>= fsize
; cw
-=winc
) {
1020 XMoveResizeWindow(dpy
,win
,x
,y
, cw
,h
);
1027 for(ch
=h
;ch
>= fsize
; ch
-=hinc
) {
1028 XMoveResizeWindow(dpy
,win
,x
,cy
, w
,ch
);
1035 for(ch
=h
;ch
>= fsize
; ch
-=hinc
) {
1036 XMoveResizeWindow(dpy
,win
,x
,y
, w
, ch
);
1043 fprintf(stderr
,"WHARF INTERNAL BUG in CloseFolder()\n");
1046 Folders
[folder
].direction
= 0;
1049 XResizeWindow(dpy
,win
,BUTTONWIDTH
,BUTTONHEIGHT
);
1051 XUnmapWindow(dpy
,win
);
1056 void MapFolder(int folder
, int *LastMapped
, int base_x
, int base_y
, int row
,
1061 if (Folders
[folder
].mapped
==ISMAPPED
)
1063 CloseFolder(folder
);
1064 Folders
[folder
].mapped
= NOTMAPPED
;
1069 int folderx
, foldery
, folderw
, folderh
;
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
;
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;
1092 folderx
= base_x
+(col
+1)*BUTTONHEIGHT
+1;
1095 foldery
= base_y
+row
*BUTTONHEIGHT
;
1096 folderw
= Folders
[folder
].count
*BUTTONWIDTH
;
1097 folderh
= BUTTONHEIGHT
;
1100 else if (num_columns
== num_rows
)
1103 if((base_x % display_width) > display_width / 2 )
1104 folderx = (col-Folders[folder].count)*BUTTONHEIGHT-2;
1106 folderx = (col+1)*BUTTONHEIGHT+1;
1110 if ((base_y
% display_height
) > scr_y
+ scr_h
/ 2) {
1111 foldery
= base_y
-(Folders
[folder
].count
)*BUTTONHEIGHT
-2;
1115 foldery
= base_y
+BUTTONHEIGHT
+2;
1119 folderw
= BUTTONWIDTH
;
1120 folderh
= (Folders
[folder
].count
)*BUTTONHEIGHT
;
1124 if((base_x
% display_width
) > scr_x
+ scr_w
/ 2 ) {
1125 folderx
= base_x
-(Folders
[folder
].count
)*BUTTONWIDTH
-2;
1129 folderx
= base_x
+BUTTONWIDTH
+1;
1133 folderh
= BUTTONHEIGHT
;
1134 folderw
= (Folders
[folder
].count
)*BUTTONWIDTH
;
1139 if ((base_y
% display_height
) < scr_y
+ scr_h
/ 2) {
1140 foldery
=base_y
+(row
+1)*BUTTONHEIGHT
;
1144 foldery
= base_y
+(row
-Folders
[folder
].count
)*BUTTONHEIGHT
;
1147 folderx
= base_x
+col
*BUTTONWIDTH
;
1148 folderw
= BUTTONWIDTH
;
1149 folderh
= (Folders
[folder
].count
)*BUTTONHEIGHT
;
1153 PlaySound(WHEV_OPEN_FOLDER
);
1155 XMoveWindow(dpy
, Folders
[folder
].win
, folderx
, foldery
);
1156 OpenFolder(folder
,folderx
, foldery
, folderw
, folderh
, dir
);
1157 *LastMapped
= folder
;
1162 DrawOutline(Drawable d
, int w
, int h
)
1167 XDrawLine( dpy
, d
, HiInnerGC
, 0, 0, w
-1, 0);
1169 XDrawLine( dpy, d, HiInnerGC, 0, 1, w-1, 1);
1172 XFillRectangle(dpy
, d
, NormalGC
, 0,h
-2,w
-1,h
-1);
1175 XDrawLine( dpy
, d
, HiInnerGC
, 0, 1, 0, h
-1);
1177 XDrawLine( dpy, d, HiInnerGC, 1, 2, 1, h-2);
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
)
1187 XMoveResizeWindow(dpy
, Buttons
[CurrentButton
].IconWin
,
1188 (j
-1)*BUTTONWIDTH
,(i
-1)*BUTTONHEIGHT
,
1189 BUTTONWIDTH
, BUTTONHEIGHT
);
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
,
1197 RedrawWindow(win
,0, CurrentButton
, num_rows
, num_columns
);
1199 RedrawUnpushedOutline(win
, i
, j
);
1202 void RedrawUnpushedOutline(Window
*win
, int i
, int j
)
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);
1218 XDrawLine( dpy
, *win
, HiInnerGC
, j
*BUTTONWIDTH
-BUTTONWIDTH
,
1219 i
*BUTTONHEIGHT
-BUTTONHEIGHT
+1, j
*BUTTONWIDTH
-BUTTONWIDTH
,
1222 XDrawLine( dpy, *win, HiInnerGC, j*BUTTONWIDTH
1223 -BUTTONWIDTH+1, i*BUTTONHEIGHT-BUTTONHEIGHT+2,
1224 j*BUTTONWIDTH-BUTTONWIDTH+1 ,i*BUTTONHEIGHT-1);
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);
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,
1245 void RedrawPushed(Window
*win
, int i
,int j
)
1248 XMoveResizeWindow(dpy
, Buttons
[CurrentButton
].IconWin
,
1249 2+(j
-1)*BUTTONWIDTH
,(i
-1)*BUTTONHEIGHT
+2,
1250 BUTTONWIDTH
-2, BUTTONHEIGHT
-2);
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
)
1271 XDrawLine( dpy
, *win
, NormalGC
, j
*BUTTONWIDTH
-BUTTONWIDTH
,
1272 i
*BUTTONHEIGHT
-BUTTONHEIGHT
, j
*BUTTONWIDTH
,i
*BUTTONHEIGHT
1275 XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH,
1276 i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH,i*BUTTONHEIGHT
1281 XDrawLine( dpy
, *win
, NormalGC
, j
*BUTTONWIDTH
-BUTTONWIDTH
,
1282 i
*BUTTONHEIGHT
-BUTTONHEIGHT
+1, j
*BUTTONWIDTH
-BUTTONWIDTH
,
1285 XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH
1286 +1, i*BUTTONHEIGHT-BUTTONHEIGHT+2, j*BUTTONWIDTH-BUTTONWIDTH+1,
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);
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);
1319 void RedrawWindow(Window
*win
, int firstbutton
, int newbutton
,
1320 int num_rows
, int num_columns
)
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
);
1351 void CreateShadowGC(void)
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
;
1368 if (TextureType
>0 && TextureType
< 128) {
1369 MakeShadowColors(dpy
, FromColor
, ToColor
, &fore_pix
, &light_grey
);
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
);
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
;
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
,
1418 * Sizes and creates the window
1421 void CreateWindow(void)
1423 int first_avail_button
,i
;
1424 XSetWindowAttributes attr
;
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
);
1440 /* size and create the window */
1441 if((num_rows
== 0)&&(num_columns
== 0))
1443 if(num_columns
== 0)
1445 num_columns
= num_buttons
/num_rows
;
1446 while(num_rows
* num_columns
< num_buttons
)
1451 num_rows
= num_buttons
/num_columns
;
1452 while(num_rows
* num_columns
< num_buttons
)
1456 while(num_rows
* num_columns
< num_buttons
)
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;
1469 if (flags
& XNegative
)
1471 wx
= DisplayWidth(dpy
,screen
) + x
- mysizehints
.width
;
1472 gravity
= NorthEastGravity
;
1478 if (flags
& YNegative
)
1480 wy
= DisplayHeight(dpy
,screen
) + y
- mysizehints
.height
;
1481 gravity
= SouthWestGravity
;
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
;
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
);
1546 RETSIGTYPE
DeadPipe(int nonsense
)
1552 write(PlayerChannel
[1],&val
,sizeof(val
));
1553 if (SoundThread
!= 0)
1554 kill(SoundThread
,SIGUSR1
);
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
,
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
;
1587 InitGetConfigLine(fd
,CatString3("*", MyName
, 0)); /* speedup */
1588 GetConfigLine(fd
, &tline
);
1590 Clength
= strlen(MyName
);
1591 while(tline
!= NULL
&& tline
[0] != '\0')
1594 unsigned width
,height
;
1595 while(isspace(*tline
))tline
++;
1597 if(strlen(&tline
[0]) <= 0)
1599 GetConfigLine(fd
, &tline
);
1604 if((strncasecmp(tline
,CatString3("*", MyName
, "Geometry"),Clength
+9)==0))
1610 tmp
= &tline
[Clength
+9];
1611 while(((isspace(*tmp
))&&(*tmp
!= '\n'))&&(*tmp
!= 0))
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
)
1623 if (flags
& HeightValue
)
1631 else if((strncasecmp(tline
,CatString3("*",MyName
,"Rows"),Clength
+5)==0))
1633 len
=sscanf(&tline
[Clength
+5],"%d",&num_rows
);
1638 else if((strncasecmp(tline
,CatString3("*",MyName
,"Columns"),Clength
+8)==0))
1640 len
=sscanf(&tline
[Clength
+8],"%d",&num_columns
);
1645 else if((strncasecmp(tline
,CatString3("*",MyName
,"NoPush"),Clength
+5)==0))
1649 else if((strncasecmp(tline
,CatString3("*",MyName
,"FullPush"),
1654 else if((strncasecmp(tline
,CatString3("*",MyName
,"NoBorder"),
1659 else if ((strncasecmp(tline
,CatString3("*",MyName
,"ForceSize"),
1663 else if ((strncasecmp(tline
,CatString3("*",MyName
,"TextureType"),
1665 if (sscanf(&tline
[Clength
+12],"%d",&TextureType
) >= 1)
1667 /* disable colorset */
1668 global_colorset
= -1;
1672 TextureType
= TEXTURE_BUILTIN
;
1675 else if ((strncasecmp(tline
,CatString3("*",MyName
,"MaxColors"),
1678 if (sscanf(&tline
[Clength
+10],"%d",&MaxColors
)<1)
1681 else if ((strncasecmp(tline
,CatString3("*",MyName
,"BgColor"),
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
);
1693 else if ((strncasecmp(tline
,CatString3("*",MyName
,"TextureColor"),
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",
1711 if (!XParseColor (dpy
, Pcmap
, c1
, &color
))
1713 fprintf(stderr
, "Cannot parse %s\n", c1
);
1714 TextureType
=TEXTURE_BUILTIN
;
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
;
1727 ToColor
[0]=color
.red
;
1728 ToColor
[1]=color
.green
;
1729 ToColor
[2]=color
.blue
;
1730 /* disable colorset */
1731 global_colorset
= -1;
1736 else if ((strncasecmp(tline
,CatString3("*",MyName
,"Pixmap"),
1738 CopyString(&BgPixmapFile
,&tline
[Clength
+7]);
1740 else if((strncasecmp(tline
,CatString3("*",MyName
,"AnimateMain"),
1745 else if((strncasecmp(tline
,CatString3("*",MyName
,"Animate"),Clength
+8)==0))
1747 if ((tline
[Clength
+9]!='M') && (tline
[Clength
+9]!='m'))
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
;
1763 /* disable texture, if any */
1764 TextureType
=TEXTURE_COLORSET
;
1768 BgPixmapFile
= NULL
;
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]);
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
);
1790 match_string(&tline
[Clength
+1]);
1792 else if((strncasecmp(tline
,"ImagePath",9)==0))
1794 CopyString(&imagePath
,&tline
[9]);
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]);
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
);
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)) {
1831 * Gets a word of a given index in the line, stripping any blanks
1832 * The returned word is newly allocated
1835 char *get_token(char *tline
, int index
)
1841 index
++; /* index is 0 based */
1842 size
= strlen(tline
);
1845 while (i
<index
&& c
<size
) {
1847 while(isspace(*start
) && c
<size
) {
1852 while(!isspace(*end
) && c
<size
) {
1856 if (end
==start
) return NULL
;
1859 if (i
<index
) return NULL
;
1860 word
=safemalloc(end
-start
+1);
1861 strncpy(word
, start
, end
-start
);
1868 * Parses a sound binding
1871 void bind_sound(char *tline
)
1873 char *event
, *sound
;
1875 event
= get_token(tline
,0);
1877 fprintf(stderr
,"%s:bad sound binding %s\n",MyName
,tline
);
1880 sound
= get_token(tline
,1);
1883 fprintf(stderr
,"%s:bad sound binding %s\n",MyName
,tline
);
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
;
1899 fprintf(stderr
,"%s:bad event %s in sound binding\n",MyName
,event
);
1905 #endif /* ENABLE_SOUND */
1909 * Parses a button command line from the config file
1912 void match_string(char *tline
)
1915 char *ptr
,*start
,*end
,*tmp
;
1916 struct button_info
*actual
;
1919 while(isspace(*tline
)&&(*tline
!= '\n')&&(*tline
!= 0))
1922 /* read next word. Its the button label. Users can specify ""
1923 * NoIcon, or whatever to skip the label */
1924 /* read to next space */
1927 while((!isspace(*end
))&&(*end
!='\n')&&(*end
!=0))
1930 ptr
= safemalloc(len
+1);
1931 strncpy(ptr
,start
,len
);
1934 if (strncmp(ptr
,"~Folder",7)==0)
1937 Folders
[num_folders
].firstbutton
= num_folderbuttons
;
1945 actual
= &Buttons
[num_buttons
++];
1946 actual
->parent
= &main_win
;
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 */
1962 while(isspace(*start
)&&(*start
!= '\n')&&(*start
!= 0))
1965 while((!isspace(*end
))&&(*end
!='\n')&&(*end
!=0))
1968 ptr
= safemalloc(len
+1);
1969 strncpy(ptr
,start
,len
);
1971 /* separate icon files to be overlaid */
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;
1985 for (i
=num_buttons
- 2;i
>=0;i
--)
1987 if (strcmp(Buttons
[i
].title
, actual
->title
) == 0)
1989 actual
= &Buttons
[i
];
1991 for(i
=0;i
<actual
->iconno
;i
++) {
1992 free(actual
->icons
[i
].file
);
1998 while(isspace(*tline
)&&(*tline
!= '\n')&&(*tline
!= 0))
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 */
2007 for(i
=0;i
<actual
->iconno
;i
++) {
2008 free(actual
->icons
[i
].file
);
2012 num_folderbuttons
++;
2014 for(i
=0;i
<actual
->iconno
;i
++) {
2015 free(actual
->icons
[i
].file
);
2018 fprintf(stderr
,"Drop in Folders not supported. Ignoring option\n");
2022 tline
=strstr(tline
,"Exec");
2023 len
= strlen(tline
);
2024 tmp
= tline
+ len
-1;
2025 while(((isspace(*tmp
))||(*tmp
== '\n'))&&(tmp
>=tline
)) {
2029 ptr
= safemalloc(len
+1);
2030 actual
->drop_action
=ptr
;
2031 strncpy(ptr
,tline
,len
);
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 */
2041 while((tline
[i
] != 0)&&
2045 while((tline
[i2
] != 0)&&
2049 strncasecmp(tline
,"maxswallow",10) == 0 ? 1 : 0;
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;
2059 while((isspace(tline
[n
]))&&(tline
[n
]!=0))
2061 len
= strlen(&tline
[n
]);
2062 tmp
= tline
+ n
+ len
-1;
2063 while(((isspace(*tmp
))||(*tmp
== '\n'))&&(tmp
>=(tline
+ n
)))
2068 ptr
= safemalloc(len
+6);
2069 if(strncasecmp(&tline
[n
],"Module",6)==0)
2075 strcpy(ptr
,"Exec ");
2077 strncat(ptr
,&tline
[n
],len
);
2081 actual
->action
= NULL
;
2087 Folders
[num_folders
].count
++;
2090 len
= strlen(tline
);
2091 tmp
= tline
+ len
-1;
2092 while(((isspace(*tmp
))||(*tmp
== '\n'))&&(tmp
>=tline
))
2097 ptr
= safemalloc(len
+1);
2098 strncpy(ptr
,tline
,len
);
2101 if (strncmp(ptr
,"Folder",6)==0)
2104 Folders
[num_folders
].count
= 0;
2105 actual
->folder
= num_folders
;
2106 Folders
[num_folders
].mapped
= NOTMAPPED
;
2108 actual
->action
= ptr
;
2114 * Change the window name displayed in the title bar.
2116 void change_window_name(char *str
)
2119 XClassHint myclasshints
;
2122 if (XStringListToTextProperty(&str
,1,&name
) == 0)
2124 fprintf(stderr
,"%s: cannot allocate window name\n",MyName
);
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
);
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
)
2150 static int miss_counter
= 0;
2154 FNextEvent(dpy
,event
);
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
))
2169 FNextEvent(dpy
,event
);
2175 if(miss_counter
> 100)
2179 if(FD_ISSET(fd
[1], &in_fdset
))
2181 FvwmPacket
* packet
= ReadFvwmPacket(fd
[1]);
2182 if ( packet
== NULL
)
2185 process_message( packet
->type
, packet
->body
);
2190 void CheckForHangon(unsigned long *body
)
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
;
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)
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
);
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)
2260 BgColor
= Colorset
[global_colorset
].bg
;
2262 XFreeGC(dpy
, NormalGC
);
2263 XFreeGC(dpy
, HiReliefGC
);
2264 XFreeGC(dpy
, HiInnerGC
);
2265 XFreeGC(dpy
, MaskGC
);
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
);
2281 RedrawUnpushedOutline(&Folders
[x
].win
, y
, 1);
2284 XClearWindow(dpy
, main_win
);
2285 RedrawWindow(&main_win
,0, -1, num_rows
, num_columns
);
2291 static void handle_config_info_packet(unsigned long *body
)
2293 char *tline
, *token
;
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
);
2314 * Process window list messages
2317 void process_message(unsigned long type
,unsigned long *body
)
2321 /* case M_TOGGLE_PAGING:
2322 pageing_enabled = body[0];
2323 RedrawWindow(&main_win,0, -1, num_rows, num_columns);
2328 RedrawWindow(&main_win
,0, -1, num_rows
, num_columns
);
2330 case M_END_WINDOWLIST
:
2331 RedrawWindow(&main_win
,0, -1, num_rows
, num_columns
);
2337 CheckForHangon(body
);
2340 handle_config_info_packet((unsigned long*)body
);
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
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
;
2370 ev
.message_type
= _XA_WM_PROTOCOLS
;
2373 ev
.data
.l
[1] = timestamp
;
2374 FSendEvent(dpy
, w
, False
, 0L, (XEvent
*) &ev
);
2378 void swallow(unsigned long *body
)
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,
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
,
2413 False
, ButtonPressMask
| ButtonReleaseMask
,
2414 GrabModeAsync
, GrabModeAsync
, None
, None
);
2418 if (Buttons
[button
].maxsize
) {
2419 unsigned int width
, height
;
2421 unsigned int junk3
, junk4
;
2423 if (XGetGeometry(dpy
, Buttons
[button
].IconWin
, &root
,
2424 &junk1
, &junk2
, &width
, &height
, &junk3
,
2427 if (width
> BUTTONWIDTH
)
2428 width
= BUTTONWIDTH
;
2429 if (height
> BUTTONHEIGHT
)
2430 height
= BUTTONHEIGHT
;
2434 width
= BUTTONWIDTH
;
2435 height
= BUTTONHEIGHT
;
2437 Buttons
[button
].icons
[0].w
= width
;
2438 Buttons
[button
].icons
[0].h
= height
;
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
,
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
,
2455 (BUTTONWIDTH
- Buttons
[button
].icons
[0].w
)/2,
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
);
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
);
2479 void FindLockMods(void)
2485 unsigned lockmask
, *mp
;
2486 XModifierKeymap
* mm
= XGetModifierMapping(dpy
);
2487 lockmask
= LockMask
;
2490 kp
= mm
->modifiermap
;
2491 for (m
= 0; m
< 8; m
++)
2493 for (i
= 0; i
< mm
->max_keypermod
; i
++)
2496 ((ks
= XKeycodeToKeysym(dpy
, kc
, 0)) != NoSymbol
))
2498 kn
= XKeysymToString(ks
);
2500 if ((knl
> 6) && (strcasecmp(kn
+ knl
- 4, "lock") == 0))
2501 lockmask
|= (1 << m
);
2505 XFreeModifiermap(mm
);
2507 lockmask
&= ~(ShiftMask
| ControlMask
);
2510 for (m
= 0, i
= 1; i
< 256; i
++)
2512 if ((i
& lockmask
) > m
)
2513 m
= *mp
++ = (i
& lockmask
);
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
;
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
;
2569 if(hints
->flags
& PMaxSize
)
2571 maxWidth
= hints
->max_width
;
2572 maxHeight
= hints
->max_height
;
2579 if(hints
->flags
& PResizeInc
)
2581 xinc
= hints
->width_inc
;
2582 yinc
= hints
->height_inc
;
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
,
2635 if (dwidth
+ delta
<= maxWidth
)
2639 delta
= makemult(dheight
- dwidth
*minAspectY
/minAspectX
,
2641 if (dheight
- delta
>= minHeight
) dheight
-= delta
;
2645 if (maxAspectX
* dheight
< maxAspectY
* dwidth
)
2647 delta
= makemult(dwidth
* maxAspectY
/ maxAspectX
- dheight
,
2649 if (dheight
+ delta
<= maxHeight
)
2653 delta
= makemult(dwidth
- maxAspectX
*dheight
/maxAspectY
,
2655 if (dwidth
- delta
>= minWidth
) dwidth
-= delta
;
2667 void PlaySound(int event
)
2673 if (Sounds
[event
]==NULL
) return;
2674 write(PlayerChannel
[1],&event
,sizeof(event
));
2675 timestamp
= clock();
2676 write(PlayerChannel
[1],×tamp
,sizeof(timestamp
));
2678 kill(SoundThread,SIGUSR1);