summaryrefslogtreecommitdiff
path: root/app/fvwm/extras/FvwmWharf
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 10:53:58 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2006-11-26 10:53:58 +0000
commit1cb4778bcef21ea9015cfccdb99abb7a0e035d74 (patch)
treef164009397f9d3d5634c6f8a94b1542f793d9692 /app/fvwm/extras/FvwmWharf
parent841f8331c93ff96bd798e9a74ba10fab155da5c5 (diff)
Importing from XF4, plus BSD make infrastructure
Diffstat (limited to 'app/fvwm/extras/FvwmWharf')
-rw-r--r--app/fvwm/extras/FvwmWharf/ASSound/ASSound.c242
-rw-r--r--app/fvwm/extras/FvwmWharf/ASSound/README1
-rw-r--r--app/fvwm/extras/FvwmWharf/FvwmWharf.1205
-rw-r--r--app/fvwm/extras/FvwmWharf/FvwmWharf.c2443
-rw-r--r--app/fvwm/extras/FvwmWharf/OffiX/DragAndDrop.h48
-rw-r--r--app/fvwm/extras/FvwmWharf/OffiX/DragAndDropTypes.h32
-rw-r--r--app/fvwm/extras/FvwmWharf/README22
-rw-r--r--app/fvwm/extras/FvwmWharf/Wharf.h121
-rw-r--r--app/fvwm/extras/FvwmWharf/icons.c367
-rw-r--r--app/fvwm/extras/FvwmWharf/sample.style41
-rw-r--r--app/fvwm/extras/FvwmWharf/stepgfx.c587
-rw-r--r--app/fvwm/extras/FvwmWharf/stepgfx.h33
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,&timestamp,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],&timestamp,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