mirror of
https://git.code.sf.net/p/flwm/flwm
synced 2025-12-11 23:06:56 -05:00
668 lines
16 KiB
C
668 lines
16 KiB
C
// Menu.cxx
|
|
|
|
#include "config.h"
|
|
#include "Frame.H"
|
|
#if DESKTOPS
|
|
#include "Desktop.H"
|
|
#endif
|
|
#include <FL/Fl_Box.H>
|
|
#include <FL/Fl_Return_Button.H>
|
|
#include <FL/Fl_Input.H>
|
|
#include <FL/Fl_Menu_Item.H>
|
|
#include <FL/fl_draw.H>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include "FrameWindow.H"
|
|
|
|
#include <sys/types.h>
|
|
#include <dirent.h>
|
|
#include <sys/stat.h>
|
|
|
|
// it is possible for the window to be deleted or withdrawn while
|
|
// the menu is up. This will detect that case (with reasonable
|
|
// reliability):
|
|
static int
|
|
window_deleted(Frame* c)
|
|
{
|
|
return c->state() != NORMAL
|
|
&& c->state() != ICONIC
|
|
&& c->state() != OTHER_DESKTOP;
|
|
}
|
|
|
|
static void
|
|
frame_callback(Fl_Widget*, void*d)
|
|
{
|
|
Frame* c = (Frame*)d;
|
|
if (window_deleted(c)) return;
|
|
c->raise();
|
|
c->activate(2);
|
|
}
|
|
|
|
#if DESKTOPS
|
|
// raise it but also put it on the current desktop:
|
|
static void
|
|
move_frame_callback(Fl_Widget*, void*d)
|
|
{
|
|
Frame* c = (Frame*)d;
|
|
if (window_deleted(c)) return;
|
|
c->desktop(Desktop::current());
|
|
c->raise();
|
|
c->activate(2);
|
|
}
|
|
#endif
|
|
|
|
#define SCREEN_DX 1 // offset to corner of contents area
|
|
#define SCREEN_W (MENU_ICON_W-2) // size of area to draw contents in
|
|
#define SCREEN_H (MENU_ICON_H-2) // size of area to draw contents in
|
|
|
|
#define MAX_NESTING_DEPTH 32
|
|
|
|
extern Fl_Window* Root;
|
|
|
|
#if FL_MAJOR_VERSION < 2
|
|
static void
|
|
frame_label_draw(const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align)
|
|
{
|
|
Frame* f = (Frame*)(o->value);
|
|
if (window_deleted(f)) return;
|
|
fl_draw_box(FL_THIN_DOWN_BOX, X, Y, MENU_ICON_W, MENU_ICON_H, FL_GRAY);
|
|
for (Frame* c = Frame::first; c; c = c->next) {
|
|
if (c->state() != UNMAPPED && (c==f || c->is_transient_for(f))) {
|
|
int x = ((c->x()-Root->x())*SCREEN_W+Root->w()/2)/Root->w();
|
|
int w = (c->w()*SCREEN_W+Root->w()-1)/Root->w();
|
|
if (w > SCREEN_W) w = SCREEN_W;
|
|
if (w < 3) w = 3;
|
|
if (x+w > SCREEN_W) x = SCREEN_W-w;
|
|
if (x < 0) x = 0;
|
|
int y = ((c->y()-Root->y())*SCREEN_H+Root->h()/2)/Root->h();
|
|
int h = (c->h()*SCREEN_H+Root->h()-1)/Root->h();
|
|
if (h > SCREEN_H) h = SCREEN_H;
|
|
if (h < 3) h = 3;
|
|
if (y+h > SCREEN_H) y = SCREEN_H-h;
|
|
if (y < 0) y = 0;
|
|
fl_color(FL_FOREGROUND_COLOR);
|
|
if (c->state() == ICONIC)
|
|
fl_rect(X+x+SCREEN_DX, Y+y+SCREEN_DX, w, h);
|
|
else
|
|
fl_rectf(X+x+SCREEN_DX, Y+y+SCREEN_DX, w, h);
|
|
}
|
|
}
|
|
fl_font(o->font, o->size);
|
|
fl_color((Fl_Color)o->color);
|
|
const char* l = f->label(); if (!l) l = "unnamed";
|
|
// double any ampersands to turn off the underscores:
|
|
char buf[256];
|
|
if (strchr(l,'&')) {
|
|
char* t = buf;
|
|
while (t < buf+254 && *l) {
|
|
if (*l=='&') *t++ = *l;
|
|
*t++ = *l++;
|
|
}
|
|
*t = 0;
|
|
l = buf;
|
|
}
|
|
fl_draw(l, X+MENU_ICON_W+3, Y, W-MENU_ICON_W-3, H, align);
|
|
}
|
|
|
|
static void
|
|
frame_label_measure(const Fl_Label* o, int& W, int& H)
|
|
{
|
|
Frame* f = (Frame*)(o->value);
|
|
if (window_deleted(f)) {W = MENU_ICON_W+3; H = MENU_ICON_H; return;}
|
|
const char* l = f->label(); if (!l) l = "unnamed";
|
|
fl_font(o->font, o->size);
|
|
fl_measure(l, W, H);
|
|
W += MENU_ICON_W+3;
|
|
if (W > MAX_MENU_WIDTH) W = MAX_MENU_WIDTH;
|
|
if (H < MENU_ICON_H) H = MENU_ICON_H;
|
|
}
|
|
|
|
// This labeltype is used for non-frame items so the text can line
|
|
// up with the icons:
|
|
|
|
static void
|
|
label_draw(const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align)
|
|
{
|
|
fl_font(o->font, o->size);
|
|
fl_color((Fl_Color)o->color);
|
|
fl_draw(o->value, X+MENU_ICON_W+3, Y, W-MENU_ICON_W-3, H, align);
|
|
}
|
|
|
|
static void
|
|
label_measure(const Fl_Label* o, int& W, int& H)
|
|
{
|
|
fl_font(o->font, o->size);
|
|
fl_measure(o->value, W, H);
|
|
W += MENU_ICON_W+3;
|
|
if (W > MAX_MENU_WIDTH) W = MAX_MENU_WIDTH;
|
|
if (H < MENU_ICON_H) H = MENU_ICON_H;
|
|
}
|
|
|
|
#define FRAME_LABEL FL_FREE_LABELTYPE
|
|
#define TEXT_LABEL Fl_Labeltype(FL_FREE_LABELTYPE+1)
|
|
|
|
#endif // FL_MAJOR_VERSION < 2
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
static void
|
|
cancel_cb(Fl_Widget* w, void*)
|
|
{
|
|
w->window()->hide();
|
|
}
|
|
|
|
#if DESKTOPS
|
|
|
|
static void
|
|
desktop_cb(Fl_Widget*, void* v)
|
|
{
|
|
Desktop::current((Desktop*)v);
|
|
}
|
|
|
|
static void
|
|
delete_desktop_cb(Fl_Widget*, void* v)
|
|
{
|
|
delete (Desktop*)v;
|
|
}
|
|
|
|
#if ASK_FOR_NEW_DESKTOP_NAME
|
|
|
|
static Fl_Input* new_desktop_input = 0;
|
|
|
|
static void
|
|
new_desktop_ok_cb(Fl_Widget* w, void*)
|
|
{
|
|
w->window()->hide();
|
|
Desktop::current(new Desktop(new_desktop_input->value(), Desktop::available_number()));
|
|
}
|
|
|
|
static void
|
|
new_desktop_cb(Fl_Widget*, void*)
|
|
{
|
|
if (!new_desktop_input) {
|
|
FrameWindow* w = new FrameWindow(190,90);
|
|
new_desktop_input = new Fl_Input(10,30,170,25,"New desktop name:");
|
|
new_desktop_input->align(FL_ALIGN_TOP_LEFT);
|
|
new_desktop_input->labelfont(FL_BOLD);
|
|
Fl_Return_Button* b = new Fl_Return_Button(100,60,80,20,"OK");
|
|
b->callback(new_desktop_ok_cb);
|
|
Fl_Button* b2 = new Fl_Button(10,60,80,20,"Cancel");
|
|
b2->callback(cancel_cb);
|
|
w->set_non_modal();
|
|
w->end();
|
|
}
|
|
char buf[120];
|
|
sprintf(buf, "Desktop %d", Desktop::available_number());
|
|
new_desktop_input->value(buf);
|
|
new_desktop_input->window()->hotspot(new_desktop_input);
|
|
new_desktop_input->window()->show();
|
|
}
|
|
|
|
#else // !ASK_FOR_NEW_DESKTOP_NAME
|
|
|
|
static void
|
|
new_desktop_cb(Fl_Widget*, void*)
|
|
{
|
|
char buf[120];
|
|
int i = Desktop::available_number();
|
|
sprintf(buf, "Desktop %d", i);
|
|
Desktop::current(new Desktop(buf, i));
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
static void
|
|
exit_cb(Fl_Widget*, void*)
|
|
{
|
|
printf("exit_cb\n");
|
|
Frame::save_protocol();
|
|
exit(0);
|
|
}
|
|
|
|
static void
|
|
logout_cb(Fl_Widget*, void*)
|
|
{
|
|
static FrameWindow* w = 0;
|
|
if (!w) {
|
|
w = new FrameWindow(190,90);
|
|
Fl_Box* l = new Fl_Box(0, 0, 190, 60, "Really log out?");
|
|
l->labelfont(FL_BOLD);
|
|
Fl_Return_Button* b = new Fl_Return_Button(100,60,80,20,"OK");
|
|
b->callback(exit_cb);
|
|
Fl_Button* b2 = new Fl_Button(10,60,80,20,"Cancel");
|
|
b2->callback(cancel_cb);
|
|
w->set_non_modal();
|
|
w->end();
|
|
}
|
|
w->hotspot(w);
|
|
w->show();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
#include <unistd.h>
|
|
#include <sys/wait.h>
|
|
#include <errno.h>
|
|
|
|
#if XTERM_MENU_ITEM || WMX_MENU_ITEMS
|
|
|
|
static const char* xtermname = "xterm";
|
|
|
|
static void
|
|
spawn_cb(Fl_Widget*, void*n)
|
|
{
|
|
char* name = (char*)n;
|
|
// strange code thieved from 9wm to avoid leaving zombies
|
|
if (fork() == 0) {
|
|
if (fork() == 0) {
|
|
close(ConnectionNumber(fl_display));
|
|
if (name == xtermname) execlp(name, name, "-ut", (void*)0);
|
|
else execl(name, name, (void*)0);
|
|
fprintf(stderr, "flwm: can't run %s, %s\n", name, strerror(errno));
|
|
XBell(fl_display, 70);
|
|
exit(1);
|
|
}
|
|
exit(0);
|
|
}
|
|
wait((int *) 0);
|
|
}
|
|
|
|
#endif
|
|
|
|
static Fl_Menu_Item other_menu_items[] = {
|
|
#if XTERM_MENU_ITEM
|
|
{"New xterm", 0, spawn_cb, (void*)xtermname, 0, 0, 0, MENU_FONT_SIZE},
|
|
#endif
|
|
#if DESKTOPS
|
|
{"New desktop", 0, new_desktop_cb, 0, 0, 0, 0, MENU_FONT_SIZE},
|
|
#endif
|
|
{"Logout", 0, logout_cb, 0, 0, 0, 0, MENU_FONT_SIZE},
|
|
{0}};
|
|
#define num_other_items (sizeof(other_menu_items)/sizeof(Fl_Menu_Item))
|
|
|
|
// use this to fill in a menu location:
|
|
static void
|
|
init(Fl_Menu_Item& m, const char* data)
|
|
{
|
|
#ifdef HAVE_STYLES
|
|
m.style = 0;
|
|
#endif
|
|
m.label(data);
|
|
#if FL_MAJOR_VERSION > 2
|
|
m.flags = fltk::RAW_LABEL;
|
|
#else
|
|
m.flags = 0;
|
|
#endif
|
|
m.labeltype(FL_NORMAL_LABEL);
|
|
m.shortcut(0);
|
|
m.labelfont(MENU_FONT_SLOT);
|
|
m.labelsize(MENU_FONT_SIZE);
|
|
m.labelcolor(FL_FOREGROUND_COLOR);
|
|
}
|
|
|
|
#if WMX_MENU_ITEMS
|
|
|
|
// wmx commands are read from ~/.wmx,
|
|
// 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 int wmxbufsize = 0;
|
|
static int num_wmx = 0;
|
|
static time_t wmx_time = 0;
|
|
static int wmx_pathlen = 0;
|
|
|
|
static int
|
|
scan_wmx_dir (char *path, int bufindex, int nest)
|
|
{
|
|
DIR* dir = opendir(path);
|
|
struct stat st;
|
|
int pathlen = strlen (path);
|
|
if (dir) {
|
|
struct dirent* ent;
|
|
while ((ent=readdir(dir))) {
|
|
if (ent->d_name[0] == '.')
|
|
continue;
|
|
strcpy(path+pathlen, ent->d_name);
|
|
if (stat(path, &st) < 0) continue;
|
|
int len = pathlen+strlen(ent->d_name);
|
|
while (bufindex+len+2 > wmxbufsize) { // worst-case alloc needs
|
|
wmxbufsize = wmxbufsize ? 2*wmxbufsize : 1024;
|
|
wmxbuffer = (char*)realloc(wmxbuffer, wmxbufsize);
|
|
}
|
|
int start = bufindex; // remember where it started so we can delete it
|
|
wmxbuffer[bufindex++] = nest; // remember nesting level
|
|
strcpy(wmxbuffer+bufindex, path);
|
|
bufindex += len+1;
|
|
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)) {
|
|
// make sure it exists and is an executable file:
|
|
} else {
|
|
// ignore other files
|
|
bufindex = start;
|
|
num_wmx--;
|
|
}
|
|
}
|
|
closedir(dir);
|
|
}
|
|
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
|
|
// We keep submenus together by noting that they're proper superstrings
|
|
static int
|
|
wmxCompare(const void *A, const void *B)
|
|
{
|
|
char* pA = *(char **)A+1; // skip leading nesting level indicator
|
|
char* pB = *(char **)B+1;
|
|
|
|
pA += strspn(pA, "/");
|
|
pB += strspn(pB, "/");
|
|
|
|
// caseless compare
|
|
while (*pA && *pB) {
|
|
if (toupper(*pA) > toupper(*pB))
|
|
return(1);
|
|
if (toupper(*pA) < toupper(*pB))
|
|
return(-1);
|
|
pA++;
|
|
pB++;
|
|
}
|
|
if (*pA)
|
|
return(1);
|
|
if (*pB)
|
|
return(-1);
|
|
return(0);
|
|
}
|
|
|
|
void
|
|
load_wmx()
|
|
{
|
|
const char* home=getenv("HOME"); if (!home) home = ".";
|
|
char path[1024];
|
|
strcpy(path, home);
|
|
if (path[strlen(path)-1] != '/') strcat(path, "/");
|
|
strcat(path, ".wmx/");
|
|
struct stat st; if (stat(path, &st) < 0) return;
|
|
if (st.st_mtime == wmx_time) return;
|
|
wmx_time = st.st_mtime;
|
|
num_wmx = 0;
|
|
wmx_pathlen = strlen(path);
|
|
scan_wmx_dir(path, 0, 0);
|
|
|
|
// Build wmxlist
|
|
if (num_wmx > wmxlistsize) {
|
|
if (wmxlist)
|
|
delete [] wmxlist;
|
|
wmxlist = new char *[num_wmx];
|
|
wmxlistsize = num_wmx;
|
|
}
|
|
for (int i=0; i<num_wmx; i++) {
|
|
char* cmd = wmxbuffer;
|
|
for (int j = 0; j < num_wmx; j++) {
|
|
wmxlist[j] = cmd;
|
|
cmd += strlen(cmd+1)+2;
|
|
}
|
|
}
|
|
|
|
qsort(wmxlist, num_wmx, sizeof(char *), wmxCompare);
|
|
}
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
int exit_flag; // set by the -x switch
|
|
|
|
static int is_active_frame(Frame* c) {
|
|
for (Frame* a = Frame::activeFrame(); a; a = a->transient_for())
|
|
if (a == c) return 1;
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
ShowTabMenu(int tab)
|
|
{
|
|
|
|
static char beenhere;
|
|
if (!beenhere) {
|
|
beenhere = 1;
|
|
#if FL_MAJOR_VERSION < 2
|
|
Fl::set_labeltype(FRAME_LABEL, frame_label_draw, frame_label_measure);
|
|
Fl::set_labeltype(TEXT_LABEL, label_draw, label_measure);
|
|
#endif
|
|
if (exit_flag) {
|
|
Fl_Menu_Item* m = other_menu_items+num_other_items-2;
|
|
m->label("Exit");
|
|
m->callback(exit_cb);
|
|
}
|
|
}
|
|
|
|
static Fl_Menu_Item* menu = 0;
|
|
static int arraysize = 0;
|
|
|
|
#if DESKTOPS
|
|
int one_desktop = !Desktop::first->next;
|
|
#endif
|
|
|
|
// count up how many items are on the menu:
|
|
|
|
int n = num_other_items;
|
|
#if WMX_MENU_ITEMS
|
|
load_wmx();
|
|
if (num_wmx) {
|
|
n -= 1; // delete "new xterm"
|
|
// count the wmx items, plus an extra for submenu terminators:
|
|
int level = 0;
|
|
for (int i=0; i<num_wmx; i++) {
|
|
int nextlev = (i==num_wmx-1) ? 0 : wmxlist[i+1][0];
|
|
if (nextlev < level) {
|
|
n += level-nextlev;
|
|
level = nextlev;
|
|
} else if (nextlev > level)
|
|
level++;
|
|
n++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if DESKTOPS
|
|
// count number of items per desktop in these variables:
|
|
int numsticky = 0;
|
|
Desktop* d;
|
|
for (d = Desktop::first; d; d = d->next) d->junk = 0;
|
|
#endif
|
|
|
|
// every frame contributes 1 item:
|
|
Frame* c;
|
|
for (c = Frame::first; c; c = c->next) {
|
|
if (c->state() == UNMAPPED || c->transient_for()) continue;
|
|
#if DESKTOPS
|
|
if (!c->desktop()) {
|
|
numsticky++;
|
|
} else {
|
|
c->desktop()->junk++;
|
|
}
|
|
#endif
|
|
n++;
|
|
}
|
|
|
|
#if DESKTOPS
|
|
if (!one_desktop) {
|
|
// add the sticky "desktop":
|
|
n += 2; if (!numsticky) n++;
|
|
if (Desktop::current()) {
|
|
n += numsticky;
|
|
Desktop::current()->junk += numsticky;
|
|
}
|
|
// every desktop contributes menu title, null terminator,
|
|
// and possible delete:
|
|
for (d = Desktop::first; d; d = d->next) {
|
|
n += 2; if (!d->junk) n++;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (n > arraysize) {
|
|
delete[] menu;
|
|
menu = new Fl_Menu_Item[arraysize = n];
|
|
}
|
|
|
|
// build the menu:
|
|
n = 0;
|
|
const Fl_Menu_Item* preset = 0;
|
|
const Fl_Menu_Item* first_on_desk = 0;
|
|
#if DESKTOPS
|
|
if (one_desktop) {
|
|
#endif
|
|
for (c = Frame::first; c; c = c->next) {
|
|
if (c->state() == UNMAPPED || c->transient_for()) continue;
|
|
#if FL_MAJOR_VERSION < 2
|
|
init(menu[n],(char*)c);
|
|
menu[n].labeltype(FRAME_LABEL);
|
|
#else
|
|
init(menu[n],c->label());
|
|
#endif
|
|
menu[n].callback(frame_callback, c);
|
|
if (is_active_frame(c)) preset = menu+n;
|
|
n++;
|
|
}
|
|
if (n > 0) first_on_desk = menu;
|
|
#if DESKTOPS
|
|
} else for (d = Desktop::first; ; d = d->next) {
|
|
// this loop adds the "sticky" desktop last, when d==0
|
|
if (d == Desktop::current()) preset = menu+n;
|
|
init(menu[n], d ? d->name() : "Sticky");
|
|
menu[n].callback(desktop_cb, d);
|
|
menu[n].flags = FL_SUBMENU;
|
|
n++;
|
|
if (d && !d->junk) {
|
|
init(menu[n],"delete this desktop");
|
|
menu[n].callback(delete_desktop_cb, d);
|
|
n++;
|
|
} else if (!d && !numsticky) {
|
|
init(menu[n],"(empty)");
|
|
menu[n].callback_ = 0;
|
|
menu[n].deactivate();
|
|
n++;
|
|
} else {
|
|
if (d == Desktop::current()) first_on_desk = menu+n;
|
|
for (c = Frame::first; c; c = c->next) {
|
|
if (c->state() == UNMAPPED || c->transient_for()) continue;
|
|
if (c->desktop() == d || (!c->desktop() && d == Desktop::current())) {
|
|
init(menu[n],(char*)c);
|
|
#if FL_MAJOR_VERSION < 2
|
|
init(menu[n],(char*)c);
|
|
menu[n].labeltype(FRAME_LABEL);
|
|
#else
|
|
init(menu[n],c->label());
|
|
#endif
|
|
menu[n].callback(d == Desktop::current() ?
|
|
frame_callback : move_frame_callback, c);
|
|
if (d == Desktop::current() && is_active_frame(c)) preset = menu+n;
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
menu[n].label(0); n++; // terminator for submenu
|
|
if (!d) break;
|
|
}
|
|
#endif
|
|
|
|
// For ALT+Tab, move the selection forward or backward:
|
|
if (tab > 0 && first_on_desk) {
|
|
if (!preset)
|
|
preset = first_on_desk;
|
|
else {
|
|
preset++;
|
|
if (!preset->label() || preset->callback_ != frame_callback)
|
|
preset = first_on_desk;
|
|
}
|
|
} else if (tab < 0 && first_on_desk) {
|
|
if (preset && preset != first_on_desk)
|
|
preset--;
|
|
else {
|
|
// go to end of menu
|
|
preset = first_on_desk;
|
|
while (preset[1].label() && preset[1].callback_ == frame_callback)
|
|
preset++;
|
|
}
|
|
}
|
|
|
|
#if WMX_MENU_ITEMS
|
|
// put wmx-style commands above that:
|
|
if (num_wmx > 0) {
|
|
char* cmd;
|
|
int pathlen[MAX_NESTING_DEPTH];
|
|
int level = 0;
|
|
pathlen[0] = wmx_pathlen;
|
|
for (int i = 0; i < num_wmx; i++) {
|
|
cmd = wmxlist[i]+1; // skip level number
|
|
init(menu[n], cmd+pathlen[level]);
|
|
menu[n].callback(spawn_cb, cmd);
|
|
#if FL_MAJOR_VERSION < 2
|
|
#if DESKTOPS
|
|
if (one_desktop)
|
|
#endif
|
|
if (!level)
|
|
menu[n].labeltype(TEXT_LABEL);
|
|
#endif
|
|
int nextlev = (i==num_wmx-1) ? 0 : wmxlist[i+1][0];
|
|
if (nextlev < level) {
|
|
// add null terminators to turn off levels
|
|
for (; level>nextlev; level--)
|
|
init(menu[++n], 0);
|
|
} else if (nextlev > level) {
|
|
// This should be made a submenu
|
|
pathlen[++level] = strlen(cmd)+1; // extra for next trailing /
|
|
menu[n].flags = FL_SUBMENU;
|
|
menu[n].callback((Fl_Callback*)0);
|
|
}
|
|
n++;
|
|
}
|
|
}
|
|
|
|
// put the fixed menu items at the bottom:
|
|
#if XTERM_MENU_ITEM
|
|
if (num_wmx) // if wmx commands, delete the built-in xterm item:
|
|
memcpy(menu+n, other_menu_items+1, sizeof(other_menu_items)-sizeof(Fl_Menu_Item));
|
|
else
|
|
#endif
|
|
#endif
|
|
memcpy(menu+n, other_menu_items, sizeof(other_menu_items));
|
|
#if FL_MAJOR_VERSION < 2
|
|
#if DESKTOPS
|
|
if (one_desktop)
|
|
#endif
|
|
// fix the menus items so they are indented to align with window names:
|
|
while (menu[n].label()) menu[n++].labeltype(TEXT_LABEL);
|
|
#endif
|
|
|
|
const Fl_Menu_Item* picked =
|
|
menu->popup(Fl::event_x(), Fl::event_y(), 0, preset);
|
|
#if FL_MAJOR_VERSION < 2
|
|
if (picked && picked->callback()) picked->do_callback(0);
|
|
#endif
|
|
}
|
|
|
|
void ShowMenu() {ShowTabMenu(0);}
|