Finally does subdirectories in the ~/.wmx directory to make submenus.

This commit is contained in:
Bill Spitzak
2007-08-03 05:39:01 +00:00
parent aa276ead5c
commit 14c1417763

69
Menu.C
View File

@ -307,13 +307,11 @@ init(Fl_Menu_Item& m, const char* data)
#if WMX_MENU_ITEMS #if WMX_MENU_ITEMS
// wmxlist is an array of char* pointers (for efficient sorting purposes),
// which are stored in wmxbuffer (for memory efficiency and to avoid
// freeing and fragmentation)
static char** wmxlist = NULL;
static int wmxlistsize = 0;
// wmx commands are read from ~/.wmx, // wmx commands are read from ~/.wmx,
// they are stored null-separated here: // and stored null-separated here by scan_wmx_dir:
// The strings are kept in this single buffer for memory efficiency and
// to avoid freeing and fragmentation as the scan is done many times:
// Each string has a leading character for the nesting level.
static char* wmxbuffer = NULL; static char* wmxbuffer = NULL;
static int wmxbufsize = 0; static int wmxbufsize = 0;
static int num_wmx = 0; static int num_wmx = 0;
@ -334,22 +332,30 @@ scan_wmx_dir (char *path, int bufindex, int nest)
strcpy(path+pathlen, ent->d_name); strcpy(path+pathlen, ent->d_name);
if (stat(path, &st) < 0) continue; if (stat(path, &st) < 0) continue;
int len = pathlen+strlen(ent->d_name); int len = pathlen+strlen(ent->d_name);
// worst-case alloc needs while (bufindex+len+2 > wmxbufsize) { // worst-case alloc needs
if (bufindex+len+nest+1 > wmxbufsize) wmxbufsize = wmxbufsize ? 2*wmxbufsize : 1024;
wmxbuffer = (char*)realloc(wmxbuffer, (wmxbufsize+=1024)); wmxbuffer = (char*)realloc(wmxbuffer, wmxbufsize);
for (int i=0; i<nest; i++) }
wmxbuffer[bufindex++] = '/'; // extra slash marks menu titles int start = bufindex; // remember where it started so we can delete it
if (S_ISDIR(st.st_mode) && (st.st_mode & 0555) && nest<MAX_NESTING_DEPTH){ wmxbuffer[bufindex++] = nest; // remember nesting level
strcpy(wmxbuffer+bufindex, path); strcpy(wmxbuffer+bufindex, path);
bufindex += len+1; bufindex += len+1;
strcat(path, "/");
bufindex = scan_wmx_dir (path, bufindex, nest+1);
num_wmx++; num_wmx++;
if (S_ISDIR(st.st_mode) && (st.st_mode & 0555) && nest<MAX_NESTING_DEPTH) {
strcpy(path+len, "/");
int oldcount = num_wmx;
bufindex = scan_wmx_dir (path, bufindex, nest+1);
if (num_wmx == oldcount) {
// ignore empty directories
bufindex = start;
num_wmx--;
}
} else if (S_ISREG(st.st_mode) && (st.st_mode & 0111)) { } else if (S_ISREG(st.st_mode) && (st.st_mode & 0111)) {
// make sure it exists and is an executable file: // make sure it exists and is an executable file:
strcpy(wmxbuffer+bufindex, path); } else {
bufindex += len+1; // ignore other files
num_wmx++; bufindex = start;
num_wmx--;
} }
} }
closedir(dir); closedir(dir);
@ -357,14 +363,17 @@ scan_wmx_dir (char *path, int bufindex, int nest)
return bufindex; return bufindex;
} }
// They are then split into this array of char* pointers for sorting:
static char** wmxlist = NULL;
static int wmxlistsize = 0;
// comparison for qsort // comparison for qsort
// We keep submenus together by noting that they're proper superstrings // We keep submenus together by noting that they're proper superstrings
static int static int
wmxCompare(const void *A, const void *B) wmxCompare(const void *A, const void *B)
{ {
char *pA, *pB; char* pA = *(char **)A+1; // skip leading nesting level indicator
pA = *(char **)A; char* pB = *(char **)B+1;
pB = *(char **)B;
pA += strspn(pA, "/"); pA += strspn(pA, "/");
pB += strspn(pB, "/"); pB += strspn(pB, "/");
@ -385,7 +394,7 @@ wmxCompare(const void *A, const void *B)
return(0); return(0);
} }
static void void
load_wmx() load_wmx()
{ {
const char* home=getenv("HOME"); if (!home) home = "."; const char* home=getenv("HOME"); if (!home) home = ".";
@ -409,10 +418,9 @@ load_wmx()
} }
for (int i=0; i<num_wmx; i++) { for (int i=0; i<num_wmx; i++) {
char* cmd = wmxbuffer; char* cmd = wmxbuffer;
for (int j = 0; j < num_wmx; j++) { for (int j = 0; j < num_wmx; j++) {
wmxlist[j] = cmd; wmxlist[j] = cmd;
cmd += strlen(cmd)+1; cmd += strlen(cmd+1)+2;
} }
} }
@ -463,10 +471,10 @@ ShowTabMenu(int tab)
load_wmx(); load_wmx();
if (num_wmx) { if (num_wmx) {
n -= 1; // delete "new xterm" n -= 1; // delete "new xterm"
// add wmx items // count the wmx items, plus an extra for submenu terminators:
int level = 0; int level = 0;
for (int i=0; i<num_wmx; i++) { for (int i=0; i<num_wmx; i++) {
int nextlev = (i==num_wmx-1)?0:strspn(wmxlist[i+1], "/")-1; int nextlev = (i==num_wmx-1) ? 0 : wmxlist[i+1][0];
if (nextlev < level) { if (nextlev < level) {
n += level-nextlev; n += level-nextlev;
level = nextlev; level = nextlev;
@ -608,9 +616,9 @@ ShowTabMenu(int tab)
int level = 0; int level = 0;
pathlen[0] = wmx_pathlen; pathlen[0] = wmx_pathlen;
for (int i = 0; i < num_wmx; i++) { for (int i = 0; i < num_wmx; i++) {
cmd = wmxlist[i]; cmd = wmxlist[i]+1; // skip level number
cmd += strspn(cmd, "/")-1;
init(menu[n], cmd+pathlen[level]); init(menu[n], cmd+pathlen[level]);
menu[n].callback(spawn_cb, cmd);
#if FL_MAJOR_VERSION < 2 #if FL_MAJOR_VERSION < 2
#if DESKTOPS #if DESKTOPS
if (one_desktop) if (one_desktop)
@ -618,10 +626,9 @@ ShowTabMenu(int tab)
if (!level) if (!level)
menu[n].labeltype(TEXT_LABEL); menu[n].labeltype(TEXT_LABEL);
#endif #endif
int nextlev = (i==num_wmx-1)?0:strspn(wmxlist[i+1], "/")-1; int nextlev = (i==num_wmx-1) ? 0 : wmxlist[i+1][0];
if (nextlev < level) { if (nextlev < level) {
menu[n].callback(spawn_cb, cmd); // add null terminators to turn off levels
// Close 'em off
for (; level>nextlev; level--) for (; level>nextlev; level--)
init(menu[++n], 0); init(menu[++n], 0);
} else if (nextlev > level) { } else if (nextlev > level) {
@ -629,8 +636,6 @@ ShowTabMenu(int tab)
pathlen[++level] = strlen(cmd)+1; // extra for next trailing / pathlen[++level] = strlen(cmd)+1; // extra for next trailing /
menu[n].flags = FL_SUBMENU; menu[n].flags = FL_SUBMENU;
menu[n].callback((Fl_Callback*)0); menu[n].callback((Fl_Callback*)0);
} else {
menu[n].callback(spawn_cb, cmd);
} }
n++; n++;
} }