/* wmmount - The Window Maker universal mount point * * 17/06/99 Release 1.0 beta2 * Copyright (C) 1999 Sam Hawker * This software comes with ABSOLUTELY NO WARRANTY * This software is free software, and you are welcome to redistribute it * under certain conditions * See the README file for details. */ /* User defines */ /* Intervals * INTERVAL - Minimum interval unit in usecs * INTERVAL1 - Update interval in multiples of def_interval * INTERVAL2 - Button repeat interval in multiples of def_interval * INTERVAL3 - Double-click interval in multiples of def_interval */ #define INTERVAL 250000 #define INTERVAL1 10 #define INTERVAL2 1 #define INTERVAL3 1 /* Maximum allowed mountpoints and icons */ #define MAXICONS 20 #define MAXMPOINTS 20 /* System-wide config file */ #define SYSCONFIG "/usr/X11R6/lib/X11/wmmount/system.wmmount" /* Config file defaults */ #define MOUNTCMD "/bin/mount %m" #define UMOUNTCMD "/bin/umount %m" #define OPENCMD "/usr/X11R6/bin/nxterm -T '%n - %m' -e mc %m" #define NAMEFONT "-*-helvetica-bold-r-*-*-10-*-*-*-*-*-*-*" #define USAGEFONT "-*-helvetica-medium-r-*-*-10-*-*-*-*-*-*-*" /* End of user defines * * -- AVOID MAKING MODIFICATIONS BEYOND THIS POINT -- */ /* Includes */ #include "dockapp.h" #include #include #include #ifdef __linux__ #include #include #endif #ifdef __FreeBSD__ #include #include #endif #include "xpm/main.xpm" /* Variables */ Pixmap pm_main; Pixmap pm_main_mask; char *mountcmd=NULL; char *umountcmd=NULL; char *opencmd=NULL; char *namefont=NULL; char *usagefont=NULL; Font f_name, f_usage; Pixmap pm_icon[MAXICONS]; int icons=0; struct mpinfo { char *mpoint; char *name; char *mountcmd; char *umountcmd; char *opencmd; int icon; int udisplay; } mpoint[MAXMPOINTS]; int mpoints=0; int namex, namey, usagex, usagey; #define BUTTON1 (int)(1<<0) #define BUTTON2 (int)(1<<1) #define BUTTON3 (int)(1<<2) #define DCLICK (int)(1<<3) #define PREV BUTTON1 #define NEXT BUTTON2 int state=0; int select1=0; int counter1=0; int counter2=0; int counter3=0; bool mounted; int usage; char usagestr[8]; /* Functions and procedures */ int main(int argc, char **argv); void init(int argc, char * const *argv); void done(); void mainloop(); void buttonpress(XButtonEvent *xev); void buttonrelease(XButtonEvent *xev); int config_init(); void config_done(); void xpm_init(); void xpm_done(); void font_init(); void font_done(); void checkmount(bool forced); void drawall(); void drawbtns(int btnmask); void drawbtn(int x, int y, int w, int h, bool down); void execcmd(char *cmd, char *path); /* Implementation */ int main(int argc, char **argv) { /* Initialize */ init(argc, (char * const *)argv); /* Initialize dockapp */ dockapp_init(argc, (char * const *)argv); /* Open dockapp */ if(!dockapp_open()) { /* Read config file */ if(!config_init()) { /* Initialize xpms */ xpm_init(); /* Initialize fonts */ font_init(); /* Check mounts */ checkmount(true); /* Draw everything */ drawall(); /* Execute main loop */ mainloop(); /* Free fonts */ font_done(); /* Free xpms */ xpm_done(); /* Free config file data */ config_done(); } /* Close dockapp */ dockapp_close(); } /* Free dockapp */ dockapp_done(); /* Free */ done(); /* Finish */ return 0; } void init(int argc, char * const *argv) { /* Process command-line arguments */ int option_index; int option_c; struct option long_options[] = { {"help", 0, NULL, 'h' }, {NULL, 0, NULL, '\0'} }; while(true) { option_index=0; option_c=getopt_long(argc, (char * const *)argv, "-h", long_options, &option_index); if(option_c==-1) break; if(option_c==1) { fprintf(stderr, "%s: unwanted argument -- '%s'\n", argv[0], optarg); } if(option_c>1) { switch(option_c) { case 'h': printf("wmmount - The Window Maker universal mount point\n"); printf("\n"); printf("17/06/99 Release 1.0 beta2\n"); printf("Copyright (C) 1999 Sam Hawker \n"); printf("This software comes with ABSOLUTELY NO WARRANTY\n"); printf("This software is free software, and you are welcome to redistribute it\n"); printf("under certain conditions\n"); printf("See the README file for details.\n"); printf("\n"); printf("usage:\n"); printf("\n"); printf(" %s [options] [-- dockapp_options]\n", argv[0]); printf("\n"); printf("options:\n"); printf("\n"); printf(" -h, --help Show this help message\n"); printf("\n"); printf("dockapp options:\n"); printf("\n"); printf(" -h, --help Show dockapp help message\n"); exit(0); } } } } void done() { /* Free command-line option arguments */ } void mainloop() { /* Do the main loop */ XEvent xev; fd_set fds; struct timeval tv; XSelectInput(dockapp_d, dockapp_w_active, ButtonPressMask | ButtonReleaseMask | ExposureMask); XMapWindow(dockapp_d, dockapp_w_main); while(true) { while(XPending(dockapp_d)) { XNextEvent(dockapp_d, &xev); switch(xev.type) { case Expose: dockapp_expose(); break; case ButtonPress: buttonpress(&xev.xbutton); break; case ButtonRelease: buttonrelease(&xev.xbutton); break; case ClientMessage: if(xev.xclient.data.l[0]==dockapp_a_delwin) return; } } FD_ZERO(&fds); FD_SET(ConnectionNumber(dockapp_d), &fds); tv.tv_sec=(long)INTERVAL/1000000L; tv.tv_usec=(long)INTERVAL%1000000L; if(!select(ConnectionNumber(dockapp_d)+1, &fds, NULL, NULL, &tv)) { counter1++; if(counter1>=INTERVAL1) { counter1=0; /* Update interval */ checkmount(false); } counter2++; if(counter2>=INTERVAL2) { counter2=0; /* Button repeat interval */ if(state & (PREV | NEXT)) { if(state & PREV) select1--; else select1++; if(select1<0) select1=mpoints-1; if(select1>=mpoints) select1=0; checkmount(true); } } counter3++; if(counter3>=INTERVAL3) { counter3=0; /* Double-click interval/timeout */ state&=~DCLICK; } } } } void buttonpress(XButtonEvent *xev) { /* Process button press events */ int x=xev->x-(dockapp_size/2-32); int y=xev->y-(dockapp_size/2-32); char *cmd; if(x>=33 && y>=47 && x<=45 && y<=57) { select1--; if(select1<0) select1=mpoints-1; counter2=0; state|=PREV; checkmount(true); return; } if(x>=46 && y>=47 && x<=58 && y<=57) { select1++; if(select1>mpoints-1) select1=0; counter2=0; state|=NEXT; checkmount(true); return; } if(x>=5 && y>=47 && x<=32 && y<=57) { if(mounted) { cmd=mpoint[select1].umountcmd; if(cmd==NULL) cmd=umountcmd; if(cmd==NULL) cmd=UMOUNTCMD; } else { cmd=mpoint[select1].mountcmd; if(cmd==NULL) cmd=mountcmd; if(cmd==NULL) cmd=MOUNTCMD; } execcmd(cmd, NULL); return; } if(x>=4 && y>=4 && x<=59 && y<=42) { if(mounted) { if(state & DCLICK) { cmd=mpoint[select1].opencmd; if(cmd==NULL) cmd=opencmd; if(cmd==NULL) cmd=OPENCMD; execcmd(cmd, NULL); state&=~DCLICK; } else { state|=DCLICK; counter3=0; } } return; } } void buttonrelease(XButtonEvent *xev) { /* Process button release events */ state&=~(PREV | NEXT); drawbtns(PREV | NEXT); dockapp_expose(); } int config_init() { /* Process config file */ char *home; char *filename; FILE *f; char buf[256]; int keynum1; char *keyarg1; static char *keys1[] = { "mountcmd=", "umountcmd=", "opencmd=", "namefont=", "usagefont=", "icon ", "mountpoint ", "" }; int keynum2; char *keyarg2; static char *keys2[] = { "mountpoint ", "name=", "iconnumber=", "usagedisplay=", "mountcmd=", "umountcmd=", "opencmd=", "" }; home=getenv("HOME"); filename=(char *)malloc(strlen(home)+strlen("/.wmmount")+1); sprintf(filename, "%s/.wmmount", home); f=fopen(filename, "r"); free(filename); if(f==NULL) { fprintf(stderr, "%s: User config file not found\n", dockapp_argv[0]); filename=SYSCONFIG; f=fopen(filename, "r"); if(f==NULL) { fprintf(stderr, "%s: System config file not found\n", dockapp_argv[0]); return -1; } } while(1) { fgets(buf, 256, f); if(feof(f)!=0) break; buf[strlen(buf)-1]='\0'; keynum1=0; while(1) { if(strncmp(buf, keys1[keynum1], strlen(keys1[keynum1]))==0) break; keynum1++; } keyarg1=buf+strlen(keys1[keynum1]); if(keynum1==0) mountcmd=strdup(keyarg1); if(keynum1==1) umountcmd=strdup(keyarg1); if(keynum1==2) opencmd=strdup(keyarg1); if(keynum1==3) namefont=strdup(keyarg1); if(keynum1==4) usagefont=strdup(keyarg1); if(keynum1==5) { if(icons0) { mpoints--; free(mpoint[mpoints].mpoint); free(mpoint[mpoints].name); free(mpoint[mpoints].mountcmd); free(mpoint[mpoints].umountcmd); free(mpoint[mpoints].opencmd); } } void xpm_init() { /* Create pixmaps from xpm data */ dockapp_createpixmap(main_xpm, NULL, NULL, &pm_main, &pm_main_mask, NULL, NULL); XCopyArea(dockapp_d, pm_main_mask, dockapp_pm_mask, dockapp_gc_mask, 0, 0, 64, 64, 0, 0); dockapp_installmask(); } void xpm_done() { /* Free xpms */ /* Done automatically by X, so I won't bother */ } void font_init() { /* Initialize fonts */ XFontStruct *xfs; char *font; font=namefont; if(font==NULL) font=NAMEFONT; xfs=XLoadQueryFont(dockapp_d, font); f_name=xfs->fid; namex=6-xfs->min_bounds.lbearing; namey=5+xfs->ascent; usagey=namey; usagey+=xfs->descent; XFreeFontInfo(NULL, xfs, 1); font=usagefont; if(font==NULL) font=USAGEFONT; xfs=XLoadQueryFont(dockapp_d, USAGEFONT); f_usage=xfs->fid; usagex=6-xfs->min_bounds.lbearing; usagey+=xfs->ascent; XFreeFontInfo(NULL, xfs, 1); } void font_done() { /* Free fonts */ /* Done automatically by X */ } void checkmount(bool forced) { /* Check mount and usage */ bool getmounted; int getusage, getavail; dev_t dev1, dev2; struct stat st; struct statfs sfs; char *buf; float value; char unit; getmounted=false; if(strcmp(mpoint[select1].mpoint, "/")==0) /* I think I can assume / is mounted. */ getmounted=true; else { /* Check that the directory above the mount point is on a different device */ buf=strdup(mpoint[select1].mpoint); stat(buf, &st); dev1=st.st_dev; if(buf[strlen(buf)-1]=='/') buf[strlen(buf)-1]='\0'; *(strrchr(buf, '/')+1)='\0'; stat(buf, &st); dev2=st.st_dev; if(memcmp(&dev1, &dev2, sizeof(dev_t))!=0) getmounted=true; free(buf); } if(getmounted && mpoint[select1].udisplay!=0) { statfs(mpoint[select1].mpoint, &sfs); getusage=(sfs.f_blocks-sfs.f_bfree); getavail=(sfs.f_bavail); } if(getmounted && (!mounted || (getusage!=usage) || forced)) { value=getusage; switch(mpoint[select1].udisplay) { case 1: value=getavail; case 2: value*=(float)sfs.f_bsize; value/=1024.0; unit='k'; if(value>=999.5) { value/=1024.0; unit='M'; } if(value>=999.5) { value/=1024.0; unit='G'; } if(value<9.995) { sprintf(usagestr, "%1.02f%cB", value, unit); break; } if(value<99.95) { sprintf(usagestr, "%1.01f%cB", value, unit); break; } if(value<999.5) { sprintf(usagestr, "%1.0f%cB", value, unit); break; } strcpy(usagestr, "E big"); break; case 3: if(getusage+getavail==0) strcpy(usagestr, "E div0"); else sprintf(usagestr, "%.01f%%", getusage*100.0/(getusage+getavail)); break; default: strcpy(usagestr, ""); } } if((getmounted!=mounted) || (getmounted && getusage!=usage && mpoint[select1].udisplay!=0) || forced) { mounted=getmounted; usage=getusage; drawall(); dockapp_expose(); } } void drawall() { /* Draw everything */ XCopyArea(dockapp_d, pm_main, dockapp_pm_main, dockapp_gc_clip, 0, 0, 64, 64, 0, 0); XCopyArea(dockapp_d, pm_icon[mpoint[select1].icon], dockapp_pm_main, dockapp_gc_main, 0, 0, 32, 10, 25, 30); XSetFont(dockapp_d, dockapp_gc_main, f_name); XSetForeground(dockapp_d, dockapp_gc_main, dockapp_color0); XDrawString(dockapp_d, dockapp_pm_main, dockapp_gc_main, namex, namey, (char *)mpoint[select1].name, strlen(mpoint[select1].name)); if(mounted) { XSetFont(dockapp_d, dockapp_gc_main, f_usage); XSetForeground(dockapp_d, dockapp_gc_main, dockapp_color0); XDrawString(dockapp_d, dockapp_pm_main, dockapp_gc_main, usagex, usagey, (char *)usagestr, strlen(usagestr)); } drawbtns(BUTTON1 | BUTTON2 | BUTTON3); } void drawbtns(int btnmask) { /* Draw buttons */ if(btnmask & BUTTON1) drawbtn(33, 47, 13, 11, (state & BUTTON1)); if(btnmask & BUTTON2) drawbtn(46, 47, 13, 11, (state & BUTTON2)); if(btnmask & BUTTON3) drawbtn(5, 47, 28, 11, mounted); } void drawbtn(int x, int y, int w, int h, bool down) { /* Draw single button */ if(down) { XCopyArea(dockapp_d, pm_main, dockapp_pm_main, dockapp_gc_main, x, y, 1, h-1, x+w-1, y+1); XCopyArea(dockapp_d, pm_main, dockapp_pm_main, dockapp_gc_main, x+w-1, y+1, 1, h-1, x, y); XCopyArea(dockapp_d, pm_main, dockapp_pm_main, dockapp_gc_main, x, y, w-1, 1, x+1, y+h-1); XCopyArea(dockapp_d, pm_main, dockapp_pm_main, dockapp_gc_main, x+1, y+h-1, w-1, 1, x, y); } else XCopyArea(dockapp_d, pm_main, dockapp_pm_main, dockapp_gc_main, x, y, w, h, x, y); } void execcmd(char *cmd, char *path) { /* Execute external command (without using /bin/sh) */ /* This has got quite complicated now * * It splits the command-line into its arguments, performs substitutions and * then executes the command * * It doesn't wait for a return and children are reaped using SIGCHLD */ int argc=1; char **argv=NULL; int i, j; char c; int buflen=strlen(cmd)+1; char *buf=(char *)malloc(buflen); bool quoted=false; char quotec; char *subst; int pid; signal(SIGCHLD, SIG_IGN); j=0; for(i=0;i