Parcourir la source

xmenu now can be operated by keyboard

master
phillbush il y a 4 ans
Parent
révision
858338d978
3 fichiers modifiés avec 129 ajouts et 5 suppressions
  1. +1
    -1
      config.mk
  2. +23
    -1
      xmenu.1
  3. +105
    -3
      xmenu.c

+ 1
- 1
config.mk Voir le fichier

@@ -1,4 +1,4 @@
# progrma name
# program name
PROG = xmenu

# paths


+ 23
- 1
xmenu.1 Voir le fichier

@@ -37,6 +37,28 @@ separating the item above from the item below.
The command is the string that will be output after selecting the item.
.IP
The newline terminates the item specification.
.SH USAGE
.B xmenu
is controlled by the mouse,
but can also be controlled by the keyboard.
Items can be selected using the arrow keys,
Tab (with and without Shift),
Enter and Esc.
.TP
.BR Down ", " Tab
Cycle through the items in the regular direction.
.TP
.BR Up ", " Shift-Tab
Cycle through the items in the reverse direction.
.TP
.BR Right ", " Enter
Select the highlighted item.
.TP
.B Left
Go to the menu above.
.TP
.B Esc
Go to the menu above or exit xmenu.
.SH RESOURCES
.B
xmenu
@@ -83,7 +105,7 @@ The output is redirected to xargs to make a command to be run by the shell.
.EX
#!/bin/sh

cat <<EOF | ./xmenu | xargs sh -c
cat <<EOF | xmenu | xargs sh -c
Applications
Web Browser firefox
Image editor gimp


+ 105
- 3
xmenu.c Voir le fichier

@@ -6,6 +6,10 @@
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/XKBlib.h>

#define ITEMPREV 0
#define ITEMNEXT 1

/* macros */
#define LEN(x) (sizeof (x) / sizeof (x[0]))
@@ -49,6 +53,7 @@ struct Item {
int y; /* item y position relative to menu */
int h; /* item height */
size_t labellen; /* strlen(label) */
struct Item *prev; /* previous item */
struct Item *next; /* next item */
struct Menu *submenu; /* submenu spawned by clicking on item */
};
@@ -248,8 +253,13 @@ setupgeom(void)
static 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 */
@@ -360,6 +370,8 @@ parsestdin(void)
rootmenu = menu;
prevmenu = menu;
count = 1;
curritem->prev = NULL;
curritem->next = NULL;
} else if (level < prevmenu->level) { /* item is continuation of a parent menu*/
for (menu = prevmenu, i = level;
menu != NULL && i < prevmenu->level;
@@ -373,11 +385,19 @@ parsestdin(void)
;

item->next = curritem;

curritem->prev = item;
curritem->next = NULL;

prevmenu = menu;
} else if (level == prevmenu->level) { /* item is a continuation of current menu */
for (item = prevmenu->list; item->next != NULL; item = item->next)
;
item->next = curritem;

curritem->prev = item;
curritem->next = NULL;

} else if (level > prevmenu->level) { /* item begins a new menu */
menu = allocmenu(prevmenu, curritem, level);

@@ -387,6 +407,9 @@ parsestdin(void)
item->submenu = menu;
menu->caller = item;

curritem->prev = NULL;
curritem->next = NULL;

prevmenu = menu;
}
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 */
static void
run(void)
@@ -623,12 +687,14 @@ run(void)
struct Menu *menu;
struct Item *item;
struct Item *previtem = NULL;
KeySym ksym;
XEvent ev;

while (!XNextEvent(dpy, &ev)) {
switch(ev.type) {
case Expose:
drawmenu();
if (ev.xexpose.count == 0)
drawmenu();
break;
case MotionNotify:
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item);
@@ -649,6 +715,7 @@ run(void)
case ButtonRelease:
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item);
if (menu != NULL && item != NULL) {
selectitem:
if (item->label == NULL)
break; /* ignore separators */
if (item->submenu != NULL) {
@@ -657,10 +724,45 @@ run(void)
printf("%s\n", item->output);
return;
}
currmenu->selected = currmenu->list;
drawmenu();
break;
} else {
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;
case LeaveNotify:
currmenu->selected = NULL;


Chargement…
Annuler
Enregistrer