diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 10:53:58 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 10:53:58 +0000 |
commit | 1cb4778bcef21ea9015cfccdb99abb7a0e035d74 (patch) | |
tree | f164009397f9d3d5634c6f8a94b1542f793d9692 /app/fvwm/extras/FvwmWharf | |
parent | 841f8331c93ff96bd798e9a74ba10fab155da5c5 (diff) |
Importing from XF4, plus BSD make infrastructure
Diffstat (limited to 'app/fvwm/extras/FvwmWharf')
-rw-r--r-- | app/fvwm/extras/FvwmWharf/ASSound/ASSound.c | 242 | ||||
-rw-r--r-- | app/fvwm/extras/FvwmWharf/ASSound/README | 1 | ||||
-rw-r--r-- | app/fvwm/extras/FvwmWharf/FvwmWharf.1 | 205 | ||||
-rw-r--r-- | app/fvwm/extras/FvwmWharf/FvwmWharf.c | 2443 | ||||
-rw-r--r-- | app/fvwm/extras/FvwmWharf/OffiX/DragAndDrop.h | 48 | ||||
-rw-r--r-- | app/fvwm/extras/FvwmWharf/OffiX/DragAndDropTypes.h | 32 | ||||
-rw-r--r-- | app/fvwm/extras/FvwmWharf/README | 22 | ||||
-rw-r--r-- | app/fvwm/extras/FvwmWharf/Wharf.h | 121 | ||||
-rw-r--r-- | app/fvwm/extras/FvwmWharf/icons.c | 367 | ||||
-rw-r--r-- | app/fvwm/extras/FvwmWharf/sample.style | 41 | ||||
-rw-r--r-- | app/fvwm/extras/FvwmWharf/stepgfx.c | 587 | ||||
-rw-r--r-- | app/fvwm/extras/FvwmWharf/stepgfx.h | 33 |
12 files changed, 4142 insertions, 0 deletions
diff --git a/app/fvwm/extras/FvwmWharf/ASSound/ASSound.c b/app/fvwm/extras/FvwmWharf/ASSound/ASSound.c new file mode 100644 index 000000000..c1939064a --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/ASSound/ASSound.c @@ -0,0 +1,242 @@ +/* + * AfterStep Sound System - sound module for Wharf + * + * Copyright (c) 1996 by Alfredo Kojima + */ +/* + * Todo: + * realtime audio mixing + * replace the Audio module + */ +#include <stdlib.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/time.h> +#include <signal.h> +#include <unistd.h> +#define AUDIO_DEVICE "/dev/audio" + +typedef struct LList { + struct LList *next; + struct LList *prev; + int data; + int timestamp; +} LList; + +typedef struct SoundEntry { + char *data; + int size; +} SoundEntry; + +/* timeout time for sound playing in seconds */ +#define PLAY_TIMEOUT 1 + +/* table of audio data (not filenames) */ +SoundEntry **SoundTable; + +int LastSound=0; +char *SoundPlayer; + +char *ProgName; +LList *PlayQueue=NULL, *OldestQueued=NULL; + +int InPipe; + +void *ckmalloc(size_t size) +{ + void *tmp; + + tmp=malloc(size); + if (tmp==NULL) { + fprintf(stderr,"%s: virtual memory exhausted.",ProgName); + exit(1); + } + return tmp; +} + +/* + * Register -- + * makes a new sound entry + */ +void Register(char *sound_file, int code) +{ + int file; + struct stat stat_buf; + + if (sound_file[0]=='.' && sound_file[1]==0) { + SoundTable[code]=ckmalloc(sizeof(SoundEntry)); + SoundTable[code]->size = -1; + return; /* dummy sound */ + } + if (stat(sound_file, &stat_buf)<0) { + fprintf(stderr,"%s: sound file %s not found\n",ProgName, + sound_file); + return; + } + SoundTable[code]=ckmalloc(sizeof(SoundEntry)); + if (SoundPlayer!=NULL) { + SoundTable[code]->data=ckmalloc(strlen(sound_file)); + SoundTable[code]->size=1; + strcpy(SoundTable[code]->data,sound_file); + return; + } + SoundTable[code]->data=ckmalloc(stat_buf.st_size); + file=open(sound_file, O_RDONLY); + if (file<0) { + fprintf(stderr,"%s: can't open sound file %s\n",ProgName, sound_file); + free(SoundTable[code]->data); + free(SoundTable[code]); + SoundTable[code]=NULL; + return; + } + SoundTable[code]->size=read(file,SoundTable[code]->data,stat_buf.st_size); + if (SoundTable[code]->size<1) { + fprintf(stderr,"%s: error reading sound file %s\n",ProgName, + sound_file); + free(SoundTable[code]->data); + free(SoundTable[code]); + close(file); + SoundTable[code]=NULL; + return; + } + close(file); +} + +/* + * PlaySound -- + * plays a sound + */ + +void PlaySound(int sid) +{ + int audio=-1; + if ((sid < LastSound) && (SoundTable[sid]->size<=0)) return; + if ((sid>=LastSound) || (sid<0) || SoundTable[sid]==NULL) { + fprintf(stderr,"%s: request to play invalid sound received\n", + ProgName); + return; + } + if (SoundPlayer!=NULL) { + static char cmd[1024]; + pid_t child; + + child = fork(); + if (child<0) return; + else if (child==0) { + execlp(SoundPlayer,SoundPlayer,SoundTable[sid]->data,NULL); + } else { + while (wait(NULL)<0); + } + /* + sprintf(cmd,"%s %s",SoundPlayer,SoundTable[sid]->data); + system(cmd); + */ + return; + } +#if 0 + audio = open(AUDIO_DEVICE,O_WRONLY|O_NONBLOCK); + if ((audio<0) && errno==EAGAIN) { + sleep(1); + audio = open(AUDIO_DEVICE,O_WRONLY|O_NONBLOCK); + if (audio<0) return; + } + write(audio, SoundTable[sid]->data,SoundTable[sid]->size); + close(audio); + audio=-1; +#endif +} + +void DoNothing(int foo) +{ + signal(SIGUSR1, DoNothing); +} + +/* + * HandleRequest -- + * play requested sound + * sound -1 is a quit command + * + * Note: + * Something not good will happed if a new play request + * arrives before exiting the handler + */ +void HandleRequest(int foo) +{ + int sound, timestamp; + char *buffer; + LList *tmp; +/* + signal(SIGUSR1, DoNothing); + */ + read(InPipe,&sound,sizeof(sound)); + read(InPipe,×tamp,sizeof(timestamp)); + if (sound<0) { + printf("exitting ASSound..\n"); + exit(0); + } + if ((clock()-timestamp)<PLAY_TIMEOUT) + PlaySound(sound); +#if 0 + tmp = ckmalloc(sizeof(LList)); + tmp->data = sound; + tmp->timestamp = clock(); + tmp->next = PlayQueue; + if (PlayQueue==NULL) { + OldestQueued = tmp; + tmp->prev = NULL; + } else { + PlayQueue->prev = tmp; + } + PlayQueue = tmp; + signal(SIGUSR1, HandleRequest); +#endif +} + +/* + * Program startup. + * Arguments: + * argv[1] - pipe for reading data + * argv[2] - the name of the sound player to be used. ``-'' indicates + * internal player. + * argv[3]... - filenames of sound files with code n-3 + */ +int main(int argc, char **argv) +{ + int i; + + signal(SIGUSR1, HandleRequest); + ProgName=argv[0]; + if (argc<4) { + fprintf(stderr, "%s can only be started by an AfterStep module\n", + ProgName); + exit(1); + } + SoundPlayer=argv[2]; + if (SoundPlayer[0]=='-' && SoundPlayer[1]==0) { + SoundPlayer=NULL; + printf("%s:need a sound player.\n",ProgName); + } + SoundTable=ckmalloc(sizeof(SoundEntry *)*(argc-3)); + for(i=3; i<argc; i++) { + Register(argv[i], i-3); + } + LastSound=i-3; + InPipe = atoi(argv[1]); + while(1) { +#if 0 + LList *tmp; + while (OldestQueued!=NULL) { + if ((clock()-OldestQueued->timestamp) < PLAY_TIMEOUT) + PlaySound(OldestQueued->data); + tmp = OldestQueued->prev; + free(OldestQueued); + OldestQueued=tmp; + } + pause(); +#endif + HandleRequest(0); + } +} + diff --git a/app/fvwm/extras/FvwmWharf/ASSound/README b/app/fvwm/extras/FvwmWharf/ASSound/README new file mode 100644 index 000000000..3ed69c962 --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/ASSound/README @@ -0,0 +1 @@ +ASSound must go to the AfterStep modules directory. diff --git a/app/fvwm/extras/FvwmWharf/FvwmWharf.1 b/app/fvwm/extras/FvwmWharf/FvwmWharf.1 new file mode 100644 index 000000000..9b3cee258 --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/FvwmWharf.1 @@ -0,0 +1,205 @@ +.TH FvwmWharf 1.0 "October 1996" FvwmWharf +.UC +.SH NAME +FvwmWharf \- the AfterStep application "dock" module ported to +Fvwm. +.SH SYNOPSIS +FvwmWharf is spawned by Fvwm, so no command line invocation will work. + +.SH DESCRIPTION +The FvwmWharf module is a free-floating application loader that can +execute programs, "Swallow" running programs, and contain "Folders" of +more applications, among other things. The user can press the first +button at any time to trigger invocation of one of these functions, or +the user can press button two in order to cause the entire Wharf +to withdraw to the nearest corner in an iconized state. FvwmWharf only +works when Fvwm is used as the window manager. + +.SH COPYRIGHTS +The FvwmWharf module is copyright 1995 and 1996 by a variety of contributors. +They are, in alphabetical order, Beat Christen, Frank Fejes, Alfredo +Kenji Kojima, Dan Weeks, and Bo Yang + +The GoodStuff program, and the concept for +interfacing this module to the Window Manager, are all original work +by Robert Nation + +No guarantees or warranties or anything +are provided or implied in any way whatsoever. Use this program at your +own risk. Permission to use this program for any purpose is given, +as long as the copyright is kept intact. + + +.SH INITIALIZATION +During initialization, \fIFvwmWharf\fP will search for a configuration +file which describes the button panel geometry, color, icons, and +actions. The format of +this file will be described later. The configuration file will be the +one which Fvwm used during its initialization. + +If the FvwmWharf executable is linked to another name, ie ln -s +FvwmWharf Pier, then another module called Pier can be +started, with a completely different configuration than FvwmWharf, +simply by changing the keywords FvwmWharf??? to Pier???. This way multiple +button-bars can be used. + +.SH INVOCATION +FvwmWharf should be invoked in the same way as other +Fvwm modules. + +.SH CONFIGURATION OPTIONS +The following options can be placed in the .steprc file + +.IP "*FvwmWharfAnimate" +If specified, the opening and closing of Folders will be animated, +rather than simply drawn in one frame. + +.IP "*FvwmWharfAnimateMain" +Designates that full-length Wharf windraws will be animated. + +.IP "*FvwmWharfBgColor \fIcolor\fP" +If \fI*FvwmWharfTextureType 0\fP is specified, \fIFvwmWharf\fP's buttons +will be filled with \fIcolor\fP. + +.IP "*FvwmWharfColumns \fIcolumns\fP" +Specifies the number of columns of buttons to be created. If unspecified, +the number of columns will be set to 1. +If the columns are set to a number greater than 1 then there will be that number +of columns with enough rows to satisfy the requested number of buttons. + +.IP "*FvwmWharfForceSize" +If specified, will force pixmaps larger than 64x64 to the default +size. Pixmaps smaller than 64x64 are not supported. + +.IP "*FvwmWharfFullPush" +If specified, the entire FvwmWharf button background will be moved down +and to the right when pushed. Especially useful with *FvwmWharfNoBorder +textures. + +.IP "*FvwmWharfGeometry \fIgeometry\fP" +Specifies the FvwmWharf window location and/or size. If the size is +not specified, FvwmWharf will auto-size itself in a reasonable manner. +The geometry is a standard X11 window geometry specification. This option is +pre-set in the NEXTSTEP(tm) style section for a consistent look and feel with NEXTSTEP(tm). +Secondary FvwmWharf invocations from links may have their own geometry. + +.IP "*FvwmWharfMaxColors \fInumber\fP" +Specifies the maximum \fInumber\fP of colors to use on a gradient +fill. + +.IP "*FvwmWharfNoBorder" +Denotes that beveled borders should not be drawn around the FvwmWharf button. +Useful with textures that include their own bevels. + +.IP "*FvwmWharfPixmap \fIpixmap\fP" +Sets the pixmap file to be used as \fIFvwmWharf\fP's button. To be used +with \fI*FvwmWharfTextureType 128\fP. + +.IP "*FvwmWharfTextureColor \fIfrom\fP \fIto\fP" +When used with a \fI*FvwmWharfTextureType\fP of 1 to 5, designates the +ends of the gradient range to be used on \fIFvwmWharf\fP's buttons. + +.IP "*FvwmWharfTextureType \fItype\fP" +Specifies the type of gradient fill to be used on +\fIFvwmWharf\fP's buttons. Valid values are: +.nf +0 - No texture - use \fIFvwmWharfBgColor\fP to set the desired color +1 - Gradient from upper-left to lower right +2 - Horizontal one way gradient from top to bottom +3 - Horizontal cylindrical gradient from top/bottom to center +4 - Vertical one way gradient from left to right +5 - Vertical cylindrical gradient from left/right to center +128 - User specified pixmap +.fi +The default is the builtin \fIFvwmWharf\fP texture pixmap. + +.IP "*FvwmWharf \fIlabel icon command\fP" +Specifies a window manager built-in command or folder to activate +(folders will be discussed below), as described in the Fvwm +man page, which should be executed when a button is pressed. The label +field is an internal item that is still around from the GoodStuff module. +The icon field +specifies an X11 bitmap file, XPM color icon file, or a comma-delimited +set of pixmaps containing the +icon(s) to display on the button. FvwmWharf will search through the path +specified in the IconPath or PixmapPath configuration items to +find the icon file. + +NOTE: Icons must have one transparent pixel or the definition of a transparent color in order to be valid. + +If \fIcommand\fP is an Fvwm Exec command, then the button will +appear pushed in until the mouse button is released. + +A single extension to the Fvwm built-in command set is provided. +A command of the form: +.nf + +*FvwmWharf junk clock.xpm Swallow "Clock" asclock -shape -12 & + +.fi +will cause FvwmWharf to spawn an asclock process, and capture +the first window whose name or resource is "Clock", and display it in +the button-bar. This is handy for applications like xclock, xbiff, +xload, asclock, and asmail. Modules can be swallowed by specifying SwallowModule instead +of just "swallow" NOTE: if you use xclock for this application, you will want +to specify xclock -padding 0. + +For certain applications that overrun the 48 pixel by 48 pixel boundary of FvwmWharf +icons and Swallowed programs there is a special option called +.I MaxSwallow. +.I MaxSwallow +will allow the application to draw itself larger than the 48x48 boundary. It is +invoked the same way Swallow is. + +To create folder "slide-outs" in +.B FvwmWharf +the following format must be used: +.nf + +*FvwmWharf files Folders.xpm Folder +*FvwmWharf xftp 3DRings.xpm Exec xftp & +*FvwmWharf xdir FolderDeposit.xpm Exec xdir & +*FvwmWharf moxfm FilingCabinet.xpm Exec moxfm & +*FvwmWharf ~Folders + +.fi +The first line of this set tells FvwmWharf that this button definition will be a +folder. All of the button definitions between the +.I Folder +and the line with the definition of +.I *FvwmWharf ~Folders +will appear on the "files" folder when it is exposed. To expose the "files" +folder simply click on the FvwmWharf button with the Folders.xpm icon showing. A +button bar will appear perpendicular to your FvwmWharf bar and toward the center +of the screen. On this smaller bar will be the three icons that were configured +between the +.I Folder +and +.I ~Folder +parts of the FvwmWharf configuration. As many folder buttons may be configured as +is room on your screen. The only items that may not be configured within +folders are Swallowed applications and more folders. + +.SH DRAG AND DROP +\fIFvwmWharf\fP supports the OffiX Drag and Drop standard. In order to +have Drag and Drop enabled on a particular button, the following syntax +must be adhered to: +.nf + +*FvwmWharf nil nil DropExec "\fIprogram\fP" \fIprogram\fP %s +*FvwmWharf \fIprogram\fP \fIiconname\fP Exec "\fIprogram\fP" \fIprogram\fP + +.fi + +The button will call \fIprogram\fP when pushed. If a file is dragged +onto into it, \fIprogram\fP will be called with %s being replaced by +the dropped filename. + +.SH AUTHORS +.nf +Beat Christen (bchriste@iiic.ethz.ch) +Frank Fejes (frank@ssax.com) +Alfredo Kengi Kojima (kojima@inf.ufrgs.br) +Dan Weeks (dan@mango.sfasu.edu) +Bo Yang (eric@coeus.ucsd.edu) +.fi diff --git a/app/fvwm/extras/FvwmWharf/FvwmWharf.c b/app/fvwm/extras/FvwmWharf/FvwmWharf.c new file mode 100644 index 000000000..5b5975bd2 --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/FvwmWharf.c @@ -0,0 +1,2443 @@ +/* Wharf.c. by Bo Yang. + * + * Copyright 1993, Robert Nation. + * + * Modifications: Copyright 1995 by Bo Yang. + * + * modifications made by Frank Fejes for AfterStep Copyright 1996 + * + * folder code Copyright 1996 by Beat Christen. + * + * swallowed button actions Copyright 1996 by Kaj Groner + * + * Various enhancements Copyright 1996 Alfredo K. Kojima + * + * button pushing styles + * configurable border drawing + * Change of icon creation code. Does not use shape extension anymore. + * each icon window now contains the whole background + * OffiX drop support added + * animation added + * withdraw on button2 click + * icon overlaying + * sound bindings + * + * based on GoodStuff.c by Robert Nation + * The GoodStuff module, and the entire GoodStuff program, and the concept for + * interfacing that module to the Window Manager, are all original work + * by Robert Nation + * + * No guarantees or warantees or anything + * are provided or implied in any way whatsoever. Use this program at your + * own risk. Permission to use this program for any purpose is given, + * as long as the copyright is kept intact. */ + +#define TRUE 1 +#define FALSE 0 +#define DOUBLECLICKTIME 1 + +#include "config.h" + +#ifdef HAVE_SYS_BSDTYPES_H +#include <sys/bsdtypes.h> /* Saul */ +#endif + +#include <stdio.h> +#include <signal.h> +#include <fcntl.h> +#include <string.h> +#include <sys/wait.h> +#include <sys/time.h> + +#if HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#include <unistd.h> +#include <ctype.h> +#include <stdlib.h> +#include "../../fvwm/module.h" +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xproto.h> +#include <X11/Xatom.h> +#include <X11/Intrinsic.h> +#include <syslog.h> + +#include "Wharf.h" +#define AFTER_ICONS 1 +/*#include "../../afterstep/asbuttons.h" pdg */ + +#ifdef ENABLE_DND +#include "OffiX/DragAndDrop.h" +#include "OffiX/DragAndDropTypes.h" +#endif + +#include "stepgfx.h" + +/* + * You may want to raise the following values if your machine is fast + */ +#define ANIM_STEP 2 /* must be >= 1. Greater is smoother and slower */ +#define ANIM_STEP_MAIN 1 /* same for the main folder */ +#define ANIM_DELAY 10 + +#ifdef ENABLE_SOUND +#define WHEV_PUSH 0 +#define WHEV_CLOSE_FOLDER 1 +#define WHEV_OPEN_FOLDER 2 +#define WHEV_CLOSE_MAIN 3 +#define WHEV_OPEN_MAIN 4 +#define WHEV_DROP 5 +#define MAX_EVENTS 6 + +int SoundActive = 0; +char *Sounds[6]={".",".",".",".",".","."}; +char *SoundPlayer=NULL; +char *SoundPath="."; + +pid_t SoundThread; +int PlayerChannel[2]; + +/*char *ModulePath=AFTERDIR; pdg */ +#endif + +char *MyName; + +Display *dpy; +int x_fd,fd_width; +int ROWS = FALSE; + +Window Root; +int screen; +int flags; +long d_depth; +Bool NoBorder=0; +Bool Pushed = 0; +Bool Pushable = 1; +Bool ForceSize=0; +Pixel back_pix, fore_pix, light_grey; +GC NormalGC, HiReliefGC, HiInnerGC; + +GC MaskGC, DefGC; +int AnimationStyle=0,AnimateMain=0; +int PushStyle=0; +int AnimationDir=1; + +Window main_win; +int Width, Height,win_x,win_y; +unsigned int display_width, display_height; + +#define MW_EVENTS (ExposureMask | ButtonReleaseMask |\ + ButtonPressMask | LeaveWindowMask | EnterWindowMask) +XSizeHints mysizehints; +int num_buttons = 0; +int num_folderbuttons = MAX_BUTTONS; +int num_folders = 0; +int num_rows = 0; +int num_columns = 0; +int max_icon_width = 30,max_icon_height = 0; +int BUTTONWIDTH, BUTTONHEIGHT; +int x= -100000,y= -100000,w= -1,h= -1,gravity = NorthWestGravity; +int new_desk = 0; +int pageing_enabled = 1; +int ready = 0; + +int CurrentButton = -1; +int fd[2]; + +struct button_info Buttons[BUTTON_ARRAY_LN]; +struct folder_info Folders[FOLDER_ARRAY_LN]; + +char *iconPath = NULL; +char *pixmapPath = NULL; + +static Atom wm_del_win; +Atom _XA_WM_PROTOCOLS; +Atom _XA_WM_NAME; +#ifdef ENABLE_DND +Atom DndProtocol; +Atom DndSelection; +#endif +int TextureType=TEXTURE_BUILTIN; +char *BgPixmapFile=NULL; +int FromColor[3]={0x4000,0x4000,0x4000}, ToColor[3]={0x8000,0x8000,0x8000}; +Pixel BgColor=0; +int MaxColors=16; +int Withdrawn; + +#define DIR_TOLEFT 1 +#define DIR_TORIGHT 2 +#define DIR_TOUP 3 +#define DIR_TODOWN 4 + +#ifdef ENABLE_SOUND +void waitchild(int bullshit) +{ + int stat; + + wait(&stat); + SoundActive=0; +} +#endif + +unsigned int lock_mods[256]; +void FindLockMods(void); + + +/*********************************************************************** + * + * Procedure: + * main - start of afterstep + * + *********************************************************************** + */ +int main(int argc, char **argv) +{ + char *display_name = NULL; + int i,j; + Window root; + int x,y,border_width,button; + int depth; + char *temp, *s; + temp = argv[0]; + + s=strrchr(argv[0], '/'); + if (s != NULL) + temp = s + 1; + + MyName = safemalloc(strlen(temp)+1); + strcpy(MyName, temp); + + for(i=0;i<BUTTON_ARRAY_LN;i++) + { +#ifdef ENABLE_DND + Buttons[i].drop_action = NULL; +#endif + Buttons[i].title = NULL; + Buttons[i].action = NULL; + Buttons[i].iconno = 0; + for(j=0;j<MAX_OVERLAY;j++) { + Buttons[i].icons[j].file = NULL; + Buttons[i].icons[j].w = 0; + Buttons[i].icons[j].h = 0; + Buttons[i].icons[j].mask = None; /* pixmap for the icon mask */ + Buttons[i].icons[j].icon = None; + Buttons[i].icons[j].depth = 0; + } + Buttons[i].IconWin = None; + Buttons[i].completeIcon = None; + Buttons[i].up = 1; /* Buttons start up */ + Buttons[i].hangon = NULL; /* don't wait on anything yet*/ + Buttons[i].folder = -1; + } + signal (SIGPIPE, DeadPipe); + if((argc != 6)&&(argc != 7)) + { + fprintf(stderr,"%s Version %s should only be executed by AfterStep!\n", + MyName, VERSION); + exit(1); + } + fd[0] = atoi(argv[1]); + fd[1] = atoi(argv[2]); + + if (!(dpy = XOpenDisplay(display_name))) + { + fprintf(stderr,"%s: can't open display %s", MyName, + XDisplayName(display_name)); + exit (1); + } + x_fd = XConnectionNumber(dpy); + + fd_width = GetFdWidth(); + + screen= DefaultScreen(dpy); + Root = RootWindow(dpy, screen); + if(Root == None) + { + fprintf(stderr,"%s: Screen %d is not valid ", MyName, screen); + exit(1); + } + display_width = DisplayWidth(dpy, screen); + display_height = DisplayHeight(dpy, screen); + + d_depth = DefaultDepth(dpy, screen); + + SetMessageMask(fd, M_NEW_DESK | M_END_WINDOWLIST | M_MAP | M_WINDOW_NAME | + M_RES_CLASS | M_CONFIG_INFO | M_END_CONFIG_INFO | M_RES_NAME); +/* + sprintf(set_mask_mesg,"SET_MASK %lu\n", + (unsigned long)(M_NEW_DESK | + M_END_WINDOWLIST| + M_MAP| + M_RES_NAME| + M_RES_CLASS| + M_WINDOW_NAME)); + + SendText(fd,set_mask_mesg,0); +*/ + ParseOptions(argv[3]); + if(num_buttons == 0) + { + fprintf(stderr,"%s: No Buttons defined. Quitting\n", MyName); + exit(0); + } + +#ifdef ENABLE_SOUND + /* startup sound subsystem */ + if (SoundActive) { + if (pipe(PlayerChannel)<0) { + fprintf(stderr,"%s: could not create pipe. Disabling sound\n"); + SoundActive=0; + } else { + signal(SIGCHLD,waitchild); + SoundThread=fork(); + if (SoundThread<0) { + fprintf(stderr,"%s: could not fork(). Disabling sound", + MyName); + perror("."); + SoundActive=0; + } else if (SoundThread==0) { /* in the sound player process */ + char *margv[9], *name; + int i; + + margv[0]="ASSound"; + name = findIconFile("ASSound",ModulePath,X_OK); + if(name == NULL) { + fprintf(stderr,"Wharf: couldn't find ASSound\n"); + SoundActive = 0; + } else { + margv[1]=safemalloc(16); + close(PlayerChannel[1]); + sprintf(margv[1],"%x",PlayerChannel[0]); + if (SoundPlayer!=NULL) + margv[2]=SoundPlayer; + else + margv[2]="-"; + for(i=0;i<MAX_EVENTS;i++) { + if (Sounds[i][0]=='.') { + margv[i+3]=Sounds[i]; + } else { + margv[i+3]=safemalloc(strlen(Sounds[i]) + +strlen(SoundPath)+4); + sprintf(margv[i+3],"%s/%s",SoundPath,Sounds[i]); + } + } + margv[i+3]=NULL; + execvp(name,margv); + fprintf(stderr,"Wharf: couldn't spawn ASSound\n"); + exit(1); + } + } else { /* in parent */ + close(PlayerChannel[0]); + } + } + } +#endif + + CreateShadowGC(); + + switch (TextureType) { + case TEXTURE_PIXMAP: + if (BgPixmapFile==NULL) { + fprintf(stderr,"%s: No Button background pixmap defined.Using default\n", MyName); + goto Builtin; + } + Buttons[BACK_BUTTON].icons[0].file=BgPixmapFile; + if (GetXPMFile(BACK_BUTTON,0)) + break; + else goto Solid; + case TEXTURE_GRADIENT: + case TEXTURE_HGRADIENT: + case TEXTURE_HCGRADIENT: + case TEXTURE_VGRADIENT: + case TEXTURE_VCGRADIENT: + if (GetXPMGradient(BACK_BUTTON, FromColor, ToColor, MaxColors,TextureType)) + break; + else goto Solid; + + case TEXTURE_BUILTIN: + Builtin: + TextureType=TEXTURE_BUILTIN; +/* if (GetXPMData( BACK_BUTTON, button_xpm)) + break; +pdg */ + default: +Solid: + TextureType=TEXTURE_SOLID; + if (GetSolidXPM(BACK_BUTTON, BgColor)) + break; + else { + fprintf( stderr, "back Wharf button creation\n"); + exit(-1); + } + } + for(i=0;i<num_buttons;i++) + { + for(j=0;j<Buttons[i].iconno;j++) { + LoadIconFile(i,j); + } + } + for(i=num_folderbuttons;i<MAX_BUTTONS;i++) { + for(j=0;j<Buttons[i].iconno;j++) { + LoadIconFile(i,j); + } + } +#ifdef ENABLE_DND + DndProtocol=XInternAtom(dpy,"DndProtocol",False); + DndSelection=XInternAtom(dpy,"DndSelection",False); +#endif + + + CreateWindow(); + for(i=0;i<num_buttons;i++) { + CreateIconWindow(i, &main_win); + } + for(i=num_folderbuttons;i<MAX_BUTTONS;i++) + CreateIconWindow(i, Buttons[i].parent); + XGetGeometry(dpy,main_win,&root,&x,&y, + (unsigned int *)&Width,(unsigned int *)&Height, + (unsigned int *)&border_width,(unsigned int *)&depth); + + for(i=0;i<num_rows;i++) + for(j=0;j<num_columns; j++) + { + button = i*num_columns + j; + ConfigureIconWindow(button,i,j); + }; + for(i=0;i<num_folders;i++) + for(j=0;j<Folders[i].count;j++) + if(num_columns < num_rows) { + ConfigureIconWindow(Folders[i].firstbutton+j,0, j); + } else { + ConfigureIconWindow(Folders[i].firstbutton+j,j, 0); + } + /* dirty hack to make swallowed app background be textured */ + XSetWindowBackgroundPixmap(dpy, main_win, Buttons[BACK_BUTTON].icons[0].icon); + XMapSubwindows(dpy,main_win); + XMapWindow(dpy,main_win); + for(i=0;i<num_folders;i++) + XMapSubwindows(dpy, Folders[i].win); + + FindLockMods(); + + /* request a window list, since this triggers a response which + * will tell us the current desktop and paging status, needed to + * indent buttons correctly */ + SendText(fd,"Send_WindowList",0); + Loop(); + return 0; +} + +/*********************************************************************** + * + * Procedure: + * Loop - wait for data to process + * + ***********************************************************************/ + +void Loop(void) +{ + Window *CurrentWin=None; + int x,y,CurrentRow,CurrentColumn,CurrentBase=0; + XEvent Event; + int NewButton,i=0,j=0,i2, bl=-1; + int LastMapped=-1; + time_t t, tl = (time_t) 0; + int CancelPush=0; + + while(1) + { + if(My_XNextEvent(dpy,&Event)) + { + switch(Event.type) + { + + case Expose: + for(x=0;x<num_folders;x++) + if(Event.xany.window == Folders[x].win ) + { + RedrawWindow(&Folders[x].win,num_folderbuttons, -1, Folders[x].cols,Folders[x].rows); + for(y=1;y<=Folders[x].count;y++) + if(num_columns<num_rows) + RedrawUnpushedOutline(&Folders[x].win, 1, y); + else + RedrawUnpushedOutline(&Folders[x].win, y, 1); + } + if (Pushed) + break; + if((Event.xexpose.count == 0)&& + (Event.xany.window == main_win)) + { + if(ready < 1) + ready ++; + RedrawWindow(&main_win,0, -1, num_rows, num_columns); + } + break; + + case ButtonPress: + if (Event.xbutton.button != Button1) { + if (Event.xbutton.button == Button2) { + static int LastX, LastY; + + if (LastMapped != -1) { + CloseFolder(LastMapped); + Folders[LastMapped].mapped = NOTMAPPED; + LastMapped=-1; + } + if (Withdrawn) { +#ifdef ENABLE_SOUND + PlaySound(WHEV_OPEN_MAIN); +#endif + if (AnimationStyle>0 && AnimateMain) + OpenFolder(-1,LastX,LastY,Width,Height, + AnimationDir); + else + XMoveResizeWindow(dpy,main_win,LastX,LastY, + Width,Height); + Withdrawn=0; + } else { + Window junk; + int junk2,junk3,junk4,junk5; + int CornerX, CornerY; + +#ifdef ENABLE_SOUND + PlaySound(WHEV_CLOSE_MAIN); +#endif + XGetGeometry(dpy,main_win,&junk,&LastX,&LastY, + &junk2,&junk3,&junk4,&junk5); + XTranslateCoordinates(dpy,main_win,Root, + LastX,LastY, + &LastX,&LastY,&junk); + if (num_rows<num_columns) { /* horizontal */ + if (LastY > display_height/2) { + CornerY = display_height-BUTTONHEIGHT; + } else { + CornerY = 0; + } + if (Event.xbutton.x>num_columns*BUTTONWIDTH/2) { + CornerX = display_width - BUTTONWIDTH; + AnimationDir = DIR_TOLEFT; + } else { + CornerX = 0; + AnimationDir = DIR_TORIGHT; + } + if (AnimationStyle>0 && AnimateMain) { + CloseFolder(-1); + XMoveWindow(dpy,main_win, CornerX, CornerY); + } else { + XMoveResizeWindow(dpy,main_win, + CornerX, CornerY, + BUTTONWIDTH,BUTTONHEIGHT); + } + } else { /* vertical */ + if (LastX > display_width/2) { + CornerX = display_width - BUTTONWIDTH; + } else { + CornerX = 0; + } + if (Event.xbutton.y>num_rows*BUTTONHEIGHT/2) { + CornerY = display_height-BUTTONHEIGHT; + AnimationDir = DIR_TOUP; + } else { + CornerY = 0; + AnimationDir = DIR_TODOWN; + } + if (AnimationStyle>0 && AnimateMain) { + CloseFolder(-1); + XMoveWindow(dpy,main_win, CornerX, CornerY); + } else { + XMoveResizeWindow(dpy,main_win, + CornerX, CornerY, + BUTTONWIDTH,BUTTONHEIGHT); + } + } + Withdrawn=1; + } + } + break; + } +#ifdef ENABLE_SOUND + PlaySound(WHEV_PUSH); +#endif + CancelPush = 0; + CurrentWin = &Event.xbutton.window; + CurrentBase = 0; + CurrentRow = (Event.xbutton.y/BUTTONHEIGHT); + CurrentColumn = (Event.xbutton.x/BUTTONWIDTH); + if (*CurrentWin!=main_win) { + CurrentButton = CurrentBase + CurrentColumn*num_rows + + CurrentRow*num_columns; + } else { + CurrentButton = CurrentBase + CurrentColumn + + CurrentRow*num_columns; + if (CurrentButton>=num_buttons) { + CurrentButton = -1; + break; + } + } + + for(x=0;x<num_buttons;x++) + { + if (*CurrentWin == Buttons[x].IconWin) + { + CurrentButton = x; + CurrentRow = x / num_columns; + CurrentColumn = x % num_columns; + } + } + + for(x=0;x<num_folders;x++) + if(*CurrentWin == Folders[x].win) + { + CurrentBase = Folders[x].firstbutton; + if (num_rows<num_columns) + CurrentButton = CurrentBase + CurrentRow; + else + CurrentButton = CurrentBase + CurrentColumn; + } + i = CurrentRow+1; + j = CurrentColumn +1; + + if (Buttons[CurrentButton].swallow == 1 || + Buttons[CurrentButton].swallow == 2 || + Buttons[CurrentButton].action == NULL) + break; + + if (Pushable) + { + if (Buttons[CurrentButton].swallow != 3 && + Buttons[CurrentButton].swallow != 4) + { + Pushed = 1; + RedrawPushed(CurrentWin, i, j); + } + } + if (strncasecmp(Buttons[CurrentButton].action,"Folder",6)==0) { + Window junk; + int junk2,junk3,junk4,junk5; + XGetGeometry(dpy,main_win,&junk,&x,&y, + &junk2,&junk3,&junk4,&junk5); + XTranslateCoordinates(dpy,main_win,Root, + x,y, + &x,&y,&junk); +/* kludge until Beat takes a look */ +if ((num_columns == 1) && (num_rows == 1)) + MapFolder(Buttons[CurrentButton].folder, + &LastMapped, + x, y, + 1,1); +else + MapFolder(Buttons[CurrentButton].folder, + &LastMapped, + x, y, + CurrentRow, CurrentColumn); + } + break; + case EnterNotify: + CancelPush = 0; + break; + case LeaveNotify: + CancelPush = 1; + break; +#ifdef ENABLE_DND + case ClientMessage: + if (Event.xclient.message_type==DndProtocol) { + unsigned long dummy_r,size; + Atom dummy_a; + int dummy_f; + unsigned char *data, *Command; + + Window dummy_rt, dummy_c; + int dummy_x, dummy_y, base, pos_x, pos_y; + unsigned int dummy; + +/* if (Event.xclient.data.l[0]!=DndFile || + Event.xclient.data.l[0]!=DndFiles || + Event.xclient.data.l[0]!=DndExe + ) + break; */ + + XQueryPointer(dpy,main_win, + &dummy_rt,&dummy_c, + &dummy_x,&dummy_y, + &pos_x,&pos_y, + &dummy); + base = 0; + dummy_y = (pos_y/BUTTONHEIGHT); + dummy_x= (pos_x/BUTTONWIDTH); + dummy = base + dummy_x + dummy_y*num_columns; + + /* + for(x=0;x<num_folders;x++) { + if(Event.xbutton.window == Folders[x].win) { + base = Folders[x].firstbutton; + dummy = base + dummy_y + dummy_x -1; + } + } */ + if (Buttons[dummy].drop_action == NULL) + break; + dummy_x++; + dummy_y++; + CurrentWin=Buttons[dummy].parent; + if (Pushable) { + RedrawPushedOutline(CurrentWin, dummy_y, dummy_x); + XSync(dpy, 0); + } + XGetWindowProperty(dpy, Root, DndSelection, 0L, + 100000L, False, AnyPropertyType, + &dummy_a, &dummy_f, + &size,&dummy_r, + &data); + if (Event.xclient.data.l[0]==DndFiles) { + for (dummy_r = 0; dummy_r<size-1; dummy_r++) { + if (data[dummy_r]==0) + data[dummy_r]=' '; + } + } +#ifdef ENABLE_SOUND + PlaySound(WHEV_DROP); +#endif + Command=(unsigned char *)safemalloc(strlen((char *)data) + + strlen((char *)(Buttons[dummy].drop_action))); + sprintf((char *)Command,Buttons[dummy].drop_action, + data,Event.xclient.data.l[0]); + SendInfo(fd,(char *)Command,0); + free(Command); + if (Pushable) { + usleep(50000); + XClearWindow(dpy,Buttons[dummy].IconWin); + RedrawUnpushedOutline(CurrentWin, dummy_y, dummy_x); + } + } + break; +#endif /* ENABLE_DND */ + case ButtonRelease: + if ((Event.xbutton.button != Button1) || + (Buttons[CurrentButton].swallow == 1) || + (Buttons[CurrentButton].swallow == 2) || + (Buttons[CurrentButton].action == NULL)) { + break; + } + + CurrentRow = (Event.xbutton.y/BUTTONHEIGHT); + CurrentColumn = (Event.xbutton.x/BUTTONWIDTH); + + if (Pushable) + { + if (Buttons[CurrentButton].swallow != 3 && + Buttons[CurrentButton].swallow != 4) + { + Pushed=0; + RedrawUnpushed(CurrentWin, i, j); + } + } + if (CancelPush) + break; + if (*CurrentWin!=main_win) { + NewButton = CurrentBase + CurrentColumn*num_rows + + CurrentRow*num_columns; + } else { + NewButton = CurrentBase + CurrentColumn + + CurrentRow*num_columns; + } + + for(x=0;x<num_folders;x++) + if(*CurrentWin == Folders[x].win) + { + if (num_rows<num_columns) + NewButton = Folders[x].firstbutton + CurrentRow; + else + NewButton = Folders[x].firstbutton + CurrentColumn; + } + for (x=0;x<num_buttons;x++) + { + if (*CurrentWin == Buttons[x].IconWin) + { + NewButton = x; + CurrentRow = x / num_columns; + CurrentColumn = x % num_columns; + } + } + + if(NewButton == CurrentButton) + { + t = time( 0); + bl = -1; + tl = -1; + if(strncasecmp(Buttons[CurrentButton].action,"Folder",6)!=0) + { + if (LastMapped != -1 && CurrentWin != &main_win) + { + CloseFolder(LastMapped); + Folders[LastMapped].mapped = NOTMAPPED; + LastMapped = -1; + } + SendInfo(fd,Buttons[CurrentButton].action,0); + } + if((Buttons[CurrentButton].action)&& + (strncasecmp(Buttons[CurrentButton].action,"exec",4)== 0)) + { + i=4; + while((Buttons[CurrentButton].action[i] != 0)&& + (Buttons[CurrentButton].action[i] != '"')) + i++; + i2=i+1; + + while((Buttons[CurrentButton].action[i2] != 0)&& + (Buttons[CurrentButton].action[i2] != '"')) + i2++; + if(i2 - i >1) + { + Buttons[CurrentButton].hangon = safemalloc(i2-i); + strncpy(Buttons[CurrentButton].hangon, + &Buttons[CurrentButton].action[i+1],i2-i-1); + Buttons[CurrentButton].hangon[i2-i-1] = 0; + Buttons[CurrentButton].up = 0; + if (Buttons[CurrentButton].swallow == 3 || + Buttons[CurrentButton].swallow == 4) + Buttons[CurrentButton].swallow = 4; + else + Buttons[CurrentButton].swallow = 0; + } + } + } + break; + + /* + case ClientMessage: + if ((Event.xclient.format==32) && + (Event.xclient.data.l[0]==wm_del_win)) + { + DeadPipe(1); + } + break; + case PropertyNotify: + if (Pushed) + break; + for(i=0;i<num_rows;i++) + for(j=0;j<num_columns; j++) + { + button = i*num_columns + j; + if(((Buttons[button].swallow == 3)|| + (Buttons[button.swallow == 4))&& + (Event.xany.window == Buttons[button].IconWin)&& + (Event.xproperty.atom == XA_WM_NAME)) + { + XFetchName(dpy, Buttons[button].IconWin, &temp); + if(strcmp(Buttons[button].title,"-")!=0) + CopyString(&Buttons[button].title, temp); + XFree(temp); + XClearArea(dpy,main_win,j*BUTTONWIDTH, + i*BUTTONHEIGHT, BUTTONWIDTH,BUTTONHEIGHT,0); + RedrawWindow(&main_win,0, button, num_rows, num_columns); + } + } + break; + */ + default: + break; + } + } + } +} + +void OpenFolder(int folder,int x, int y, int w, int h, int direction) +{ + int winc, hinc; + int cx, cy, cw, ch; + Window win; + int isize; + + if (folder<0) { + winc = BUTTONWIDTH/ANIM_STEP_MAIN; + hinc = BUTTONHEIGHT/ANIM_STEP_MAIN; + } else { + winc = BUTTONWIDTH/ANIM_STEP; + hinc = BUTTONHEIGHT/ANIM_STEP; + } + + if (folder>=0) { + win = Folders[folder].win; + Folders[folder].direction = direction; + if (direction == DIR_TOLEFT || direction == DIR_TORIGHT) + isize = winc; + else + isize = hinc; + } else { + win = main_win; + if (direction == DIR_TOLEFT || direction == DIR_TORIGHT) + isize = BUTTONWIDTH; + else + isize = BUTTONHEIGHT; + } + cx = x; cy = y; + ch = h; cw = w; + if (AnimationStyle==0) { + XMapWindow(dpy, win); + } else + switch (direction) { + case DIR_TOLEFT: + cx = x+w; + XMoveResizeWindow(dpy,win,cx,y, 1, h); + XMapWindow(dpy, win); + for(cw=isize;cw<=w;cw+=winc) { + cx -= winc; + usleep(ANIM_DELAY/2); + XMoveResizeWindow(dpy,win,cx,y, cw,h); + XSync(dpy,0); + } + break; + case DIR_TORIGHT: + XMoveResizeWindow(dpy,win,x,y, 1, h); + XMapWindow(dpy, win); + for(cw=isize;cw<=w;cw+=winc) { + usleep(ANIM_DELAY/2); + XMoveResizeWindow(dpy,win,x,y, cw,h); + XSync(dpy,0); + } + break; + case DIR_TOUP: + cy = y+h; + XMoveResizeWindow(dpy,win,x,cy, w, 1); + XMapWindow(dpy, win); + for(ch=isize;ch<=h;ch+=hinc) { + cy -= hinc; + usleep(ANIM_DELAY/2); + XMoveResizeWindow(dpy,win,x,cy, w, ch); + XSync(dpy,0); + } + break; + case DIR_TODOWN: + XMoveResizeWindow(dpy,win,x,y, w, 1); + XMapWindow(dpy, win); + for(ch=isize;ch<=h;ch+=hinc) { + usleep(ANIM_DELAY/2); + XMoveResizeWindow(dpy,win,x,y, w, ch); + XSync(dpy,0); + } + break; + default: + XBell(dpy,100); + fprintf(stderr,"WHARF INTERNAL BUG in OpenFolder()\n"); + exit(-1); + } + + if (cw!=w || ch!=h || x != cx || cy != y || AnimationStyle==0) + XMoveResizeWindow(dpy,win,x,y,w,h); +} + + + +void CloseFolder(int folder) +{ + int winc, hinc; + int cx, cy, cw, ch; + int x,y,w,h, junk_depth, junk_bd; + int fsize, direction; + Window win, junk_win; + +#ifdef ENABLE_SOUND + PlaySound(WHEV_CLOSE_FOLDER); +#endif + if (folder<0) { + winc = BUTTONWIDTH/ANIM_STEP_MAIN; + hinc = BUTTONHEIGHT/ANIM_STEP_MAIN; + } else { + winc = BUTTONWIDTH/ANIM_STEP; + hinc = BUTTONHEIGHT/ANIM_STEP; + } + if (folder < 0) { + win = main_win; + direction = AnimationDir; + if (direction==DIR_TOUP || direction==DIR_TODOWN) + fsize=BUTTONHEIGHT; + else + fsize=BUTTONWIDTH; + } else { + direction = Folders[folder].direction; + win = Folders[folder].win; + if (direction==DIR_TOUP || direction==DIR_TODOWN) + fsize=hinc; + else + fsize=winc; + } + if (AnimationStyle==0) { + goto end; + } + XGetGeometry(dpy,win,&junk_win,&x,&y,&w,&h,&junk_bd,&junk_depth); + XTranslateCoordinates(dpy,win,Root,x,y,&x,&y,&junk_win); + switch (direction) { + case DIR_TOLEFT: + cx = x; + for(cw=w;cw >= fsize; cw-=winc) { + XMoveResizeWindow(dpy,win,cx,y, cw,h); + XSync(dpy,0); + usleep(ANIM_DELAY); + cx += winc; + } + break; + case DIR_TORIGHT: + for(cw=w;cw >= fsize; cw-=winc) { + XMoveResizeWindow(dpy,win,x,y, cw,h); + XSync(dpy,0); + usleep(ANIM_DELAY); + } + break; + case DIR_TOUP: + cy = y; + for(ch=h;ch >= fsize; ch-=hinc) { + XMoveResizeWindow(dpy,win,x,cy, w,ch); + XSync(dpy,0); + usleep(ANIM_DELAY); + cy += hinc; + } + break; + case DIR_TODOWN: + for(ch=h;ch >= fsize; ch-=hinc) { + XMoveResizeWindow(dpy,win,x,y, w, ch); + XSync(dpy,0); + usleep(ANIM_DELAY); + } + break; + default: + XBell(dpy,100); + fprintf(stderr,"WHARF INTERNAL BUG in CloseFolder()\n"); + exit(-1); + } + Folders[folder].direction = 0; + end: + if (folder<0) { + XResizeWindow(dpy,win,BUTTONWIDTH,BUTTONHEIGHT); + } else { + XUnmapWindow(dpy,win); + } +} + + +void MapFolder(int folder, int *LastMapped, int base_x, int base_y, int row, int col) +{ + int dir; + + if (Folders[folder].mapped ==ISMAPPED) + { + CloseFolder(folder); + Folders[folder].mapped = NOTMAPPED; + *LastMapped = -1; + } + else + { + int folderx, foldery, folderw, folderh; + if (*LastMapped != -1) + { + CloseFolder(*LastMapped); + Folders[*LastMapped].mapped = NOTMAPPED; + *LastMapped = -1; + } + Folders[folder].mapped = ISMAPPED; + if(num_columns < num_rows) + { + if((base_x % display_width) > display_width / 2 ) { + folderx = base_x+(col-Folders[folder].count)*BUTTONWIDTH-2; + dir = DIR_TOLEFT; + } + else { + folderx = base_x+(col+1)*BUTTONHEIGHT+1; + dir = DIR_TORIGHT; + } + foldery = base_y+row*BUTTONHEIGHT; + folderw = Folders[folder].count*BUTTONWIDTH; + folderh = BUTTONHEIGHT; + } +/* more kludgery */ + else if (num_columns == num_rows) + { +/* + if((base_x % display_width) > display_width / 2 ) + folderx = (col-Folders[folder].count)*BUTTONHEIGHT-2; + else + folderx = (col+1)*BUTTONHEIGHT+1; +*/ + if (ROWS) + { + if ((base_y % display_height) > display_height / 2) { + foldery = base_y-(Folders[folder].count)*BUTTONHEIGHT-2; + dir = DIR_TOUP; + } + else { + foldery = base_y+BUTTONHEIGHT+2; + dir = DIR_TODOWN; + } + folderx = base_x; + folderw = BUTTONWIDTH; + folderh = (Folders[folder].count)*BUTTONHEIGHT; + } + else + { + if((base_x % display_width) > display_width / 2 ) { + folderx = base_x-(Folders[folder].count)*BUTTONWIDTH-2; + dir = DIR_TOLEFT; + } + else { + folderx = base_x+BUTTONWIDTH+1; + dir = DIR_TORIGHT; + } + foldery = base_y-1; + folderh = BUTTONHEIGHT; + folderw = (Folders[folder].count)*BUTTONWIDTH; + } + } + else + { + if ((base_y % display_height) < display_height / 2) { + foldery =base_y+(row+1)*BUTTONHEIGHT; + dir = DIR_TODOWN; + } + else { + foldery = base_y+(row-Folders[folder].count)*BUTTONHEIGHT; + dir = DIR_TOUP; + } + folderx = base_x+col*BUTTONWIDTH; + folderw = BUTTONWIDTH; + folderh = (Folders[folder].count)*BUTTONHEIGHT; + } + +#ifdef ENABLE_SOUND + PlaySound(WHEV_OPEN_FOLDER); +#endif + XMoveWindow(dpy, Folders[folder].win, folderx, foldery); + OpenFolder(folder,folderx, foldery, folderw, folderh, dir); + *LastMapped = folder; + } +} + +void +DrawOutline(Drawable d, int w, int h) +{ + if (NoBorder) + return; +/* top */ + XDrawLine( dpy, d, HiInnerGC, 0, 0, w-1, 0); + /* + XDrawLine( dpy, d, HiInnerGC, 0, 1, w-1, 1); +*/ +/* bottom */ + XFillRectangle(dpy, d, NormalGC, 0,h-2,w-1,h-1); + +/* left */ + XDrawLine( dpy, d, HiInnerGC, 0, 1, 0, h-1); + /* + XDrawLine( dpy, d, HiInnerGC, 1, 2, 1, h-2); + */ +/* right */ + XDrawLine( dpy, d, NormalGC, w-1, 1, w-1, h-1); + XDrawLine( dpy, d, NormalGC, w-2, 2, w-2, h-2); +} + +void RedrawUnpushed(Window *win, int i, int j) +{ + if (PushStyle!=0) { + XMoveResizeWindow(dpy, Buttons[CurrentButton].IconWin, + (j-1)*BUTTONWIDTH ,(i-1)*BUTTONHEIGHT, + BUTTONWIDTH, BUTTONHEIGHT); + } else { + XCopyArea( dpy, Buttons[CurrentButton].completeIcon, + Buttons[CurrentButton].IconWin, NormalGC, 0, 0, + Buttons[BACK_BUTTON].icons[0].w, + Buttons[BACK_BUTTON].icons[0].h, + 0,0); + } + RedrawWindow(win,0, CurrentButton, num_rows, num_columns); + + RedrawUnpushedOutline(win, i, j); +} + +void RedrawUnpushedOutline(Window *win, int i, int j) +{ +/* top */ + if (NoBorder) { + return; + } + + XDrawLine( dpy, *win, HiInnerGC, + j*BUTTONWIDTH-BUTTONWIDTH, i*BUTTONHEIGHT-BUTTONHEIGHT, + j*BUTTONWIDTH,i*BUTTONHEIGHT-BUTTONHEIGHT); +/* + XDrawLine( dpy, *win, HiInnerGC, j*BUTTONWIDTH-BUTTONWIDTH, + i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH, + i*BUTTONHEIGHT-BUTTONHEIGHT+1); + */ + /* left */ + XDrawLine( dpy, *win, HiInnerGC, j*BUTTONWIDTH-BUTTONWIDTH, + i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH-BUTTONWIDTH, + i*BUTTONHEIGHT-1); + /* + XDrawLine( dpy, *win, HiInnerGC, j*BUTTONWIDTH + -BUTTONWIDTH+1, i*BUTTONHEIGHT-BUTTONHEIGHT+2, + j*BUTTONWIDTH-BUTTONWIDTH+1 ,i*BUTTONHEIGHT-1); + */ + /* right */ + XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH + +BUTTONWIDTH-2, i*BUTTONHEIGHT-BUTTONHEIGHT+2, j*BUTTONWIDTH + -BUTTONWIDTH+BUTTONWIDTH-2 ,i*BUTTONHEIGHT-1); + + XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH + +BUTTONWIDTH-1, i*BUTTONHEIGHT-BUTTONHEIGHT+1, + j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-1 ,i*BUTTONHEIGHT-1); + + /* bottom */ + XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH + -BUTTONWIDTH+1, i*BUTTONHEIGHT-1, j*BUTTONWIDTH-BUTTONWIDTH + +BUTTONWIDTH-2,i*BUTTONHEIGHT-1); + + XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH + +1, i*BUTTONHEIGHT-2, j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-2, + i*BUTTONHEIGHT-2); +} + +void RedrawPushed(Window *win, int i,int j) +{ + if (PushStyle!=0) { + XMoveResizeWindow(dpy, Buttons[CurrentButton].IconWin, + 2+(j-1)*BUTTONWIDTH,(i-1)*BUTTONHEIGHT+2, + BUTTONWIDTH-2, BUTTONHEIGHT-2); + } else { + XCopyArea( dpy, Buttons[CurrentButton].completeIcon, + Buttons[CurrentButton].IconWin, NormalGC, 2, 2, + Buttons[BACK_BUTTON].icons[0].w-2, + Buttons[BACK_BUTTON].icons[0].h-2, 4, 4); + XCopyArea( dpy, Buttons[BACK_BUTTON].icons[0].icon, + Buttons[CurrentButton].IconWin, NormalGC, 2, 2, + 2, BUTTONHEIGHT, 2, 2); + XCopyArea( dpy, Buttons[BACK_BUTTON].icons[0].icon, + Buttons[CurrentButton].IconWin, NormalGC, 2, 2, + BUTTONWIDTH, 2, 2, 2); + } + RedrawWindow(win,0, CurrentButton, num_rows, num_columns); + RedrawPushedOutline(win, i,j); +} + +void RedrawPushedOutline(Window *win, int i, int j) +{ + GC gc1; + /* Top Hilite */ + XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH, + i*BUTTONHEIGHT-BUTTONHEIGHT, j*BUTTONWIDTH,i*BUTTONHEIGHT + -BUTTONHEIGHT); +/* + XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH, + i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH,i*BUTTONHEIGHT + -BUTTONHEIGHT+1); + */ + /* Left Hilite */ + + XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH, + i*BUTTONHEIGHT-BUTTONHEIGHT+1, j*BUTTONWIDTH-BUTTONWIDTH, + i*BUTTONHEIGHT-1); + /* + XDrawLine( dpy, *win, NormalGC, j*BUTTONWIDTH-BUTTONWIDTH + +1, i*BUTTONHEIGHT-BUTTONHEIGHT+2, j*BUTTONWIDTH-BUTTONWIDTH+1, + i*BUTTONHEIGHT-1); + */ + if (PushStyle!=0) { + gc1 = HiReliefGC; + } else { + gc1 = HiInnerGC; + } + + /* Right Hilite */ + + XDrawLine( dpy, *win, HiReliefGC, j*BUTTONWIDTH + -BUTTONWIDTH+BUTTONWIDTH-2, i*BUTTONHEIGHT-BUTTONHEIGHT+2, + j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-2 ,i*BUTTONHEIGHT-1); + + XDrawLine( dpy, *win, gc1, j*BUTTONWIDTH + -BUTTONWIDTH+BUTTONWIDTH-1, i*BUTTONHEIGHT-BUTTONHEIGHT+1, + j*BUTTONWIDTH-BUTTONWIDTH+BUTTONWIDTH-1 ,i*BUTTONHEIGHT-1); + + /* Bottom Hilite */ + XDrawLine( dpy, *win, gc1, j*BUTTONWIDTH + -BUTTONWIDTH+1, i*BUTTONHEIGHT-1, j*BUTTONWIDTH-BUTTONWIDTH + +BUTTONWIDTH-2,i*BUTTONHEIGHT-1); + + XDrawLine( dpy, *win, HiReliefGC, j*BUTTONWIDTH + -BUTTONWIDTH+1, i*BUTTONHEIGHT-2, j*BUTTONWIDTH-BUTTONWIDTH + +BUTTONWIDTH-2,i*BUTTONHEIGHT-2); +} +/************************************************************************ + * + * Draw the window + * + ***********************************************************************/ +void RedrawWindow(Window *win, int firstbutton, int newbutton, + int num_rows, int num_columns) +{ + int i,j,button; + XEvent dummy; + + if(ready < 1) + return; + + while (XCheckTypedWindowEvent (dpy, *win, Expose, &dummy)); + + for(i=0;i<num_rows;i++) + for(j=0;j<num_columns; j++) + { + button = firstbutton+i*num_columns + j; + if((newbutton == -1)||(newbutton == button)) + { + if(((Buttons[button].swallow == 3)|| + (Buttons[button].swallow == 4))&& + (Buttons[button].IconWin != None)) + XSetWindowBorderWidth(dpy,Buttons[button].IconWin,0); + } + RedrawUnpushedOutline(win,i,j); + } +} + + +/******************************************************************* + * + * Create GC's + * + ******************************************************************/ +void CreateShadowGC(void) +{ + XGCValues gcv; + unsigned long gcm; + + if(d_depth < 2) + { + back_pix = GetColor("white"); + fore_pix = GetColor("black"); + } + else + { + if (TextureType>0 && TextureType < 128) { + MakeShadowColors(dpy, FromColor, ToColor, &fore_pix, &light_grey); + } else { + back_pix = GetColor("grey40"); + fore_pix = GetColor("grey17"); + light_grey = GetColor("white"); + } + } + gcm = GCForeground|GCBackground|GCSubwindowMode; + gcv.subwindow_mode = IncludeInferiors; + + gcv.foreground = fore_pix; + gcv.background = back_pix; + NormalGC = XCreateGC(dpy, Root, gcm, &gcv); + + gcv.foreground = back_pix; + gcv.background = fore_pix; + HiReliefGC = XCreateGC(dpy, Root, gcm, &gcv); + + gcv.foreground = light_grey; + gcv.background = fore_pix; + HiInnerGC = XCreateGC(dpy, Root, gcm, &gcv); + + gcm = GCForeground; + gcv.foreground = fore_pix; + MaskGC = XCreateGC(dpy, Root, gcm, &gcv); + + DefGC = DefaultGC(dpy, screen); +} + +/************************************************************************ + * + * Sizes and creates the window + * + ***********************************************************************/ +void CreateWindow(void) +{ + int first_avail_button,i; + + wm_del_win = XInternAtom(dpy,"WM_DELETE_WINDOW",False); + _XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False); + + /* Allow for multi-width/height buttons */ + first_avail_button = num_buttons; + + if(num_buttons > MAX_BUTTONS) + { + fprintf(stderr,"%s: Out of Buttons!\n",MyName); + exit(0); + } + + /* size and create the window */ + if((num_rows == 0)&&(num_columns == 0)) + num_columns = 1; + if(num_columns == 0) + { + num_columns = num_buttons/num_rows; + while(num_rows * num_columns < num_buttons) + num_columns++; + } + if(num_rows == 0) + { + num_rows = num_buttons/num_columns; + while(num_rows * num_columns < num_buttons) + num_rows++; + } + + while(num_rows * num_columns < num_buttons) + num_columns++; + + mysizehints.flags = PWinGravity| PResizeInc | PBaseSize; + /* subtract one for the right/bottom border */ + mysizehints.width = BUTTONWIDTH*num_columns; + mysizehints.height= BUTTONHEIGHT*num_rows; + mysizehints.width_inc = num_columns; + mysizehints.height_inc = num_rows; + mysizehints.base_height = num_rows - 1; + mysizehints.base_width = num_columns - 1; + + if(x > -100000) + { + if (x <= -1) + { + mysizehints.x = DisplayWidth(dpy,screen) + x - mysizehints.width-1; + gravity = NorthEastGravity; + } + else if ((x == 0) && (flags & 16)) + mysizehints.x = DisplayWidth(dpy,screen) - mysizehints.width-2; + else + mysizehints.x = x; + if ( y<0) + { + mysizehints.y = DisplayHeight(dpy,screen) + y - mysizehints.height-2; + gravity = SouthWestGravity; + } + else + mysizehints.y = y; + + if((x < 0) && (y < 0)) + gravity = SouthEastGravity; + mysizehints.flags |= USPosition; + } + + mysizehints.win_gravity = gravity; + + main_win = XCreateSimpleWindow(dpy,Root,mysizehints.x,mysizehints.y, + mysizehints.width,mysizehints.height, + 0,0,back_pix); + + for(i=0;i<num_folders;i++) + { + if(num_columns <num_rows) + { + Folders[i].cols = 1; + Folders[i].rows = Folders[i].count; + } + else if ((num_columns == num_rows) && (!ROWS)) + { + Folders[i].cols = 1; + Folders[i].rows = Folders[i].count; + } + else + { + Folders[i].cols = Folders[i].count; + Folders[i].rows = 1; + } + Folders[i].win = XCreateSimpleWindow(dpy, Root, 0,0, + BUTTONWIDTH*Folders[i].rows,BUTTONHEIGHT*Folders[i].cols, + 0,0,back_pix); + XSetWMNormalHints(dpy,Folders[i].win,&mysizehints); + XSelectInput(dpy, Folders[i].win, MW_EVENTS); + } + + XSetWMProtocols(dpy,main_win,&wm_del_win,1); + + XSetWMNormalHints(dpy,main_win,&mysizehints); + + XSelectInput(dpy, main_win, MW_EVENTS); + change_window_name(MyName); +} + + +void nocolor(char *a, char *b) +{ + fprintf(stderr,"%s: can't %s %s\n", MyName, a,b); +} + +/**************************************************************************** + * + * Loads a single color + * + ****************************************************************************/ +Pixel GetColor(char *name) +{ + XColor color; + XWindowAttributes attributes; + + XGetWindowAttributes(dpy,Root,&attributes); + color.pixel = 0; + if (!XParseColor (dpy, attributes.colormap, name, &color)) + { + nocolor("parse",name); + } + else if(!XAllocColor (dpy, attributes.colormap, &color)) + { + nocolor("alloc",name); + } + return color.pixel; +} + +/************************************************************************ + * + * Dead pipe handler + * + ***********************************************************************/ +void DeadPipe(int nonsense) +{ + int i,j,button; + +#ifdef ENABLE_SOUND + int val=-1; + write(PlayerChannel[1],&val,sizeof(val)); + if (SoundThread != 0) + kill(SoundThread,SIGUSR1); +#endif + for(i=0;i<num_rows;i++) + for(j=0;j<num_columns; j++) + { + button = i*num_columns + j; + /* delete swallowed windows, but not modules (afterstep handles those) */ + if(((Buttons[button].swallow == 3)||(Buttons[button].swallow == 4))&& + (Buttons[button].module == 0)) + { + my_send_clientmessage(Buttons[button].IconWin,wm_del_win,CurrentTime); + XSync(dpy,0); + } + } + XSync(dpy,0); + exit(0); +} + +int TOTHEFOLDER = -1; +/***************************************************************************** + * + * This routine is responsible for reading and parsing the config file + * + ****************************************************************************/ +void ParseOptions(char *filename) +{ + char *tline,*orig_tline,*tmp; + int Clength, len; + + GetConfigLine(fd, &tline); + orig_tline = tline; + Clength = strlen(MyName); + while(tline != NULL && tline[0] != '\0') + { + int g_x, g_y; + unsigned width,height; + while(isspace(*tline))tline++; + + if((strlen(&tline[0])>1)&& + (strncasecmp(tline,CatString3("*", MyName, "Geometry"),Clength+9)==0)) + { + tmp = &tline[Clength+9]; + while(((isspace(*tmp))&&(*tmp != '\n'))&&(*tmp != 0)) + { + tmp++; + } + tmp[strlen(tmp)-1] = 0; + + flags = XParseGeometry(tmp,&g_x,&g_y,&width,&height); + if (flags & WidthValue) + w = width; + if (flags & HeightValue) + h = height; + if (flags & XValue) + x = g_x; + if (flags & YValue) + y = g_y; + } + else if((strlen(&tline[0])>1)&& + (strncasecmp(tline,CatString3("*",MyName,"Rows"),Clength+5)==0)) + { + len=sscanf(&tline[Clength+5],"%d",&num_rows); + if(len < 1) + num_rows = 0; + ROWS = TRUE; + } + else if((strlen(&tline[0])>1)&& + (strncasecmp(tline,CatString3("*",MyName,"Columns"),Clength+8)==0)) + { + len=sscanf(&tline[Clength+8],"%d",&num_columns); + if(len < 1) + num_columns = 0; + ROWS = FALSE; + } + else if((strlen(&tline[0])>1)&& + (strncasecmp(tline,CatString3("*",MyName,"NoPush"),Clength+5)==0)) + { + Pushable = 0; + } else if((strlen(&tline[0])>1)&& + (strncasecmp(tline,CatString3("*",MyName,"FullPush"),Clength+9)==0)) + { + PushStyle = 1; + } else if((strlen(&tline[0])>1)&& + (strncasecmp(tline,CatString3("*",MyName,"NoBorder"),Clength+9)==0)) + { + NoBorder = 1; + } else if ((strlen(&tline[0])>1) + &&(strncasecmp(tline,CatString3("*",MyName,"ForceSize"),Clength+10)==0)) { + ForceSize = 1; + } else if ((strlen(&tline[0])>1) + &&(strncasecmp(tline,CatString3("*",MyName,"TextureType"),Clength+12)==0)) { + if (sscanf(&tline[Clength+12],"%d",&TextureType)<1) + TextureType = TEXTURE_BUILTIN; + } else if ((strlen(&tline[0])>1) + &&(strncasecmp(tline,CatString3("*",MyName,"MaxColors"),Clength+10)==0)) { + + if (sscanf(&tline[Clength+10],"%d",&MaxColors)<1) + MaxColors = 16; + } else if ((strlen(&tline[0])>1) + &&(strncasecmp(tline,CatString3("*",MyName,"BgColor"),Clength+8)==0)) { + char *tmp; + tmp=safemalloc(strlen(tline)); + sscanf(&tline[Clength+8],"%s",tmp); + BgColor=GetColor(tmp); + free(tmp); + } else if ((strlen(&tline[0])>1) + &&(strncasecmp(tline,CatString3("*",MyName,"TextureColor"),Clength+13)==0)) { + char *c1, *c2; + XColor color; + XWindowAttributes attributes; + + XGetWindowAttributes(dpy,Root,&attributes); + len = strlen(&tline[Clength+13]); + c1 = safemalloc(len); + c2 = safemalloc(len); + if (sscanf(&tline[Clength+13],"%s %s",c1,c2)!=2) { + fprintf(stderr,"%s:You must specify two colors for the texture\n",MyName); + FromColor[0]=0; + FromColor[1]=0; + FromColor[2]=0; + ToColor[0]=0; + ToColor[1]=0; + ToColor[2]=0; + } + if (!XParseColor (dpy, attributes.colormap, c1, &color)) + { + nocolor("parse",c1); + TextureType=TEXTURE_BUILTIN; + } else { + FromColor[0]=color.red; + FromColor[1]=color.green; + FromColor[2]=color.blue; + } + if (!XParseColor (dpy, attributes.colormap, c2, &color)) + { + nocolor("parse",c2); + TextureType=TEXTURE_BUILTIN; + } else { + ToColor[0]=color.red; + ToColor[1]=color.green; + ToColor[2]=color.blue; + } + free(c1); + free(c2); + } else if ((strlen(&tline[0])>1) + &&(strncasecmp(tline,CatString3("*",MyName,"Pixmap"),Clength+7)==0)) { + CopyString(&BgPixmapFile,&tline[Clength+7]); + } else if((strlen(&tline[0])>1)&& + (strncasecmp(tline,CatString3("*",MyName,"AnimateMain"),Clength+12)==0)) + { + AnimateMain = 1; + } + else if((strlen(&tline[0])>1)&& + (strncasecmp(tline,CatString3("*",MyName,"Animate"),Clength+8)==0)) + { + if ((tline[Clength+9]!='M') && (tline[Clength+9]!='m')) + AnimationStyle = 1; + } +#ifdef ENABLE_SOUND + else if((strlen(&tline[0])>1)&& + (strncasecmp(tline,CatString3("*",MyName,"Player"),Clength+7)==0)) + { + CopyString(&SoundPlayer, &tline[Clength+7]); + } else if((strlen(&tline[0])>1)&& + (strncasecmp(tline,CatString3("*",MyName,"Sound"),Clength+6)==0)) + { + bind_sound(&tline[Clength+6]); + SoundActive = 1; + } +#endif + else if((strlen(&tline[0])>1) + &&(strncasecmp(tline,CatString3("*", MyName, ""),Clength+1)==0) + && (num_buttons < MAX_BUTTONS)) + { + /* check if this is a invalid option */ + if (!isspace(tline[Clength+1])) + fprintf(stderr,"%s:invalid option %s\n",MyName,tline); + else + match_string(&tline[Clength+1]); + } + else if((strlen(&tline[0])>1)&&(strncasecmp(tline,"IconPath",8)==0)) + { + CopyString(&iconPath,&tline[8]); + } + else if((strlen(&tline[0])>1)&&(strncasecmp(tline,"PixmapPath",10)==0)) + { + CopyString(&pixmapPath,&tline[10]); + } +#ifdef ENABLE_SOUND + else if((strlen(&tline[0])>1)&&(strncasecmp(tline,"*AudioDir",9)==0)) + { + CopyString(&SoundPath,&tline[9]); + } + else if((strlen(&tline[0])>1)&&(strncasecmp(tline,"ModulePath",11)==0)) + { + CopyString(&ModulePath,&tline[11]); + } +#endif + GetConfigLine(fd, &tline); + orig_tline = tline; + } +#ifdef ENABLE_DND + /* ignore last button if there's nothing bound to it */ + if ((Buttons[num_buttons-1].drop_action!=NULL) && + (Buttons[num_buttons-1].iconno==0)) { + num_buttons--; + } +#endif + return; +} + +/* + * Gets a word of a given index in the line, stripping any blanks + * The returned word is newly allocated + */ +#ifdef ENABLE_SOUND +char *get_token(char *tline, int index) +{ + char *start, *end; + int i,c,size; + char *word; + + index++; /* index is 0 based */ + size = strlen(tline); + i=c=0; + start=end=tline; + while (i<index && c<size) { + start=end; + while(isspace(*start) && c<size) { + start++; + c++; + } + end=start; + while(!isspace(*end) && c<size) { + end++; + c++; + } + if (end==start) return NULL; + i++; + } + if (i<index) return NULL; + word=safemalloc(end-start+1); + strncpy(word, start, end-start); + word[end-start]=0; + return word; +} + +/************************************************************************** + * + * Parses a sound binding + * + **************************************************************************/ +void bind_sound(char *tline) +{ + char *event, *sound; + + event = get_token(tline,0); + if (event==NULL) { + fprintf(stderr,"%s:bad sound binding %s\n",MyName,tline); + return; + } + sound = get_token(tline,1); + if (sound==NULL) { + free(event); + fprintf(stderr,"%s:bad sound binding %s\n",MyName,tline); + return; + } + if (strcmp(event,"open_folder")==0) { + Sounds[WHEV_OPEN_FOLDER]=sound; + } else if (strcmp(event,"close_folder")==0) { + Sounds[WHEV_CLOSE_FOLDER]=sound; + } else if (strcmp(event,"open_main")==0) { + Sounds[WHEV_OPEN_MAIN]=sound; + } else if (strcmp(event,"close_main")==0) { + Sounds[WHEV_CLOSE_MAIN]=sound; + } else if (strcmp(event,"push")==0) { + Sounds[WHEV_PUSH]=sound; + } else if (strcmp(event,"drop")==0) { + Sounds[WHEV_DROP]=sound; + } else { + fprintf(stderr,"%s:bad event %s in sound binding\n",MyName,event); + free(sound); + } + free(event); + return; +} +#endif /* ENABLE_SOUND */ + +/************************************************************************** + * + * Parses a button command line from the config file + * + *************************************************************************/ +void match_string(char *tline) +{ + int len,i,i2,n,j,k; + char *ptr,*start,*end,*tmp; + struct button_info *actual; + + /* skip spaces */ + while(isspace(*tline)&&(*tline != '\n')&&(*tline != 0)) + tline++; + + /* read next word. Its the button label. Users can specify "" + * NoIcon, or whatever to skip the label */ + /* read to next space */ + start = tline; + end = tline; + while((!isspace(*end))&&(*end!='\n')&&(*end!=0)) + end++; + len = end - start; + ptr = safemalloc(len+1); + strncpy(ptr,start,len); + ptr[len] = 0; + + if (strncmp(ptr,"~Folder",7)==0) + { + TOTHEFOLDER = -1; + Folders[num_folders].firstbutton = num_folderbuttons; + num_folders++; + free(ptr); + return; + } + + if(TOTHEFOLDER==-1) + { + actual = &Buttons[num_buttons++]; + actual->parent = &main_win; + } + else + { + actual = &Buttons[--num_folderbuttons]; + actual->folder = num_folders; + actual->parent = &Folders[num_folders].win; + }; + + actual->title = ptr; + + /* read next word. Its the icon bitmap/pixmap label. Users can specify "" + * NoIcon, or whatever to skip the label */ + /* read to next space */ + start = end; + /* skip spaces */ + while(isspace(*start)&&(*start != '\n')&&(*start != 0)) + start++; + end = start; + while((!isspace(*end))&&(*end!='\n')&&(*end!=0)) + end++; + len = end - start; + ptr = safemalloc(len+1); + strncpy(ptr,start,len); + ptr[len] = 0; + /* separate icon files to be overlaid */ + i2 = len; + j=k=0; + for(i=0;i<MAX_OVERLAY;i++) { + while (ptr[j]!=',' && j<i2) j++; + actual->icons[i].file=safemalloc(j-k+1); + strncpy(actual->icons[i].file,&(ptr[k]),j-k); + actual->icons[i].file[j-k]=0; + actual->iconno++; + j++; + k=j; + if (j>=i2) break; + } + tline = end; + for (i=num_buttons - 2;i>=0;i--) + { + if (strcmp(Buttons[i].title, actual->title) == 0) + { + actual = &Buttons[i]; + num_buttons--; + for(i=0;i<actual->iconno;i++) { + free(actual->icons[i].file); + } + break; + } + } + /* skip spaces */ + while(isspace(*tline)&&(*tline != '\n')&&(*tline != 0)) + tline++; +#ifdef ENABLE_DND + if (strncasecmp(tline,"dropexec",8)==0) { + /* get command to execute for dropped stuff */ + + if(TOTHEFOLDER==-1) { + num_buttons--; /* make the next parsed thing the button for this */ + free(ptr); + for(i=0;i<actual->iconno;i++) { + free(actual->icons[i].file); + } + actual->iconno=0; + } else { + num_folderbuttons++; + free(ptr); + for(i=0;i<actual->iconno;i++) { + free(actual->icons[i].file); + } + actual->iconno=0; + fprintf(stderr,"Drop in Folders not supported. Ignoring option\n"); + return; + } + + tline=strstr(tline,"Exec"); + len = strlen(tline); + tmp = tline + len -1; + while(((isspace(*tmp))||(*tmp == '\n'))&&(tmp >=tline)) { + tmp--; + len--; + } + ptr = safemalloc(len+1); + actual->drop_action=ptr; + strncpy(ptr,tline,len); + ptr[len]=0; + } else +#endif + if(strncasecmp(tline,"swallow",7)==0 || strncasecmp(tline,"maxswallow",10)==0) + { + /* Look for swallow "identifier", in which + case Wharf spawns and gobbles up window */ + i=7; + while((tline[i] != 0)&& + (tline[i] != '"')) + i++; + i2=i+1; + while((tline[i2] != 0)&& + (tline[i2] != '"')) + i2++; + actual->maxsize = + strncasecmp(tline,"maxswallow",10) == 0 ? 1 : 0; + if(i2 - i >1) + { + actual->hangon = safemalloc(i2-i); + strncpy(actual->hangon,&tline[i+1],i2-i-1); + actual->hangon[i2-i-1] = 0; + actual->swallow = 1; + } + n = 7; + n = i2+1; + while((isspace(tline[n]))&&(tline[n]!=0)) + n++; + len = strlen(&tline[n]); + tmp = tline + n + len -1; + while(((isspace(*tmp))||(*tmp == '\n'))&&(tmp >=(tline + n))) + { + tmp--; + len--; + } + ptr = safemalloc(len+6); + if(strncasecmp(&tline[n],"Module",6)==0) + { + ptr[0] = 0; + actual->module = 1; + } + else + strcpy(ptr,"Exec "); + i2 = strlen(ptr); + strncat(ptr,&tline[n],len); + ptr[i2+len]=0; + SendText(fd,ptr,0); + free(ptr); + actual->action = NULL; + } + else + { + if(!TOTHEFOLDER) + { + Folders[num_folders].count++; + } + + len = strlen(tline); + tmp = tline + len -1; + while(((isspace(*tmp))||(*tmp == '\n'))&&(tmp >=tline)) + { + tmp--; + len--; + } + ptr = safemalloc(len+1); + strncpy(ptr,tline,len); + ptr[len]=0; + + if (strncmp(ptr,"Folder",6)==0) + { + TOTHEFOLDER = 0; + Folders[num_folders].count = 0; + actual->folder = num_folders; + Folders[num_folders].mapped = NOTMAPPED; + } + actual->action = ptr; + } + return; +} + +/************************************************************************** + * Change the window name displayed in the title bar. + **************************************************************************/ +void change_window_name(char *str) +{ + XTextProperty name; + int i; + + if (XStringListToTextProperty(&str,1,&name) == 0) + { + fprintf(stderr,"%s: cannot allocate window name",MyName); + return; + } + XSetWMName(dpy,main_win,&name); + XSetWMIconName(dpy,main_win,&name); + for(i=0;i<num_folders;i++) + { + XSetWMName(dpy, Folders[i].win,&name); + XSetWMIconName(dpy, Folders[i].win,&name); + } + XFree(name.value); +} + + + +/*************************************************************************** + * + * Waits for next X event, or for an auto-raise timeout. + * + ****************************************************************************/ +int My_XNextEvent(Display *dpy, XEvent *event) +{ + fd_set in_fdset; + unsigned long header[HEADER_SIZE]; + int count; + static int miss_counter = 0; + unsigned long *body; + + if(XPending(dpy)) + { + XNextEvent(dpy,event); + return 1; + } + + FD_ZERO(&in_fdset); + FD_SET(x_fd,&in_fdset); + FD_SET(fd[1],&in_fdset); + + select(fd_width, SELECT_TYPE_ARG234 &in_fdset, 0, 0, NULL); + if(FD_ISSET(x_fd, &in_fdset)) + { + if(XPending(dpy)) + { + XNextEvent(dpy,event); + miss_counter = 0; + return 1; + } + else + miss_counter++; + if(miss_counter > 100) + DeadPipe(0); + } + + if(FD_ISSET(fd[1], &in_fdset)) + { + if((count = ReadFvwmPacket(fd[1], header, &body)) > 0) + { + process_message(header[1],body); + free(body); + } + } + return 0; +} + +void CheckForHangon(unsigned long *body) +{ + int button,i,j; + char *cbody; + + cbody = (char *)&body[3]; + for(i=0;i<num_rows;i++) + for(j=0;j<num_columns; j++) + { + button = i*num_columns + j; + if(Buttons[button].hangon != NULL) + { + if(strcmp(cbody,Buttons[button].hangon)==0) + { + if(Buttons[button].swallow == 1) + { + Buttons[button].swallow = 2; + if(Buttons[button].IconWin != None) + { + XDestroyWindow(dpy,Buttons[button].IconWin); + } + Buttons[button].IconWin = (Window)body[0]; + free(Buttons[button].hangon); + Buttons[button].hangon = NULL; + } + else + { + if (Buttons[button].swallow == 4) + Buttons[button].swallow = 3; + Buttons[button].up = 1; + free(Buttons[button].hangon); + Buttons[button].hangon = NULL; + RedrawWindow(&main_win,0, button, num_rows, num_columns); + } + } + } + } +} + +/************************************************************************** + * + * Process window list messages + * + *************************************************************************/ +void process_message(unsigned long type,unsigned long *body) +{ + switch(type) + { +/* case M_TOGGLE_PAGING: + pageing_enabled = body[0]; + RedrawWindow(&main_win,0, -1, num_rows, num_columns); + break; + pdg */ + case M_NEW_DESK: + new_desk = body[0]; + RedrawWindow(&main_win,0, -1, num_rows, num_columns); + break; + case M_END_WINDOWLIST: + RedrawWindow(&main_win,0, -1, num_rows, num_columns); + case M_MAP: + swallow(body); + case M_RES_NAME: + case M_RES_CLASS: + case M_WINDOW_NAME: + CheckForHangon(body); + break; + default: + break; + } +} + + + + + +/*************************************************************************** + * + * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all + * client messages will have the following form: + * + * event type ClientMessage + * message type _XA_WM_PROTOCOLS + * window tmp->w + * format 32 + * data[0] message atom + * data[1] time stamp + * + ****************************************************************************/ +void my_send_clientmessage (Window w, Atom a, Time timestamp) +{ + XClientMessageEvent ev; + + ev.type = ClientMessage; + ev.window = w; + ev.message_type = _XA_WM_PROTOCOLS; + ev.format = 32; + ev.data.l[0] = a; + ev.data.l[1] = timestamp; + XSendEvent (dpy, w, False, 0L, (XEvent *) &ev); +} + + +void swallow(unsigned long *body) +{ + char *temp; + int button,i,j; + long supplied; + + for(i=0;i<num_rows;i++) + for(j=0;j<num_columns; j++) + { + button = i*num_columns + j; + if((Buttons[button].IconWin == (Window)body[0])&& + (Buttons[button].swallow == 2)) + { + Buttons[button].swallow = 3; + /* "Swallow" the window! */ + + XReparentWindow(dpy,Buttons[button].IconWin, main_win, + j*BUTTONWIDTH+4, i*BUTTONHEIGHT+4); + XMapWindow(dpy,Buttons[button].IconWin); + XSelectInput(dpy,(Window)body[0], + PropertyChangeMask); + if (Buttons[button].action) + { + /* + XGrabButton(dpy, Button1Mask | Button2Mask, None, + (Window)body[0], + False, ButtonPressMask | ButtonReleaseMask, + GrabModeAsync, GrabModeAsync, None, None); + XGrabButton(dpy, Button1Mask | Button2Mask, LockMask, + */ + unsigned *mods = lock_mods; + do XGrabButton(dpy, Button1Mask | Button2Mask, *mods, + + (Window)body[0], + False, ButtonPressMask | ButtonReleaseMask, + GrabModeAsync, GrabModeAsync, None, None); + while (*mods++); + + } + if (Buttons[button].maxsize) { + Buttons[button].icons[0].w = 55; + Buttons[button].icons[0].h = 57; + } + else { + Buttons[button].icons[0].w = ICON_WIN_WIDTH; + Buttons[button].icons[0].h = ICON_WIN_HEIGHT; + } + if (!XGetWMNormalHints (dpy, Buttons[button].IconWin, + &Buttons[button].hints, + &supplied)) + Buttons[button].hints.flags = 0; + + XResizeWindow(dpy,(Window)body[0], Buttons[button].icons[0].w, + Buttons[button].icons[0].h); + XMoveWindow(dpy,Buttons[button].IconWin, + j*BUTTONWIDTH + + (BUTTONWIDTH - Buttons[button].icons[0].w)/2, + i*BUTTONHEIGHT + + (BUTTONHEIGHT - Buttons[button].icons[0].h)/2); + + XFetchName(dpy, Buttons[button].IconWin, &temp); + XClearArea(dpy, main_win,j*BUTTONWIDTH, i*BUTTONHEIGHT, + BUTTONWIDTH,BUTTONHEIGHT,0); + if(strcmp(Buttons[button].title,"-")!=0) + CopyString(&Buttons[button].title, temp); + RedrawWindow(&main_win,0, -1, num_rows, num_columns); + XFree(temp); + } + } +} + + + +void FindLockMods(void) +{ + int m, i, knl; + char* kn; + KeySym ks; + KeyCode kc, *kp; + unsigned lockmask, *mp; + XModifierKeymap* mm = XGetModifierMapping(dpy); + lockmask = LockMask; + if (mm) + { + kp = mm->modifiermap; + for (m = 0; m < 8; m++) + { + for (i = 0; i < mm->max_keypermod; i++) + { + if ((kc = *kp++) && + ((ks = XKeycodeToKeysym(dpy, kc, 0)) != NoSymbol)) + { + kn = XKeysymToString(ks); + knl = strlen(kn); + if ((knl > 6) && (strcasecmp(kn + knl - 4, "lock") == 0)) + lockmask |= (1 << m); + } + } + } + XFreeModifiermap(mm); + } + lockmask &= ~(ShiftMask | ControlMask); + + mp = lock_mods; + for (m = 0, i = 1; i < 256; i++) + { + if ((i & lockmask) > m) + m = *mp++ = (i & lockmask); + } + *mp = 0; +} + + +/*********************************************************************** + * + * Procedure: + * ConstrainSize - adjust the given width and height to account for the + * constraints imposed by size hints + * + * The general algorithm, especially the aspect ratio stuff, is + * borrowed from uwm's CheckConsistency routine. + * + ***********************************************************************/ +void ConstrainSize (XSizeHints *hints, int *widthp, int *heightp) +{ +#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) ) +#define _min(a,b) (((a) < (b)) ? (a) : (b)) + + + int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta; + int baseWidth, baseHeight; + int dwidth = *widthp, dheight = *heightp; + + if(hints->flags & PMinSize) + { + minWidth = hints->min_width; + minHeight = hints->min_height; + if(hints->flags & PBaseSize) + { + baseWidth = hints->base_width; + baseHeight = hints->base_height; + } + else + { + baseWidth = hints->min_width; + baseHeight = hints->min_height; + } + } + else if(hints->flags & PBaseSize) + { + minWidth = hints->base_width; + minHeight = hints->base_height; + baseWidth = hints->base_width; + baseHeight = hints->base_height; + } + else + { + minWidth = 1; + minHeight = 1; + baseWidth = 1; + baseHeight = 1; + } + + if(hints->flags & PMaxSize) + { + maxWidth = hints->max_width; + maxHeight = hints->max_height; + } + else + { + maxWidth = 10000; + maxHeight = 10000; + } + if(hints->flags & PResizeInc) + { + xinc = hints->width_inc; + yinc = hints->height_inc; + } + else + { + xinc = 1; + yinc = 1; + } + + /* + * First, clamp to min and max values + */ + if (dwidth < minWidth) dwidth = minWidth; + if (dheight < minHeight) dheight = minHeight; + + if (dwidth > maxWidth) dwidth = maxWidth; + if (dheight > maxHeight) dheight = maxHeight; + + + /* + * Second, fit to base + N * inc + */ + dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth; + dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight; + + + /* + * Third, adjust for aspect ratio + */ +#define maxAspectX hints->max_aspect.x +#define maxAspectY hints->max_aspect.y +#define minAspectX hints->min_aspect.x +#define minAspectY hints->min_aspect.y + /* + * The math looks like this: + * + * minAspectX dwidth maxAspectX + * ---------- <= ------- <= ---------- + * minAspectY dheight maxAspectY + * + * If that is multiplied out, then the width and height are + * invalid in the following situations: + * + * minAspectX * dheight > minAspectY * dwidth + * maxAspectX * dheight < maxAspectY * dwidth + * + */ + + if (hints->flags & PAspect) + { + if (minAspectX * dheight > minAspectY * dwidth) + { + delta = makemult(minAspectX * dheight / minAspectY - dwidth, + xinc); + if (dwidth + delta <= maxWidth) + dwidth += delta; + else + { + delta = makemult(dheight - dwidth*minAspectY/minAspectX, + yinc); + if (dheight - delta >= minHeight) dheight -= delta; + } + } + + if (maxAspectX * dheight < maxAspectY * dwidth) + { + delta = makemult(dwidth * maxAspectY / maxAspectX - dheight, + yinc); + if (dheight + delta <= maxHeight) + dheight += delta; + else + { + delta = makemult(dwidth - maxAspectX*dheight/maxAspectY, + xinc); + if (dwidth - delta >= minWidth) dwidth -= delta; + } + } + } + + *widthp = dwidth; + *heightp = dheight; + return; +} + + +#ifdef ENABLE_SOUND +void PlaySound(int event) +{ + int timestamp; + + if (!SoundActive) + return; + if (Sounds[event]==NULL) return; + write(PlayerChannel[1],&event,sizeof(event)); + timestamp = clock(); + write(PlayerChannel[1],×tamp,sizeof(timestamp)); + /* + kill(SoundThread,SIGUSR1); + */ +} +#endif diff --git a/app/fvwm/extras/FvwmWharf/OffiX/DragAndDrop.h b/app/fvwm/extras/FvwmWharf/OffiX/DragAndDrop.h new file mode 100644 index 000000000..433309777 --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/OffiX/DragAndDrop.h @@ -0,0 +1,48 @@ +/* +Copyright (C) 1996 César Crusius + +This file is part of the DND Library. This library is free +software; you can redistribute it and/or modify it under the terms of +the GNU Library General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your +option) any later version. This library is distributed in the hope +that it will be useful, but WITHOUT ANY WARRANTY; without even the +implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU Library General Public License for more details. +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __DragAndDropH__ +#define __DragAndDropH__ + +#include <OffiX/DragAndDropTypes.h> + +#include <X11/Intrinsic.h> + +void DndInitialize(Widget shell); + +void DndRegisterRootDrop(XtEventHandler handler); +void DndRegisterIconDrop(XtEventHandler handler); +void DndRegisterOtherDrop(XtEventHandler handler); + +void DndRegisterDropWidget(Widget widget,XtEventHandler handler, + XtPointer data); +void DndRegisterDragWidget(Widget widget,XtEventHandler handler, + XtPointer data); + +int DndHandleDragging(Widget widget,XEvent* event); + +void DndMultipleShells(void); +void DndAddShell(Widget widget); + +void DndSetData(int Type,unsigned char *Data,unsigned long Size); +void DndGetData(unsigned char **Data,unsigned long *Size); + +int DndIsIcon(Widget widget); +int DndDataType(XEvent *event); +unsigned int DndDragButtons(XEvent *event); +Widget DndSourceWidget(XEvent *event); + +#endif diff --git a/app/fvwm/extras/FvwmWharf/OffiX/DragAndDropTypes.h b/app/fvwm/extras/FvwmWharf/OffiX/DragAndDropTypes.h new file mode 100644 index 000000000..771452a80 --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/OffiX/DragAndDropTypes.h @@ -0,0 +1,32 @@ +/* +Copyright (C) 1996 César Crusius + +This file is part of the DND Library. This library is free +software; you can redistribute it and/or modify it under the terms of +the GNU Library General Public License as published by the Free +Software Foundation; either version 2 of the License, or (at your +option) any later version. This library is distributed in the hope +that it will be useful, but WITHOUT ANY WARRANTY; without even the +implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +PURPOSE. See the GNU Library General Public License for more details. +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __DragAndDropTypesH__ +#define __DragAndDropTypesH__ + +#define DndNotDnd -1 +#define DndUnknown 0 +#define DndRawData 1 +#define DndFile 2 +#define DndFiles 3 +#define DndText 4 +#define DndDir 5 +#define DndLink 6 +#define DndExe 7 + +#define DndEND 8 + +#endif diff --git a/app/fvwm/extras/FvwmWharf/README b/app/fvwm/extras/FvwmWharf/README new file mode 100644 index 000000000..db2039d15 --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/README @@ -0,0 +1,22 @@ +This is a port of the AfterStep +wharf module to an fvwm2 module. + +You should install this directory +in the modules subdirectory of the +fvwm source directory. + +I have only build this on a SUN +running solaris 2. + +I don't think it will build if you enable the +audio extensions. It should build but I have +no idea if it works if you enable the +drag and drop extenstions. I am not sure +if all the textures work. Swallow does seem +to work. + +I am happy to attempt to maintain this. +If you find/fix any bugs or fox the +man page, + +pdg@uow.edu.au diff --git a/app/fvwm/extras/FvwmWharf/Wharf.h b/app/fvwm/extras/FvwmWharf/Wharf.h new file mode 100644 index 000000000..5486955e5 --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/Wharf.h @@ -0,0 +1,121 @@ +#include "config.h" +#include "fvwmlib.h" + +/************************************************************************* + * + * Subroutine Prototypes + * + *************************************************************************/ +extern void CreateWindow(void); +extern Pixel GetColor(char *name); +extern void nocolor(char *a, char *b); +extern void RedrawWindow(Window *win, int firstbutton, int newbutton, int num_rows, int num_columns); +extern void match_string(char *tline); +#ifdef ENABLE_SOUND +extern void bind_sound(char *tline); +extern void PlaySound(int event); +#endif +extern void Loop(void); +extern void ParseOptions(char *); +extern char *safemalloc(int length); +extern void change_window_name(char *str); +extern int My_XNextEvent(Display *dpy, XEvent *event); +extern void DeadPipe(int nonsense); +extern void LoadIconFile(int button,int ico); +extern void CreateIconWindow(int button, Window *win); +extern void ConfigureIconWindow(int button,int row, int column); +extern void GetBitmapFile(int button,int ico); +extern int GetXPMFile(int button,int ico); +extern int GetXPMData(int button, char **data); +extern int GetXPMGradient(int button, int from[3], int to[3], int maxcols, + int type); +extern int GetSolidXPM(int button, Pixel pixel); +extern Bool Pushed; +extern Bool ForceSize; +extern void DrawOutline(Drawable d, int w, int h); +void process_message(unsigned long type,unsigned long *body); +void my_send_clientmessage (Window w, Atom a, Time timestamp); +void swallow(unsigned long *body); +void ConstrainSize (XSizeHints *hints, int *widthp, int *height); +void MapFolder(int folder, int *LastMapped, int base_x, int base_y, int row, int col); +void CloseFolder(int folder); +void OpenFolder(int folder,int x, int y, int w, int h, int direction); +void RedrawPushed(Window *win, int i, int j); +void RedrawUnpushed(Window *win, int i, int j); +void RedrawUnpushedOutline(Window *win, int i,int j); +void RedrawPushedOutline(Window *win, int i, int j); +void CreateShadowGC(void); +extern Display *dpy; /* which display are we talking to */ +extern Window Root; +extern Window main_win; +extern int screen; +extern long d_depth; +extern Pixel back_pix, fore_pix; +extern GC NormalGC, HiReliefGC, HiInnerGC; +extern GC MaskGC; +extern int BUTTONWIDTH, BUTTONHEIGHT; +extern XFontStruct *font; +#define MAX_BUTTONS 100 +#define BACK_BUTTON 100 + +#define MAX_OVERLAY 3 + +#define BUTTON_ARRAY_LN 102 +#define FOLDER_ARRAY_LN 10 + +#define ICON_WIN_WIDTH 48 +#define ICON_WIN_HEIGHT 48 + +#define ISMAPPED 0 +#define NOTMAPPED 1 + +typedef struct icon_info { + char *file; + short w, h; + Pixmap icon, mask; + signed char depth; +} icon_info; + +struct button_info +{ + char *action; + char *title; + int iconno; + icon_info icons[MAX_OVERLAY]; + + Pixmap completeIcon; /* icon with background */ + Window IconWin; + Window *parent; + XSizeHints hints; + char *hangon; + char up; + char swallow; + char maxsize; + char module; + int folder; +#ifdef ENABLE_DND + char *drop_action; +#endif +}; + +struct folder_info +{ + Window win; /* Window of the Folder */ + int firstbutton; /* index to Buttons, starting at end */ + int count; /* count folded buttons */ + int mapped; /* is the window visible or not ?? */ + int cols; /* either 1 or me.count */ + int rows; /* either me.count or 1 */ + int direction; /* direction of the folder */ +}; + +extern struct button_info Buttons[MAX_BUTTONS+2]; +extern struct folder_info Folders[FOLDER_ARRAY_LN]; + +extern char *iconPath; +extern char *pixmapPath; + + + + + diff --git a/app/fvwm/extras/FvwmWharf/icons.c b/app/fvwm/extras/FvwmWharf/icons.c new file mode 100644 index 000000000..5e3219b95 --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/icons.c @@ -0,0 +1,367 @@ +/* icons.c. by Bo Yang. + * Modifications: Copyright 1995 by Bo Yang. + * + * based on icons.c by Robert Nation + * The icons module, and the entire GoodStuff program, and the concept for + * interfacing this module to the Window Manager, are all original work + * by Robert Nation + * + * Copyright 1993, Robert Nation. + * No guarantees or warantees or anything + * are provided or implied in any way whatsoever. Use this program at your + * own risk. Permission to use this program for any purpose is given, + * as long as the copyright is kept intact. */ +/*********************************************************************** + * + * Derived from fvwm icon code + * + ***********************************************************************/ + +#include "config.h" + +#include <stdio.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <stdlib.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xproto.h> +#include <X11/Xatom.h> +#include <X11/Intrinsic.h> + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#include "Wharf.h" + +#ifdef XPM +#include <X11/xpm.h> +#endif /* XPM */ +#include "stepgfx.h" + + +/**************************************************************************** + * + * Loads an icon file into a pixmap + * + ****************************************************************************/ +void LoadIconFile(int button, int ico) +{ +#ifndef NO_ICONS + /* First, check for a monochrome bitmap */ + if(Buttons[button].icons[ico].file != NULL) + GetBitmapFile(button,ico); + /* Next, check for a color pixmap */ + if((Buttons[button].icons[ico].file != NULL)&& + (Buttons[button].icons[ico].w == 0)&&(Buttons[button].icons[ico].h == 0)) + GetXPMFile(button,ico); +#endif +} + +/**************************************************************************** + * + * Creates an Icon Window + * + ****************************************************************************/ +void CreateIconWindow(int button, Window *win) +{ +#ifndef NO_ICONS + unsigned long valuemask; /* mask for create windows */ + XSetWindowAttributes attributes; /* attributes for create windows */ + + /* This used to make buttons without icons explode when pushed + if((Buttons[button].icon_w == 0)&&(Buttons[button].icon_h == 0)) + return; + */ + attributes.background_pixel = back_pix; + attributes.event_mask = ExposureMask; + valuemask = CWEventMask | CWBackPixel; + + Buttons[button].IconWin = + XCreateWindow(dpy, *win, 0, 0, BUTTONWIDTH, + BUTTONHEIGHT, 0, CopyFromParent, + CopyFromParent,CopyFromParent,valuemask,&attributes); + + return; +#endif +} + +/**************************************************************************** + * + * Combines icon shape masks after a resize + * + ****************************************************************************/ +void ConfigureIconWindow(int button,int row, int column) +{ +#ifndef NO_ICONS + int x,y, w, h; + int xoff,yoff; + int i; + + + if(Buttons[button].iconno == 0) + return; + if(Buttons[button].swallow != 0) { + return; + } + x = column*BUTTONWIDTH; + y = row*BUTTONHEIGHT; + + XMoveResizeWindow(dpy, Buttons[button].IconWin, x,y,BUTTONWIDTH, + BUTTONHEIGHT); + Buttons[button].completeIcon = + XCreatePixmap(dpy,Root, BUTTONWIDTH,BUTTONHEIGHT,d_depth); + XCopyArea(dpy, Buttons[BACK_BUTTON].icons[0].icon, + Buttons[button].completeIcon, NormalGC, 0,0, + BUTTONWIDTH,BUTTONHEIGHT, 0,0); + + for(i=0;i<Buttons[button].iconno;i++) { + w = Buttons[button].icons[i].w; + h = Buttons[button].icons[i].h; + if (w<1 || h<1) continue; + if(w > BUTTONWIDTH) w = BUTTONWIDTH; + if(h > BUTTONHEIGHT) h = BUTTONHEIGHT; + if (w < 1) w = 1; + if (h < 1) h = 1; +#ifdef XPM + xoff = (BUTTONWIDTH - w)/2; + yoff = (BUTTONHEIGHT - h)/2; + if (xoff<0) xoff=0; + if (yoff<0) yoff=0; + if (Buttons[button].icons[i].mask != None) { + XSetClipOrigin(dpy, MaskGC, xoff, yoff); + XSetClipMask(dpy, MaskGC, Buttons[button].icons[i].mask); + } else { + XRectangle rect[1]; + rect[0].x=0; rect[0].y=0; + rect[0].width=w; rect[0].height=h; + + XSetClipRectangles(dpy,MaskGC,xoff,yoff, rect, 1, YSorted); + } + XCopyArea(dpy, Buttons[button].icons[i].icon, + Buttons[button].completeIcon, MaskGC, 0,0, + w, h, xoff,yoff); + /* don't need them anymore */ + XFreePixmap(dpy, Buttons[button].icons[i].icon); + if (Buttons[button].icons[i].mask != None) { + XFreePixmap(dpy, Buttons[button].icons[i].mask); + } +#endif + if(Buttons[button].icons[i].depth == -1) { + XCopyPlane(dpy,Buttons[button].icons[i].icon, + Buttons[button].completeIcon,NormalGC, + 0,0,w,h, 0,0,1); + XFreePixmap(dpy, Buttons[button].icons[i].icon); + } + } + XSetWindowBackgroundPixmap(dpy, Buttons[button].IconWin, + Buttons[button].completeIcon); + XClearWindow(dpy,Buttons[button].IconWin); +#endif +} + +/*************************************************************************** + * + * Looks for a monochrome icon bitmap file + * + **************************************************************************/ +void GetBitmapFile(int button, int ico) +{ +#ifndef NO_ICONS + char *path = NULL; + int HotX,HotY; + + path = findIconFile(Buttons[button].icons[ico].file, iconPath,R_OK); + if(path == NULL)return; + + if(XReadBitmapFile (dpy, Root,path,(unsigned int *)&Buttons[button].icons[ico].w, + (unsigned int *)&Buttons[button].icons[ico].h, + &Buttons[button].icons[ico].icon, + (int *)&HotX, + (int *)&HotY) != BitmapSuccess) + { + Buttons[button].icons[ico].w = 0; + Buttons[button].icons[ico].h = 0; + } + else + { + Buttons[button].icons[ico].depth = -1; + } + Buttons[button].icons[ico].mask = None; + free(path); +#endif +} + + +/**************************************************************************** + * + * Looks for a color XPM icon file + * + ****************************************************************************/ +int GetXPMFile(int button,int ico) +{ +#ifndef NO_ICONS +#ifdef XPM + XWindowAttributes root_attr; + XpmAttributes xpm_attributes; + char *path = NULL; + + path = findIconFile(Buttons[button].icons[ico].file, pixmapPath,R_OK); + if(path == NULL) return 0; + XGetWindowAttributes(dpy,Root,&root_attr); + xpm_attributes.colormap = root_attr.colormap; + xpm_attributes.closeness = 40000; + xpm_attributes.valuemask = XpmSize | XpmReturnPixels|XpmColormap + |XpmCloseness; + if(XpmReadFileToPixmap(dpy, Root, path, + &Buttons[button].icons[ico].icon, + &Buttons[button].icons[ico].mask, + &xpm_attributes) == XpmSuccess) + { + Buttons[button].icons[ico].w = xpm_attributes.width; + Buttons[button].icons[ico].h = xpm_attributes.height; + Buttons[button].icons[ico].depth = d_depth; + free(path); + } else { + free(path); + Buttons[button].icons[ico].icon=None; + return 0; + } + if (button==BACK_BUTTON) { + BUTTONWIDTH = xpm_attributes.width; + BUTTONHEIGHT = xpm_attributes.height; + if (ForceSize && (BUTTONWIDTH > 64 || BUTTONHEIGHT > 64)) { + Pixmap resized; + + BUTTONWIDTH = 64; + BUTTONHEIGHT = 64; + resized = XCreatePixmap(dpy, Root, 64, 64, d_depth); + XCopyArea(dpy, Buttons[button].icons[ico].icon, + resized, NormalGC, 0, 0, 64, 64, 0, 0); + XFreePixmap(dpy, Buttons[button].icons[ico].icon); + Buttons[button].icons[ico].icon = resized; + } + DrawOutline(Buttons[button].icons[ico].icon,BUTTONWIDTH,BUTTONHEIGHT); + } + return 1; +#endif /* XPM */ +#endif +} + +/**************************************************************************** + * + * read background icons from data + * + ****************************************************************************/ +int GetXPMData(int button, char **data) +{ +#ifndef NO_ICONS +#ifdef XPM + XWindowAttributes root_attr; + XpmAttributes xpm_attributes; + + if( button != BACK_BUTTON ) + return 0; + XGetWindowAttributes(dpy,Root,&root_attr); + xpm_attributes.colormap = root_attr.colormap; + xpm_attributes.valuemask = XpmSize | XpmReturnPixels|XpmColormap; + if(XpmCreatePixmapFromData(dpy, Root, data, + &Buttons[button].icons[0].icon, + &Buttons[button].icons[0].mask, + &xpm_attributes) == XpmSuccess) + { + BUTTONWIDTH = Buttons[button].icons[0].w = xpm_attributes.width; + BUTTONHEIGHT = Buttons[button].icons[0].h = xpm_attributes.height; + Buttons[button].icons[0].depth = d_depth; + } + else { + return 0; + } + DrawOutline(Buttons[button].icons[0].icon,BUTTONWIDTH,BUTTONHEIGHT); + + return 1; +#endif /* XPM */ +#endif +} + +/******************************************************************* + * + * Make a gradient pixmap + * + *******************************************************************/ + +int GetXPMGradient(int button, int from[3], int to[3], int maxcols, + int type) +{ + Buttons[button].icons[0].icon=XCreatePixmap(dpy,Root,64,64, d_depth); + Buttons[button].icons[0].mask=None; + Buttons[button].icons[0].w = 64; + Buttons[button].icons[0].h = 64; + if (button==BACK_BUTTON) { + BUTTONWIDTH = 64; + BUTTONHEIGHT = 64; + } + Buttons[button].icons[0].depth = d_depth; + switch (type) { + case TEXTURE_GRADIENT: + if (!DrawDegradeRelief(dpy, Buttons[button].icons[0].icon, 0,0,64,64, + from, to, 0, maxcols)) { + XFreePixmap(dpy, Buttons[button].icons[0].icon); + return 0; + } + break; + case TEXTURE_HGRADIENT: + case TEXTURE_HCGRADIENT: + if (!DrawHGradient(dpy, Buttons[button].icons[0].icon, 0, 0, 64,64, + from, to, 0, maxcols, type-TEXTURE_HGRADIENT)) { + XFreePixmap(dpy, Buttons[button].icons[0].icon); + return 0; + } + break; + case TEXTURE_VGRADIENT: + case TEXTURE_VCGRADIENT: + if (!DrawVGradient(dpy, Buttons[button].icons[0].icon, 0, 0, 64,64, + from, to, 0, maxcols, type-TEXTURE_VGRADIENT)) { + XFreePixmap(dpy, Buttons[button].icons[0].icon); + return 0; + } + break; + default: + return 0; + } + DrawOutline(Buttons[button].icons[0].icon,64,64); + + return 1; +} + +/******************************************************************* + * + * Make a solid color pixmap + * + *******************************************************************/ + +int GetSolidXPM(int button, Pixel pixel) +{ + GC gc; + XGCValues gcv; + + gcv.foreground=pixel; + gc=XCreateGC(dpy,Root,GCForeground, &gcv); + if (button==BACK_BUTTON) { + BUTTONWIDTH = 64; + BUTTONHEIGHT = 64; + } + Buttons[button].icons[0].icon=XCreatePixmap(dpy,Root,64,64, d_depth); + Buttons[button].icons[0].mask=None; + XFillRectangle(dpy,Buttons[button].icons[0].icon,gc,0,0,64,64); + Buttons[button].icons[0].w = 64; + Buttons[button].icons[0].h = 64; + Buttons[button].icons[0].depth = d_depth; + XFreeGC(dpy,gc); + DrawOutline(Buttons[button].icons[0].icon,64,64); + + return 1; +} diff --git a/app/fvwm/extras/FvwmWharf/sample.style b/app/fvwm/extras/FvwmWharf/sample.style new file mode 100644 index 000000000..08b0e6ac9 --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/sample.style @@ -0,0 +1,41 @@ + + +# Animate Wharf's folders + +*FvwmWharfAnimate +*FvwmWharfAnimateMain +*FvwmWharfGeometry +0+0 +*FvwmWharfColumns 1 +*FvwmWharfTextureType 2 +*FvwmWharfMaxColors 10 +*FvwmWharfBgColor black +*FvwmWharfTextureColor darkgrey white + + + +# Create a pullout "Folder" as the first button on Wharf + + +*FvwmWharf AfterStep fvwm3.xpm Folder +*FvwmWharf Shutdown shutdown-label.xpm Quit +*FvwmWharf xlock KeysOnChain-label.xpm Exec xlock +*FvwmWharf ~Folders +*FvwmWharf xterm terminal.xpm Exec xterm +*FvwmWharf Machines machines.xpm Folder +*FvwmWharf Wumpus wumpus.xpm Exec xterm -cn -T Wumpus -n Wumpus -e ssh wumpus +*FvwmWharf Wyrm wyrm.xpm Exec xterm -cn -T Wyrm -n Wyrm -e ssh wyrm +*FvwmWharf Gryphon gryphon.xpm Exec xterm -cn -T Gryphon -n Gryphon -e ssh gryphon +*FvwmWharf Wraith wraith.xpm Exec xterm -cn -T Wraith -n Wraith -e ssh wraith +*FvwmWharf Banshee banshee.xpm Exec xterm -cn -T Banshee -n Banshee -e ssh banshee +*FvwmWharf Library library.xpm Exec xterm -cn -T Library -n Library -e /usr/bin/rlogin -l library library +*FvwmWharf Rlogin rlogin.xpm Module Rlogin +*FvwmWharf ~Folders +*FvwmWharf Applications tools-label.xpm Folder +*FvwmWharf Netscape netscape-label.xpm Exec netscape +*FvwmWharf Answerbook answerbook.xpm Exec answerbook +*FvwmWharf ~Folders +*FvwmWharf MyStuff Wizard-label.xpm Folder +*FvwmWharf Workman cdrom.xpm Exec workman.sh -Wl workman -WL workman -Wp 880 680 -WP 1215 960 -Wi +*FvwmWharf Hotjava hotjava2.xpm Exec hotjava +*FvwmWharf Todo todo.xpm Exec xvdtl +*FvwmWharf ~Folders diff --git a/app/fvwm/extras/FvwmWharf/stepgfx.c b/app/fvwm/extras/FvwmWharf/stepgfx.c new file mode 100644 index 000000000..e15da8d87 --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/stepgfx.c @@ -0,0 +1,587 @@ +/* + * Generic graphics and misc. utilities + * + */ + +#include <X11/Xlib.h> +#include <stdlib.h> + +/* Masks to apply to color components when allocating colors + * you may want to set them to 0xffff if your display supports 16bpp+ + */ +#define RED_MASK 0xff00 +#define GREEN_MASK 0xff00 +#define BLUE_MASK 0xff00 +/* + *********************************************************************** + * Allocates colors and fill a pixel value array. Color values are + * truncated with RED_MASK, GREEN_MASK and BLUE_MASK + * + * from,to are the primary colors to use + * maxcols is the number of colors + * colors is the array of pixel values + * light,dark are the colors for the relief + * dr,dg,db are the increment values for the colors + * alloc_relief if colors for relief should be allocated + * incr - 0 if gradient is light to dark, 1 if dark to light + *********************************************************************** + */ +int MakeColors(Display *dpy, Drawable d, int from[3], int to[3], int maxcols, + unsigned long *colors, unsigned long *dark, + unsigned long *light, int dr, int dg, int db, + int alloc_relief, int incr) +{ + float rv, gv, bv; + float sr,sg,sb; + int red, green, blue; + XColor color; + int i; + + sr = (float)dr / (float)maxcols; + sg = (float)dg / (float)maxcols; + sb = (float)db / (float)maxcols; + rv = (float)from[0]; + gv = (float)from[1]; + bv = (float)from[2]; + /* kludge to frce color allocation in the first iteration on any case */ + color.red = (from[0] == 0) ? 0xffff : 0; + color.green = 0; + color.blue = 0; + for(i = 0; i < maxcols; i++) { + /* color allocation saver */ + red = ((short)rv) & RED_MASK; + green = ((short)gv) & GREEN_MASK; + blue = ((short)bv) & BLUE_MASK; + if (color.red != red || color.green != green || color.blue != blue) { + color.red = red; + color.green = green; + color.blue = blue; + if (XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), + &color)==0) { + return 0; + } + } + colors[i] = color.pixel; + rv += sr; + gv += sg; + bv += sb; + rv = ((rv > 65535.0) || (rv < 0.0)) ? rv -= sr : rv; + gv = ((gv > 65535.0) || (gv < 0.0)) ? gv -= sg : gv; + bv = ((bv > 65535.0) || (bv < 0.0)) ? bv -= sb : bv; + } + /* allocate 2 colors for the bevel */ + if (alloc_relief) { + if (incr) { + rv = (float)from[0] * 0.8; + gv = (float)from[1] * 0.8; + bv = (float)from[2] * 0.8; + } else { + rv = (float)to[0] * 0.8; + gv = (float)to[1] * 0.8; + bv = (float)to[2] * 0.8; + } + color.red = (unsigned short)(rv<0?0:rv); + color.green = (unsigned short)(gv<0?0:gv); + color.blue = (unsigned short)(bv<0?0:bv); + if (XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)),&color)) + *dark = color.pixel; + else + *dark = colors[incr ? 0 : maxcols-1]; + + if (incr) { + float avg; + avg = (float)(to[0]+to[1]+to[2])/3; + rv = avg + (float)(to[0]/2); + gv = avg + (float)(to[1]/2); + bv = avg + (float)(to[2]/2); + } else { + float avg; + avg = (float)(from[0]+from[1]+from[2])/3; + rv = avg + (float)(from[0]/2); + gv = avg + (float)(from[1]/2); + bv = avg + (float)(from[2]/2); + } + color.red = (unsigned short)(rv>65535.0 ? 65535.0:rv); + color.green = (unsigned short)(gv>65535.0 ? 65535.0:gv); + color.blue = (unsigned short)(bv>65535.0 ? 65535.0:bv); + if (XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), + &color)) + *light = color.pixel; + else + *light = colors[incr ? maxcols-1 : 0]; + } else { + *light = colors[incr ? maxcols-1 : 0]; + *dark = colors[incr ? 0 : maxcols-1]; + } + return 1; +} + + +/* + ************************************************************************ + * + * Draws a texture similar to Wharf's button background + * + * from: r,g,b values of top left color + * to: r,g,b values of bottom right color + * relief: relief to add to the borders. 0=flat, >0 raised, <0 sunken + * maxcols: # of max colors to use + * + * Aborts and returns 0 on error + ************************************************************************ + */ + +int DrawDegradeRelief(Display *dpy, Drawable d, int x, int y, int w, int h, + int from[3], int to[3], int relief, int maxcols) +{ + int i = 0,j,k; + int dr, dg, db; /* delta */ + int dmax, dmax2; + GC gc, gc2; + XGCValues gcv; + int px, py, pd; + unsigned long lightcolor, darkcolor; + int alloc_relief; + unsigned long *colors; + float c1,s1; + + if (w <= 0 || h <= 0) + return 0; + + gcv.foreground = 1; + gc = XCreateGC(dpy, d, GCForeground, &gcv); + gc2 = XCreateGC(dpy, d, GCForeground, &gcv); + + dr = to[0] - from[0]; + dg = to[1] - from[1]; + db = to[2] - from[2]; + + dmax = abs(dr); + dmax2 = dr; + if (dmax < abs(dg)) { + dmax = abs(dg); + dmax2 = dg; + } + if (dmax < abs(db)) { + dmax = abs(db); + dmax2 = db; + } + /* if colors from and to are the same, force to one color */ + if (dmax==0) dmax=1; + + if (relief!=0) { + if (maxcols>4) { + alloc_relief=1; + maxcols -= 2; /* reserve two colors for the relief */ + } else { + alloc_relief=0; + } + } else + alloc_relief = 0; + + if (dmax < maxcols) { + maxcols = dmax; /* we need less colors than we expected */ + } + + colors = malloc(sizeof(unsigned long)*maxcols); + /* alloc colors */ + if (!MakeColors(dpy, d, from, to, maxcols, colors, &darkcolor, &lightcolor, + dr, dg, db, alloc_relief, dmax2>0)) + return 0; + + /* display it */ + s1 = (float)(maxcols)/((float)w*2.0); + pd = relief==0 ? 0 : 1; + for(py = pd; py < h-pd; py++) { + c1 = ((float)maxcols/2.0)*((float)py/(float)((h-pd*2)-1)); + j = -1; + k=pd+x; + for(px = pd+x; px < w-pd+x; px++) { + i = (int)c1; + if (i>=maxcols) i=maxcols-1; + if (j != colors[i]) { + j = colors[i]; + XSetForeground(dpy, gc, j); + XDrawLine(dpy, d, gc, k, y+py, px, y+py); + k=px; + } + c1+=s1; + } + XSetForeground(dpy, gc, colors[i]); + XDrawLine(dpy, d, gc, k, y+py, w-pd+x, y+py); + } + /* draw borders */ + if (relief != 0) { + if (relief>0) { + XSetForeground(dpy, gc, lightcolor); + XSetForeground(dpy, gc2, darkcolor); + } else { + XSetForeground(dpy, gc, darkcolor); + XSetForeground(dpy, gc2, lightcolor); + } + XDrawLine(dpy, d, gc, x, y, x, y+h-1); + XDrawLine(dpy, d, gc, x, y, x+w-1, y); + XDrawLine(dpy, d, gc2, x, y+h-1, x+w-1, y+h-1); + XDrawLine(dpy, d, gc2, x+w-1, y, x+w-1, y+h-1); + } + XFreeGC(dpy,gc); + XFreeGC(dpy,gc2); + free(colors); + return 1; +} + + +/* + ************************************************************************ + * + * Draws a horizontal gradient + * + * from: r,g,b values of top color + * to: r,g,b values of bottom color + * relief: relief to add to the borders. 0=flat, >0 raised, <0 sunken + * maxcols: max colors to use + * type: gradient type. 0 for one-way, != 0 for cilindrical + * + * aborts and returns 0 on error. + ************************************************************************ + */ +int DrawHGradient(Display *dpy, Drawable d, int x, int y, int w, int h, + int from[3], int to[3], int relief, int maxcols, + int type) +{ + int i,j; + XGCValues gcv; + GC gc, gc2; + int dr,dg,db; + float s,c; + int dmax; + unsigned long *colors, lightcolor, darkcolor; + int py,pd; + int alloc_relief; + + if (w <= 1 || h <= 1) + return 0; + + gcv.foreground = 1; + gc = XCreateGC(dpy, d, GCForeground, &gcv); + gc2 = XCreateGC(dpy, d, GCForeground, &gcv); + + dr = to[0] - from[0]; + dg = to[1] - from[1]; + db = to[2] - from[2]; + + dmax = dr; + if (abs(dmax) < abs(dg)) { + dmax = dg; + } + if (abs(dmax) < abs(db)) { + dmax = db; + } + if (relief!=0) { + if (maxcols>4) { + alloc_relief=1; + maxcols -= 2; /* reserve two colors for the relief */ + } else { + alloc_relief=0; + } + } else + alloc_relief=0; + + if (type) { + if (h/2 < maxcols) { + maxcols = h/2; /* we need less colors than we expected */ + } + } else { + if (h < maxcols) { + maxcols = h; /* we need less colors than we expected */ + } + } + /* alloc colors */ + colors=malloc(maxcols*sizeof(unsigned long)); + if (!MakeColors(dpy, d, from, to, maxcols, colors, &darkcolor, &lightcolor, + dr, dg, db, alloc_relief, dmax>0)) + return 0; + /* display it */ + if (type) { + s = ((float)maxcols*2)/(float)h; + } else { + s = (float)maxcols/(float)h; + } + pd = relief==0 ? 0 : 1; + c=0; + j=-1; + if (type==0) { /* one-way */ + for(py = pd; py < h-pd; py++) { + i=(int)c; + if (i>=maxcols) i=maxcols-1; + if (j != i) { + XSetForeground(dpy, gc, colors[i]); + } + XDrawLine(dpy, d, gc, x+pd, y+py, x+w-1-pd, y+py); + j = i; + c += s; + } + } else { /* cylindrical */ + for(py = pd; py < h-pd; py++) { + i=(int)c; + if (i>=maxcols) i=maxcols-1; + if (j != i) { + XSetForeground(dpy, gc, colors[i]); + } + XDrawLine(dpy, d, gc, x+pd, y+py, x+w-1-pd, y+py); + j = i; + if (py == h/2) s = -s; + c += s; + } + } + /* draw borders */ + if (relief != 0) { + if (relief>0) { + XSetForeground(dpy, gc, lightcolor); + XSetForeground(dpy, gc2, darkcolor); + } else { + XSetForeground(dpy, gc, darkcolor); + XSetForeground(dpy, gc2, lightcolor); + } + XDrawLine(dpy, d, gc, x, y, x, y+h-1); + XDrawLine(dpy, d, gc, x, y, x+w-1, y); + XDrawLine(dpy, d, gc2, x, y+h-1, x+w-1, y+h-1); + XDrawLine(dpy, d, gc2, x+w-1, y, x+w-1, y+h-1); + } + XFreeGC(dpy,gc); + XFreeGC(dpy,gc2); + free(colors); + return 1; +} + + +/* + ************************************************************************ + * + * Draws a vertical gradient + * + * from: r,g,b values of left color + * to: r,g,b values of right color + * relief: relief to add to the borders. 0=flat, >0 raised, <0 sunken + * maxcols: max colors to use + * type: gradient type. 0 for one-way, != 0 for cilindrical + * + * aborts and returns 0 on error. + ************************************************************************ + */ +int DrawVGradient(Display *dpy, Drawable d, int x, int y, int w, int h, + int from[3], int to[3], int relief, int maxcols, + int type) +{ + int i,j; + XGCValues gcv; + GC gc, gc2; + int dr,dg,db; + float s,c; + int dmax; + unsigned long *colors, lightcolor, darkcolor; + int px,pd; + int alloc_relief; + + if (w <= 1 || h <= 1) + return 0; + + gcv.foreground = 1; + gc = XCreateGC(dpy, d, GCForeground, &gcv); + gc2 = XCreateGC(dpy, d, GCForeground, &gcv); + + dr = to[0] - from[0]; + dg = to[1] - from[1]; + db = to[2] - from[2]; + + dmax = dr; + if (abs(dmax) < abs(dg)) { + dmax = dg; + } + if (abs(dmax) < abs(db)) { + dmax = db; + } + if (relief!=0) { + if (maxcols>4) { + alloc_relief=1; + maxcols -= 2; /* reserve two colors for the relief */ + } else { + alloc_relief=0; + } + } else + alloc_relief=0; + + if (type) { + if (w/2 < maxcols) { + maxcols = w/2; /* we need less colors than we expected */ + } + } else { + if (w < maxcols) { + maxcols = w; /* we need less colors than we expected */ + } + } + /* alloc colors */ + colors=malloc(maxcols*sizeof(unsigned long)); + if (!MakeColors(dpy, d, from, to, maxcols, colors, &darkcolor, &lightcolor, + dr, dg, db, alloc_relief, dmax>0)) + return 0; + /* display it */ + if (type) { + s = ((float)maxcols*2)/(float)w; + } else { + s = (float)maxcols/(float)w; + } + pd = relief==0 ? 0 : 1; + c=0; + j=-1; + if (type==0) { /* one-way */ + for(px = pd; px < w-pd; px++) { + i=(int)c; + if (i>=maxcols) i=maxcols-1; + if (j != i) { + XSetForeground(dpy, gc, colors[i]); + } + XDrawLine(dpy, d, gc, x+px, y+pd, x+px, y+h-pd-1); + j = i; + c += s; + } + } else { /* cylindrical */ + for(px = pd; px < w-pd; px++) { + i=(int)c; + if (i>=maxcols) i=maxcols-1; + if (j != i) { + XSetForeground(dpy, gc, colors[i]); + } + XDrawLine(dpy, d, gc, x+px, y+pd, x+px, y+h-pd-1); + j = i; + if (px == w/2) s = -s; + c += s; + } + } + /* draw borders */ + if (relief != 0) { + if (relief>0) { + XSetForeground(dpy, gc, lightcolor); + XSetForeground(dpy, gc2, darkcolor); + } else { + XSetForeground(dpy, gc, darkcolor); + XSetForeground(dpy, gc2, lightcolor); + } + XDrawLine(dpy, d, gc, x, y, x, y+h-1); + XDrawLine(dpy, d, gc, x, y, x+w-1, y); + XDrawLine(dpy, d, gc2, x, y+h-1, x+w-1, y+h-1); + XDrawLine(dpy, d, gc2, x+w-1, y, x+w-1, y+h-1); + } + XFreeGC(dpy,gc); + XFreeGC(dpy,gc2); + free(colors); + return 1; +} + + +/************************************************************************ + * + * Draws text with a texture + * + * d - target drawable + * font - font to draw text + * x,y - position of text + * gradient - texture pixmap. size must be at least as large as text + * text - text to draw + * chars - chars in text + ************************************************************************/ +void DrawTexturedText(Display *dpy, Drawable d, XFontStruct *font, + int x, int y, Pixmap gradient, char *text, int chars) + +{ + Pixmap mask; + int w,h; + GC gc; + XGCValues gcv; + + /* make the mask pixmap */ + w = XTextWidth(font,text,chars); + h = font->ascent+font->descent; + mask=XCreatePixmap(dpy,DefaultRootWindow(dpy),w+1,h+1,1); + gcv.foreground = 0; + gcv.function = GXcopy; + gcv.font = font->fid; + gc = XCreateGC(dpy,mask,GCFunction|GCForeground|GCFont,&gcv); + XFillRectangle(dpy,mask,gc,0,0,w,h); + XSetForeground(dpy,gc,1); + XDrawString(dpy,mask,gc,0,font->ascent,text,chars); + XFreeGC(dpy,gc); + /* draw the texture */ + gcv.function=GXcopy; + gc = XCreateGC(dpy,d,GCFunction,&gcv); + XSetClipOrigin(dpy,gc,x,y); + XSetClipMask(dpy,gc,mask); + XCopyArea(dpy,gradient,d,gc,0,0,w,h,x,y); + XFreeGC(dpy,gc); + XFreePixmap(dpy,mask); +} + + + + +int MakeShadowColors(Display *dpy, int from[3], int to[3], + unsigned long *dark, unsigned long *light) +{ + float rv, gv, bv; + XColor color; + int incr; + int dr,dg,db,dmax; + + dr = to[0] - from[0]; + dg = to[1] - from[1]; + db = to[2] - from[2]; + + dmax = dr; + if (abs(dmax) < abs(dg)) { + dmax = dg; + } + if (abs(dmax) < abs(db)) { + dmax = db; + } + incr=(dmax>0); + /* allocate 2 colors for the bevel */ + if (incr) { + rv = (float)from[0] * 0.8; + gv = (float)from[1] * 0.8; + bv = (float)from[2] * 0.8; + } else { + rv = (float)to[0] * 0.8; + gv = (float)to[1] * 0.8; + bv = (float)to[2] * 0.8; + } + color.red = (short)(rv<0?0:rv); + color.green = (short)(gv<0?0:gv); + color.blue = (short)(bv<0?0:bv); + if (XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)),&color)) + *dark = color.pixel; + else + return 0; + + if (incr) { + float avg; + avg = (float)(to[0]+to[1]+to[2])/3; + rv = avg + (float)(to[0]/2); + gv = avg + (float)(to[1]/2); + bv = avg + (float)(to[2]/2); + } else { + float avg; + avg = (float)(from[0]+from[1]+from[2])/3; + rv = avg + (float)(from[0]/2); + gv = avg + (float)(from[1]/2); + bv = avg + (float)(from[2]/2); + } + color.red = (unsigned short)(rv>65535.0 ? 65535.0:rv); + color.green = (unsigned short)(gv>65535.0 ? 65535.0:gv); + color.blue = (unsigned short)(bv>65535.0 ? 65535.0:bv); + if (XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), + &color)) + *light = color.pixel; + else + return 0; + return 1; +} diff --git a/app/fvwm/extras/FvwmWharf/stepgfx.h b/app/fvwm/extras/FvwmWharf/stepgfx.h new file mode 100644 index 000000000..902f5a06f --- /dev/null +++ b/app/fvwm/extras/FvwmWharf/stepgfx.h @@ -0,0 +1,33 @@ + + + +#ifndef STEPGFX_H_ +#define STEPGFX_H_ + +#define TEXTURE_SOLID 0 +#define TEXTURE_GRADIENT 1 +#define TEXTURE_HGRADIENT 2 +#define TEXTURE_HCGRADIENT 3 +#define TEXTURE_VGRADIENT 4 +#define TEXTURE_VCGRADIENT 5 + +#define TEXTURE_PIXMAP 128 + +#define TEXTURE_BUILTIN 255 + +extern int DrawVGradient(Display *dpy, Drawable d, int x, int y, int w, int h, + int from[3], int to[3], int relief, int maxcols, + int type); +extern int DrawHGradient(Display *dpy, Drawable d, int x, int y, int w, int h, + int from[3], int to[3], int relief, int maxcols, + int type); +extern int DrawDegradeRelief(Display *dpy, Drawable d, int x, int y, int w, + int h, int from[3], int to[3], int relief, + int maxcols); +extern void DrawTexturedText(Display *dpy, Drawable d, XFontStruct *font, + int x, int y, Pixmap gradient, char *text, int chars); + +extern int MakeShadowColors(Display *dpy, int from[3], int to[3], + unsigned long *dark, unsigned long *light); + +#endif |