mirror of
https://git.code.sf.net/p/flwm/flwm
synced 2025-12-12 23:36:58 -05:00
Finally does subdirectories in the ~/.wmx directory to make submenus.
This commit is contained in:
69
Menu.C
69
Menu.C
@ -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++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user