Merging icons branch on master branch.
And adjusting the geometry of items.
This commit is contained in:
parent
f8ffe0b2e4
commit
33376f5420
20
README
20
README
|
@ -11,6 +11,15 @@ The -w (windowed) option was removed from the master branch. It was too
|
||||||
buggy in tiled window managers and required more code to be maintained.
|
buggy in tiled window managers and required more code to be maintained.
|
||||||
|
|
||||||
|
|
||||||
|
§ Features
|
||||||
|
|
||||||
|
XMenu comes with the following features:
|
||||||
|
• XMenu reads something in and prints something out, the UNIX way.
|
||||||
|
• Submenus (some menu entries can spawn another menu).
|
||||||
|
• Separators (menu entries can be separated by a line).
|
||||||
|
• Icons (menu entries can follow by an icon image).
|
||||||
|
|
||||||
|
|
||||||
§ Files
|
§ Files
|
||||||
|
|
||||||
The files are:
|
The files are:
|
||||||
|
@ -22,21 +31,14 @@ The files are:
|
||||||
• ./xmenu.1: The manual file (man page) for XMenu.
|
• ./xmenu.1: The manual file (man page) for XMenu.
|
||||||
• ./xmenu.c: The source code of XMenu.
|
• ./xmenu.c: The source code of XMenu.
|
||||||
• ./xmenu.sh: A sample script illustrating how to use XMenu.
|
• ./xmenu.sh: A sample script illustrating how to use XMenu.
|
||||||
|
• ./icons/: Icons for the sample script
|
||||||
|
|
||||||
§ Branches
|
|
||||||
|
|
||||||
There are other branches in this git repository that adds novel
|
|
||||||
functionalities to XMenu.
|
|
||||||
|
|
||||||
• icons: Add suport to image icons before menu entries.
|
|
||||||
|
|
||||||
|
|
||||||
§ Installation
|
§ Installation
|
||||||
|
|
||||||
First, edit ./config.mk to match your local setup.
|
First, edit ./config.mk to match your local setup.
|
||||||
|
|
||||||
In order to build XMenu you need the Xlib and the Xft header files.
|
In order to build XMenu you need the Imlib2, Xlib and Xft header files.
|
||||||
The default configuration for XMenu is specified in the file config.h,
|
The default configuration for XMenu is specified in the file config.h,
|
||||||
you can edit it, but most configuration can be changed at runtime via
|
you can edit it, but most configuration can be changed at runtime via
|
||||||
X resources. Enter the following command to build XMenu. This command
|
X resources. Enter the following command to build XMenu. This command
|
||||||
|
|
|
@ -9,13 +9,12 @@ X11INC = /usr/X11R6/include
|
||||||
X11LIB = /usr/X11R6/lib
|
X11LIB = /usr/X11R6/lib
|
||||||
|
|
||||||
FREETYPEINC = /usr/include/freetype2
|
FREETYPEINC = /usr/include/freetype2
|
||||||
FREETYPELIB = -lfontconfig -lXft
|
|
||||||
# OpenBSD (uncomment)
|
# OpenBSD (uncomment)
|
||||||
#FREETYPEINC = $(X11INC)/freetype2
|
#FREETYPEINC = ${X11INC}/freetype2
|
||||||
|
|
||||||
# includes and libs
|
# includes and libs
|
||||||
INCS = -I${X11INC} -I${FREETYPEINC}
|
INCS = -I/usr/local/include -I${X11INC} -I${FREETYPEINC}
|
||||||
LIBS = -L${X11LIB} -L${FREETYPELIB} -lX11
|
LIBS = -L/usr/local/lib -L${X11LIB} -lfontconfig -lXft -lX11 -lImlib2
|
||||||
|
|
||||||
# flags
|
# flags
|
||||||
CPPFLAGS =
|
CPPFLAGS =
|
||||||
|
|
10
xmenu.1
10
xmenu.1
|
@ -13,17 +13,21 @@ and outputs the item selected to stdout.
|
||||||
Each item read from stdin has the following format:
|
Each item read from stdin has the following format:
|
||||||
.IP
|
.IP
|
||||||
.EX
|
.EX
|
||||||
ITEM := [TABS] [LABEL [TABS OUTPUT]] NEWLINE
|
ITEM := [TABS] [[IMAGE TABS] LABEL [TABS OUTPUT]] NEWLINE
|
||||||
.EE
|
.EE
|
||||||
.PP
|
.PP
|
||||||
That means that each item is composed by
|
That means that each item is composed by
|
||||||
tabs, followed by a label, followed by more tabs, followed by an output,
|
tabs, followed by an optional image specification, followed by tabs
|
||||||
|
followed by a label, followed by more tabs, followed by an output,
|
||||||
and ended by a newline. Brackets group optional elements.
|
and ended by a newline. Brackets group optional elements.
|
||||||
.IP
|
.IP
|
||||||
The initial tabs indicate the menu hierarchy:
|
The initial tabs indicate the menu hierarchy:
|
||||||
items indented with a tab is shown in a submenu of the preceding item not indented.
|
items indented with a tab is shown in a submenu of the preceding item not indented.
|
||||||
An item without initial tabs is a top-level item.
|
An item without initial tabs is a top-level item.
|
||||||
.IP
|
.IP
|
||||||
|
The image is a string of the form "IMG:/path/to/image.png".
|
||||||
|
It specifies a image to be shown as icon at the left of the entry.
|
||||||
|
.IP
|
||||||
The label is the string that will be shown as a item in the menu.
|
The label is the string that will be shown as a item in the menu.
|
||||||
An item without label is considered a separator and is drawn as a thin line in the menu
|
An item without label is considered a separator and is drawn as a thin line in the menu
|
||||||
separating the item above from the item below.
|
separating the item above from the item below.
|
||||||
|
@ -104,7 +108,7 @@ creating a command to be run by the shell.
|
||||||
|
|
||||||
cat <<EOF | xmenu | sh &
|
cat <<EOF | xmenu | sh &
|
||||||
Applications
|
Applications
|
||||||
Web Browser firefox
|
IMG:./web.png Web Browser firefox
|
||||||
Image editor gimp
|
Image editor gimp
|
||||||
Terminal (xterm) xterm
|
Terminal (xterm) xterm
|
||||||
Terminal (urxvt) urxvt
|
Terminal (urxvt) urxvt
|
||||||
|
|
91
xmenu.c
91
xmenu.c
|
@ -8,10 +8,12 @@
|
||||||
#include <X11/Xresource.h>
|
#include <X11/Xresource.h>
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
#include <X11/Xft/Xft.h>
|
#include <X11/Xft/Xft.h>
|
||||||
|
#include <Imlib2.h>
|
||||||
|
|
||||||
#define PROGNAME "xmenu"
|
#define PROGNAME "xmenu"
|
||||||
#define ITEMPREV 0
|
#define ITEMPREV 0
|
||||||
#define ITEMNEXT 1
|
#define ITEMNEXT 1
|
||||||
|
#define IMGPADDING 8
|
||||||
|
|
||||||
/* macros */
|
/* macros */
|
||||||
#define LEN(x) (sizeof (x) / sizeof (x[0]))
|
#define LEN(x) (sizeof (x) / sizeof (x[0]))
|
||||||
|
@ -45,12 +47,14 @@ struct Geometry {
|
||||||
struct Item {
|
struct Item {
|
||||||
char *label; /* string to be drawed on menu */
|
char *label; /* string to be drawed on menu */
|
||||||
char *output; /* string to be outputed when item is clicked */
|
char *output; /* string to be outputed when item is clicked */
|
||||||
|
char *file; /* filename of the image */
|
||||||
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 *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 */
|
||||||
|
Imlib_Image image;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* menu structure */
|
/* menu structure */
|
||||||
|
@ -71,9 +75,9 @@ static void getresources(void);
|
||||||
static void getcolor(const char *s, XftColor *color);
|
static void getcolor(const char *s, XftColor *color);
|
||||||
static void setupdc(void);
|
static void setupdc(void);
|
||||||
static void calcgeom(struct Geometry *geom);
|
static void calcgeom(struct Geometry *geom);
|
||||||
static struct Item *allocitem(const char *label, const char *output);
|
static struct Item *allocitem(const char *label, const char *output, char *file);
|
||||||
static struct Menu *allocmenu(struct Menu *parent, struct Item *list, unsigned level);
|
static struct Menu *allocmenu(struct Menu *parent, struct Item *list, unsigned level);
|
||||||
static struct Menu *buildmenutree(unsigned level, const char *label, const char *output);
|
static struct Menu *buildmenutree(unsigned level, const char *label, const char *output, char *file);
|
||||||
static struct Menu *parsestdin(void);
|
static struct Menu *parsestdin(void);
|
||||||
static void setupmenusize(struct Geometry *geom, struct Menu *menu);
|
static void setupmenusize(struct Geometry *geom, struct Menu *menu);
|
||||||
static void setupmenupos(struct Geometry *geom, struct Menu *menu);
|
static void setupmenupos(struct Geometry *geom, struct Menu *menu);
|
||||||
|
@ -131,6 +135,13 @@ main(int argc, char *argv[])
|
||||||
rootwin = RootWindow(dpy, screen);
|
rootwin = RootWindow(dpy, screen);
|
||||||
colormap = DefaultColormap(dpy, screen);
|
colormap = DefaultColormap(dpy, screen);
|
||||||
|
|
||||||
|
/* imlib2 stuff */
|
||||||
|
imlib_set_cache_size(2048 * 1024);
|
||||||
|
imlib_context_set_dither(1);
|
||||||
|
imlib_context_set_display(dpy);
|
||||||
|
imlib_context_set_visual(visual);
|
||||||
|
imlib_context_set_colormap(colormap);
|
||||||
|
|
||||||
/* setup */
|
/* setup */
|
||||||
getresources();
|
getresources();
|
||||||
setupdc();
|
setupdc();
|
||||||
|
@ -249,7 +260,7 @@ calcgeom(struct Geometry *geom)
|
||||||
|
|
||||||
/* allocate an item */
|
/* allocate an item */
|
||||||
static struct Item *
|
static struct Item *
|
||||||
allocitem(const char *label, const char *output)
|
allocitem(const char *label, const char *output, char *file)
|
||||||
{
|
{
|
||||||
struct Item *item;
|
struct Item *item;
|
||||||
|
|
||||||
|
@ -268,6 +279,12 @@ allocitem(const char *label, const char *output)
|
||||||
err(1, "strdup");
|
err(1, "strdup");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (file == NULL) {
|
||||||
|
item->file = NULL;
|
||||||
|
} else {
|
||||||
|
if ((item->file = strdup(file)) == NULL)
|
||||||
|
err(1, "strdup");
|
||||||
|
}
|
||||||
item->y = 0;
|
item->y = 0;
|
||||||
item->h = 0;
|
item->h = 0;
|
||||||
if (item->label == NULL)
|
if (item->label == NULL)
|
||||||
|
@ -276,6 +293,7 @@ allocitem(const char *label, const char *output)
|
||||||
item->labellen = strlen(item->label);
|
item->labellen = strlen(item->label);
|
||||||
item->next = NULL;
|
item->next = NULL;
|
||||||
item->submenu = NULL;
|
item->submenu = NULL;
|
||||||
|
item->image = NULL;
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
@ -316,7 +334,7 @@ allocmenu(struct Menu *parent, struct Item *list, unsigned level)
|
||||||
|
|
||||||
/* build the menu tree */
|
/* build the menu tree */
|
||||||
static struct Menu *
|
static struct Menu *
|
||||||
buildmenutree(unsigned level, const char *label, const char *output)
|
buildmenutree(unsigned level, const char *label, const char *output, char *file)
|
||||||
{
|
{
|
||||||
static struct Menu *prevmenu = NULL; /* menu the previous item was added to */
|
static struct Menu *prevmenu = NULL; /* menu the previous item was added to */
|
||||||
static struct Menu *rootmenu = NULL; /* menu to be returned */
|
static struct Menu *rootmenu = NULL; /* menu to be returned */
|
||||||
|
@ -326,7 +344,7 @@ buildmenutree(unsigned level, const char *label, const char *output)
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
/* create the item */
|
/* create the item */
|
||||||
curritem = allocitem(label, output);
|
curritem = allocitem(label, output, file);
|
||||||
|
|
||||||
/* put the item in the menu tree */
|
/* put the item in the menu tree */
|
||||||
if (prevmenu == NULL) { /* there is no menu yet */
|
if (prevmenu == NULL) { /* there is no menu yet */
|
||||||
|
@ -379,7 +397,7 @@ parsestdin(void)
|
||||||
{
|
{
|
||||||
struct Menu *rootmenu;
|
struct Menu *rootmenu;
|
||||||
char *s, buf[BUFSIZ];
|
char *s, buf[BUFSIZ];
|
||||||
char *label, *output;
|
char *file, *label, *output;
|
||||||
unsigned level = 0;
|
unsigned level = 0;
|
||||||
|
|
||||||
rootmenu = NULL;
|
rootmenu = NULL;
|
||||||
|
@ -392,6 +410,13 @@ parsestdin(void)
|
||||||
s = level + buf;
|
s = level + buf;
|
||||||
label = strtok(s, "\t\n");
|
label = strtok(s, "\t\n");
|
||||||
|
|
||||||
|
/* get the filename */
|
||||||
|
file = NULL;
|
||||||
|
if (label != NULL && strncmp(label, "IMG:", 4) == 0) {
|
||||||
|
file = label + 4;
|
||||||
|
label = strtok(NULL, "\t\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* get the output */
|
/* get the output */
|
||||||
output = strtok(NULL, "\n");
|
output = strtok(NULL, "\n");
|
||||||
if (output == NULL) {
|
if (output == NULL) {
|
||||||
|
@ -401,12 +426,36 @@ parsestdin(void)
|
||||||
output++;
|
output++;
|
||||||
}
|
}
|
||||||
|
|
||||||
rootmenu = buildmenutree(level, label, output);
|
rootmenu = buildmenutree(level, label, output, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rootmenu;
|
return rootmenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* load and scale image */
|
||||||
|
static Imlib_Image
|
||||||
|
loadimage(const char *file, int size)
|
||||||
|
{
|
||||||
|
Imlib_Image image;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int imgsize;
|
||||||
|
|
||||||
|
image = imlib_load_image(file);
|
||||||
|
if (image == NULL)
|
||||||
|
errx(1, "cannot load image %s", file);
|
||||||
|
|
||||||
|
imlib_context_set_image(image);
|
||||||
|
|
||||||
|
width = imlib_image_get_width();
|
||||||
|
height = imlib_image_get_height();
|
||||||
|
imgsize = MIN(width, height);
|
||||||
|
|
||||||
|
image = imlib_create_cropped_scaled_image(0, 0, imgsize, imgsize, size, size);
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
/* setup the size of a menu and the position of its items */
|
/* setup the size of a menu and the position of its items */
|
||||||
static void
|
static void
|
||||||
setupmenusize(struct Geometry *geom, struct Menu *menu)
|
setupmenusize(struct Geometry *geom, struct Menu *menu)
|
||||||
|
@ -428,8 +477,12 @@ setupmenusize(struct Geometry *geom, struct Menu *menu)
|
||||||
/* get length of item->label rendered in the font */
|
/* get length of item->label rendered in the font */
|
||||||
XftTextExtentsUtf8(dpy, dc.font, (XftChar8 *)item->label,
|
XftTextExtentsUtf8(dpy, dc.font, (XftChar8 *)item->label,
|
||||||
item->labellen, &ext);
|
item->labellen, &ext);
|
||||||
labelwidth = ext.xOff + dc.font->height * 2;
|
labelwidth = ext.xOff + dc.font->height * 2 + IMGPADDING * 2;
|
||||||
menu->w = MAX(menu->w, labelwidth);
|
menu->w = MAX(menu->w, labelwidth);
|
||||||
|
|
||||||
|
/* create image */
|
||||||
|
if (item->file != NULL)
|
||||||
|
item->image = loadimage(item->file, dc.font->height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,7 +692,7 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color)
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
x = dc.font->height;
|
x = dc.font->height + IMGPADDING;
|
||||||
y = item->y + item->h/2 + dc.font->ascent/2 - 1;
|
y = item->y + item->h/2 + dc.font->ascent/2 - 1;
|
||||||
XSetForeground(dpy, dc.gc, color[ColorFG].pixel);
|
XSetForeground(dpy, dc.gc, color[ColorFG].pixel);
|
||||||
XftDrawStringUtf8(menu->draw, &color[ColorFG], dc.font,
|
XftDrawStringUtf8(menu->draw, &color[ColorFG], dc.font,
|
||||||
|
@ -647,7 +700,7 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color)
|
||||||
|
|
||||||
/* draw triangle, if item contains a submenu */
|
/* draw triangle, if item contains a submenu */
|
||||||
if (item->submenu != NULL) {
|
if (item->submenu != NULL) {
|
||||||
x = menu->w - dc.font->height/2 - triangle_width/2;
|
x = menu->w - dc.font->height/2 - IMGPADDING/2 - triangle_width/2 - 1;
|
||||||
y = item->y + item->h/2 - triangle_height/2 - 1;
|
y = item->y + item->h/2 - triangle_height/2 - 1;
|
||||||
|
|
||||||
XPoint triangle[] = {
|
XPoint triangle[] = {
|
||||||
|
@ -660,6 +713,15 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color)
|
||||||
XFillPolygon(dpy, menu->pixmap, dc.gc, triangle, LEN(triangle),
|
XFillPolygon(dpy, menu->pixmap, dc.gc, triangle, LEN(triangle),
|
||||||
Convex, CoordModeOrigin);
|
Convex, CoordModeOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* draw image */
|
||||||
|
if (item->file != NULL) {
|
||||||
|
x = IMGPADDING / 2;
|
||||||
|
y = item->y + (item->h - dc.font->height) / 2;
|
||||||
|
imlib_context_set_drawable(menu->pixmap);
|
||||||
|
imlib_context_set_image(item->image);
|
||||||
|
imlib_render_image_on_drawable(x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* draw items of the current menu and of its ancestors */
|
/* draw items of the current menu and of its ancestors */
|
||||||
|
@ -845,10 +907,17 @@ freemenu(struct Menu *menu)
|
||||||
if (item->submenu != NULL)
|
if (item->submenu != NULL)
|
||||||
freemenu(item->submenu);
|
freemenu(item->submenu);
|
||||||
tmp = item;
|
tmp = item;
|
||||||
item = item->next;
|
|
||||||
if (tmp->label != tmp->output)
|
if (tmp->label != tmp->output)
|
||||||
free(tmp->label);
|
free(tmp->label);
|
||||||
free(tmp->output);
|
free(tmp->output);
|
||||||
|
if (tmp->file != NULL) {
|
||||||
|
free(tmp->file);
|
||||||
|
if (tmp->image != NULL) {
|
||||||
|
imlib_context_set_image(tmp->image);
|
||||||
|
imlib_free_image();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item = item->next;
|
||||||
free(tmp);
|
free(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
xmenu.sh
4
xmenu.sh
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
cat <<EOF | xmenu | sh &
|
cat <<EOF | xmenu | sh &
|
||||||
Applications
|
Applications
|
||||||
Web Browser firefox
|
IMG:./icons/web.png Web Browser firefox
|
||||||
Image editor gimp
|
IMG:./icons/gimp.png Image editor gimp
|
||||||
Terminal (xterm) xterm
|
Terminal (xterm) xterm
|
||||||
Terminal (urxvt) urxvt
|
Terminal (urxvt) urxvt
|
||||||
Terminal (st) st
|
Terminal (st) st
|
||||||
|
|
Loading…
Reference in New Issue
Block a user