/* 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 /* Saul */ #endif #include #include #include #include #include #include #if HAVE_SYS_SELECT_H #include #endif #include #include #include #include "../../fvwm/module.h" #include #include #include #include #include #include #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;i0 && 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 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;x1) { 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=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;i0 && 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;i1)&& (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 (iparent = &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;iicons[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;iiconno;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;iiconno;i++) { free(actual->icons[i].file); } actual->iconno=0; } else { num_folderbuttons++; free(ptr); for(i=0;iiconno;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 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;iw * 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;imodifiermap; for (m = 0; m < 8; m++) { for (i = 0; i < mm->max_keypermod; i++) { if ((kc = *kp++) && ((ks = XKeycodeToKeysym(dpy, kc, 0)) != NoSymbol)) { kn = XKeysymToString(ks); knl = strlen(kn); if ((knl > 6) && (strcasecmp(kn + knl - 4, "lock") == 0)) lockmask |= (1 << m); } } } XFreeModifiermap(mm); } lockmask &= ~(ShiftMask | ControlMask); mp = lock_mods; for (m = 0, i = 1; i < 256; i++) { if ((i & lockmask) > m) m = *mp++ = (i & lockmask); } *mp = 0; } /*********************************************************************** * * Procedure: * ConstrainSize - adjust the given width and height to account for the * constraints imposed by size hints * * The general algorithm, especially the aspect ratio stuff, is * borrowed from uwm's CheckConsistency routine. * ***********************************************************************/ void ConstrainSize (XSizeHints *hints, int *widthp, int *heightp) { #define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) ) #define _min(a,b) (((a) < (b)) ? (a) : (b)) int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc, delta; int baseWidth, baseHeight; int dwidth = *widthp, dheight = *heightp; if(hints->flags & PMinSize) { minWidth = hints->min_width; minHeight = hints->min_height; if(hints->flags & PBaseSize) { baseWidth = hints->base_width; baseHeight = hints->base_height; } else { baseWidth = hints->min_width; baseHeight = hints->min_height; } } else if(hints->flags & PBaseSize) { minWidth = hints->base_width; minHeight = hints->base_height; baseWidth = hints->base_width; baseHeight = hints->base_height; } else { minWidth = 1; minHeight = 1; baseWidth = 1; baseHeight = 1; } if(hints->flags & PMaxSize) { maxWidth = hints->max_width; maxHeight = hints->max_height; } else { maxWidth = 10000; maxHeight = 10000; } if(hints->flags & PResizeInc) { xinc = hints->width_inc; yinc = hints->height_inc; } else { xinc = 1; yinc = 1; } /* * First, clamp to min and max values */ if (dwidth < minWidth) dwidth = minWidth; if (dheight < minHeight) dheight = minHeight; if (dwidth > maxWidth) dwidth = maxWidth; if (dheight > maxHeight) dheight = maxHeight; /* * Second, fit to base + N * inc */ dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth; dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight; /* * Third, adjust for aspect ratio */ #define maxAspectX hints->max_aspect.x #define maxAspectY hints->max_aspect.y #define minAspectX hints->min_aspect.x #define minAspectY hints->min_aspect.y /* * The math looks like this: * * minAspectX dwidth maxAspectX * ---------- <= ------- <= ---------- * minAspectY dheight maxAspectY * * If that is multiplied out, then the width and height are * invalid in the following situations: * * minAspectX * dheight > minAspectY * dwidth * maxAspectX * dheight < maxAspectY * dwidth * */ if (hints->flags & PAspect) { if (minAspectX * dheight > minAspectY * dwidth) { delta = makemult(minAspectX * dheight / minAspectY - dwidth, xinc); if (dwidth + delta <= maxWidth) dwidth += delta; else { delta = makemult(dheight - dwidth*minAspectY/minAspectX, yinc); if (dheight - delta >= minHeight) dheight -= delta; } } if (maxAspectX * dheight < maxAspectY * dwidth) { delta = makemult(dwidth * maxAspectY / maxAspectX - dheight, yinc); if (dheight + delta <= maxHeight) dheight += delta; else { delta = makemult(dwidth - maxAspectX*dheight/maxAspectY, xinc); if (dwidth - delta >= minWidth) dwidth -= delta; } } } *widthp = dwidth; *heightp = dheight; return; } #ifdef ENABLE_SOUND void PlaySound(int event) { int timestamp; if (!SoundActive) return; if (Sounds[event]==NULL) return; write(PlayerChannel[1],&event,sizeof(event)); timestamp = clock(); write(PlayerChannel[1],×tamp,sizeof(timestamp)); /* kill(SoundThread,SIGUSR1); */ } #endif