|
@@ -6,6 +6,10 @@ |
|
|
#include <X11/Xlib.h> |
|
|
#include <X11/Xlib.h> |
|
|
#include <X11/Xutil.h> |
|
|
#include <X11/Xutil.h> |
|
|
#include <X11/Xresource.h> |
|
|
#include <X11/Xresource.h> |
|
|
|
|
|
#include <X11/XKBlib.h> |
|
|
|
|
|
|
|
|
|
|
|
#define ITEMPREV 0 |
|
|
|
|
|
#define ITEMNEXT 1 |
|
|
|
|
|
|
|
|
/* macros */ |
|
|
/* macros */ |
|
|
#define LEN(x) (sizeof (x) / sizeof (x[0])) |
|
|
#define LEN(x) (sizeof (x) / sizeof (x[0])) |
|
@@ -49,6 +53,7 @@ struct Item { |
|
|
int y; /* item y position relative to menu */ |
|
|
int y; /* item y position relative to menu */ |
|
|
int h; /* item height */ |
|
|
int h; /* item height */ |
|
|
size_t labellen; /* strlen(label) */ |
|
|
size_t labellen; /* strlen(label) */ |
|
|
|
|
|
struct Item *prev; /* previous item */ |
|
|
struct Item *next; /* next item */ |
|
|
struct Item *next; /* next item */ |
|
|
struct Menu *submenu; /* submenu spawned by clicking on item */ |
|
|
struct Menu *submenu; /* submenu spawned by clicking on item */ |
|
|
}; |
|
|
}; |
|
@@ -248,8 +253,13 @@ setupgeom(void) |
|
|
static void |
|
|
static void |
|
|
setupgrab(void) |
|
|
setupgrab(void) |
|
|
{ |
|
|
{ |
|
|
XGrabPointer(dpy, rootwin, True, ButtonPressMask | ButtonReleaseMask, |
|
|
|
|
|
GrabModeAsync, GrabModeAsync, None, None, CurrentTime); |
|
|
|
|
|
|
|
|
if (XGrabPointer(dpy, rootwin, True, ButtonPressMask, |
|
|
|
|
|
GrabModeAsync, GrabModeAsync, None, |
|
|
|
|
|
None, CurrentTime) != GrabSuccess) |
|
|
|
|
|
errx(1, "cannot grab pointer"); |
|
|
|
|
|
if (XGrabKeyboard(dpy, rootwin, True, GrabModeAsync, |
|
|
|
|
|
GrabModeAsync, CurrentTime) != GrabSuccess) |
|
|
|
|
|
errx(1, "cannot grab keyboard"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* allocate an item */ |
|
|
/* allocate an item */ |
|
@@ -360,6 +370,8 @@ parsestdin(void) |
|
|
rootmenu = menu; |
|
|
rootmenu = menu; |
|
|
prevmenu = menu; |
|
|
prevmenu = menu; |
|
|
count = 1; |
|
|
count = 1; |
|
|
|
|
|
curritem->prev = NULL; |
|
|
|
|
|
curritem->next = NULL; |
|
|
} else if (level < prevmenu->level) { /* item is continuation of a parent menu*/ |
|
|
} else if (level < prevmenu->level) { /* item is continuation of a parent menu*/ |
|
|
for (menu = prevmenu, i = level; |
|
|
for (menu = prevmenu, i = level; |
|
|
menu != NULL && i < prevmenu->level; |
|
|
menu != NULL && i < prevmenu->level; |
|
@@ -373,11 +385,19 @@ parsestdin(void) |
|
|
; |
|
|
; |
|
|
|
|
|
|
|
|
item->next = curritem; |
|
|
item->next = curritem; |
|
|
|
|
|
|
|
|
|
|
|
curritem->prev = item; |
|
|
|
|
|
curritem->next = NULL; |
|
|
|
|
|
|
|
|
prevmenu = menu; |
|
|
prevmenu = menu; |
|
|
} else if (level == prevmenu->level) { /* item is a continuation of current menu */ |
|
|
} else if (level == prevmenu->level) { /* item is a continuation of current menu */ |
|
|
for (item = prevmenu->list; item->next != NULL; item = item->next) |
|
|
for (item = prevmenu->list; item->next != NULL; item = item->next) |
|
|
; |
|
|
; |
|
|
item->next = curritem; |
|
|
item->next = curritem; |
|
|
|
|
|
|
|
|
|
|
|
curritem->prev = item; |
|
|
|
|
|
curritem->next = NULL; |
|
|
|
|
|
|
|
|
} else if (level > prevmenu->level) { /* item begins a new menu */ |
|
|
} else if (level > prevmenu->level) { /* item begins a new menu */ |
|
|
menu = allocmenu(prevmenu, curritem, level); |
|
|
menu = allocmenu(prevmenu, curritem, level); |
|
|
|
|
|
|
|
@@ -387,6 +407,9 @@ parsestdin(void) |
|
|
item->submenu = menu; |
|
|
item->submenu = menu; |
|
|
menu->caller = item; |
|
|
menu->caller = item; |
|
|
|
|
|
|
|
|
|
|
|
curritem->prev = NULL; |
|
|
|
|
|
curritem->next = NULL; |
|
|
|
|
|
|
|
|
prevmenu = menu; |
|
|
prevmenu = menu; |
|
|
} |
|
|
} |
|
|
count++; |
|
|
count++; |
|
@@ -616,6 +639,47 @@ drawmenu(void) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* cycle through the items; non-zero direction is next, zero is prev */ |
|
|
|
|
|
static struct Item * |
|
|
|
|
|
itemcycle(int direction) |
|
|
|
|
|
{ |
|
|
|
|
|
struct Item *item; |
|
|
|
|
|
struct Item *lastitem; |
|
|
|
|
|
|
|
|
|
|
|
item = NULL; |
|
|
|
|
|
|
|
|
|
|
|
if (direction == ITEMNEXT) { |
|
|
|
|
|
if (currmenu->selected == NULL) |
|
|
|
|
|
item = currmenu->list; |
|
|
|
|
|
else if (currmenu->selected->next != NULL) |
|
|
|
|
|
item = currmenu->selected->next; |
|
|
|
|
|
|
|
|
|
|
|
while (item != NULL && item->label == NULL) |
|
|
|
|
|
item = item->next; |
|
|
|
|
|
|
|
|
|
|
|
if (item == NULL) |
|
|
|
|
|
item = currmenu->list; |
|
|
|
|
|
} else { |
|
|
|
|
|
for (lastitem = currmenu->list; |
|
|
|
|
|
lastitem != NULL && lastitem->next != NULL; |
|
|
|
|
|
lastitem = lastitem->next) |
|
|
|
|
|
; |
|
|
|
|
|
|
|
|
|
|
|
if (currmenu->selected == NULL) |
|
|
|
|
|
item = lastitem; |
|
|
|
|
|
else if (currmenu->selected->prev != NULL) |
|
|
|
|
|
item = currmenu->selected->prev; |
|
|
|
|
|
|
|
|
|
|
|
while (item != NULL && item->label == NULL) |
|
|
|
|
|
item = item->prev; |
|
|
|
|
|
|
|
|
|
|
|
if (item == NULL) |
|
|
|
|
|
item = lastitem; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return item; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/* run event loop */ |
|
|
/* run event loop */ |
|
|
static void |
|
|
static void |
|
|
run(void) |
|
|
run(void) |
|
@@ -623,12 +687,14 @@ run(void) |
|
|
struct Menu *menu; |
|
|
struct Menu *menu; |
|
|
struct Item *item; |
|
|
struct Item *item; |
|
|
struct Item *previtem = NULL; |
|
|
struct Item *previtem = NULL; |
|
|
|
|
|
KeySym ksym; |
|
|
XEvent ev; |
|
|
XEvent ev; |
|
|
|
|
|
|
|
|
while (!XNextEvent(dpy, &ev)) { |
|
|
while (!XNextEvent(dpy, &ev)) { |
|
|
switch(ev.type) { |
|
|
switch(ev.type) { |
|
|
case Expose: |
|
|
case Expose: |
|
|
drawmenu(); |
|
|
|
|
|
|
|
|
if (ev.xexpose.count == 0) |
|
|
|
|
|
drawmenu(); |
|
|
break; |
|
|
break; |
|
|
case MotionNotify: |
|
|
case MotionNotify: |
|
|
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item); |
|
|
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item); |
|
@@ -649,6 +715,7 @@ run(void) |
|
|
case ButtonRelease: |
|
|
case ButtonRelease: |
|
|
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item); |
|
|
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item); |
|
|
if (menu != NULL && item != NULL) { |
|
|
if (menu != NULL && item != NULL) { |
|
|
|
|
|
selectitem: |
|
|
if (item->label == NULL) |
|
|
if (item->label == NULL) |
|
|
break; /* ignore separators */ |
|
|
break; /* ignore separators */ |
|
|
if (item->submenu != NULL) { |
|
|
if (item->submenu != NULL) { |
|
@@ -657,10 +724,45 @@ run(void) |
|
|
printf("%s\n", item->output); |
|
|
printf("%s\n", item->output); |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
currmenu->selected = currmenu->list; |
|
|
drawmenu(); |
|
|
drawmenu(); |
|
|
|
|
|
break; |
|
|
} else { |
|
|
} else { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
case ButtonPress: |
|
|
|
|
|
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item); |
|
|
|
|
|
if (menu == NULL || item == NULL) |
|
|
|
|
|
return; |
|
|
|
|
|
break; |
|
|
|
|
|
case KeyPress: |
|
|
|
|
|
ksym = XkbKeycodeToKeysym(dpy, ev.xkey.keycode, 0, 0); |
|
|
|
|
|
|
|
|
|
|
|
if (ksym == XK_Escape && currmenu == rootmenu) |
|
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
/* Shift-Tab = ISO_Left_Tab */ |
|
|
|
|
|
if (ksym == XK_Tab && (ev.xkey.state & ShiftMask)) |
|
|
|
|
|
ksym = XK_ISO_Left_Tab; |
|
|
|
|
|
|
|
|
|
|
|
/* cycle through menu */ |
|
|
|
|
|
item = NULL; |
|
|
|
|
|
if (ksym == XK_ISO_Left_Tab || ksym == XK_Up) { |
|
|
|
|
|
item = itemcycle(ITEMPREV); |
|
|
|
|
|
} else if (ksym == XK_Tab || ksym == XK_Down) { |
|
|
|
|
|
item = itemcycle(ITEMNEXT); |
|
|
|
|
|
} else if ((ksym == XK_Return || ksym == XK_Right) && |
|
|
|
|
|
currmenu->selected != NULL) { |
|
|
|
|
|
item = currmenu->selected; |
|
|
|
|
|
goto selectitem; |
|
|
|
|
|
} else if ((ksym == XK_Escape || ksym == XK_Left) && |
|
|
|
|
|
currmenu->parent != NULL) { |
|
|
|
|
|
item = currmenu->parent->selected; |
|
|
|
|
|
setcurrmenu(currmenu->parent); |
|
|
|
|
|
} else |
|
|
|
|
|
break; |
|
|
|
|
|
currmenu->selected = item; |
|
|
|
|
|
drawmenu(); |
|
|
break; |
|
|
break; |
|
|
case LeaveNotify: |
|
|
case LeaveNotify: |
|
|
currmenu->selected = NULL; |
|
|
currmenu->selected = NULL; |
|
|