diff --git a/config.h b/config.h index 27e9c11..d6a8807 100644 --- a/config.h +++ b/config.h @@ -17,12 +17,18 @@ static struct Config config = { .separator_pixels = 3, /* space around separator */ .gap_pixels = 0, /* gap between menus */ - /* the variables below cannot be set by X resources */ + /* + * The variables below cannot be set by X resources. + * Their values must be less than .height_pixels. + */ /* geometry of the right-pointing isoceles triangle for submenus */ .triangle_width = 3, .triangle_height = 7, - /* padding of the area around the icon */ - .iconpadding = 4, + /* the icon size is equal to .height_pixels - .iconpadding * 2 */ + .iconpadding = 2, + + /* area around the icon, the triangle and the separator */ + .horzpadding = 8, }; diff --git a/xmenu.1 b/xmenu.1 index 470b251..73a95f6 100644 --- a/xmenu.1 +++ b/xmenu.1 @@ -3,7 +3,7 @@ xmenu \- menu utility for X .SH SYNOPSIS .B xmenu -.RB [ \-w ] +.RB [ \-iw ] .RI [ title ] .SH DESCRIPTION .B xmenu @@ -14,9 +14,19 @@ and outputs the item selected to stdout. .PP The options are as follows: .TP +.B -i +Disable icons. +.B xmenu +allocates a space at the left side of the menu for the icons; +if there is no icon, then this space will be blank. +Setting the +.B -i +option removes this space, making the menu narrower. +.TP .B -w Asks the window manager to draw a border around the menus. -This option may be buggy in some window managers, specially tiled ones. +This option may be buggy in some window managers, +specially tiled ones that do not respect window hints. .PP Each item read from stdin has the following format: .IP diff --git a/xmenu.c b/xmenu.c index 92b1581..af0f801 100644 --- a/xmenu.c +++ b/xmenu.c @@ -21,7 +21,7 @@ static void ealloccolor(const char *s, XftColor *color); static void initresources(void); static void initdc(void); -static void initscreengeom(void); +static void initconfig(void); static void initatoms(void); /* structure builders, and their helper routines */ @@ -31,10 +31,10 @@ static struct Menu *buildmenutree(unsigned level, const char *label, const char static struct Menu *parsestdin(void); /* image loader */ -static Imlib_Image loadicon(const char *file, int size); +static Imlib_Image loadicon(const char *file); /* structure setters, and their helper routines */ -static void setupmenusize(struct Menu *menu); +static void setupitems(struct Menu *menu); static void setupmenupos(struct Menu *menu); static void setupmenu(struct Menu *menu, XClassHint *classh); @@ -79,6 +79,7 @@ static Atom netatom[NetLast]; /* flags */ static int wflag = 0; /* whether to let the window manager control XMenu */ +static int iflag = 0; /* whether to disable icons */ /* include config variable */ #include "config.h" @@ -96,8 +97,11 @@ main(int argc, char *argv[]) XClassHint classh; int ch; - while ((ch = getopt(argc, argv, "w")) != -1) { + while ((ch = getopt(argc, argv, "iw")) != -1) { switch (ch) { + case 'i': + iflag = 1; + break; case 'w': wflag = 1; break; @@ -121,16 +125,18 @@ main(int argc, char *argv[]) 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); + if (!iflag) { + 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); + } /* initializers */ initresources(); initdc(); - initscreengeom(); + initconfig(); initatoms(); /* set window class */ @@ -239,9 +245,9 @@ initdc(void) dc.gc = XCreateGC(dpy, rootwin, 0, NULL); } -/* calculate screen geometry */ +/* calculate configuration values that are not set manually */ static void -initscreengeom(void) +initconfig(void) { Window dw; /* dummy variable */ int di; /* dummy variable */ @@ -250,6 +256,7 @@ initscreengeom(void) XQueryPointer(dpy, rootwin, &dw, &dw, &config.cursx, &config.cursy, &di, &di, &du); config.screenw = DisplayWidth(dpy, screen); config.screenh = DisplayHeight(dpy, screen); + config.iconsize = config.height_pixels - config.iconpadding * 2; } /* intern atoms */ @@ -441,7 +448,7 @@ parsestdin(void) /* load and scale icon */ static Imlib_Image -loadicon(const char *file, int size) +loadicon(const char *file) { Imlib_Image icon; int width; @@ -458,18 +465,20 @@ loadicon(const char *file, int size) height = imlib_image_get_height(); imgsize = MIN(width, height); - icon = imlib_create_cropped_scaled_image(0, 0, imgsize, imgsize, size, size); + icon = imlib_create_cropped_scaled_image(0, 0, imgsize, imgsize, + config.iconsize, + config.iconsize); return icon; } -/* setup the size of a menu and the position of its items */ +/* setup the height, width and icon of the items of a menu */ static void -setupmenusize(struct Menu *menu) +setupitems(struct Menu *menu) { XGlyphInfo ext; struct Item *item; - int labelwidth; + int itemwidth; menu->w = config.width_pixels; for (item = menu->list; item != NULL; item = item->next) { @@ -485,13 +494,25 @@ setupmenusize(struct Menu *menu) XftTextExtentsUtf8(dpy, dc.font, (XftChar8 *)item->label, item->labellen, &ext); - /* set menu width */ - labelwidth = ext.xOff + item->h * 2; - menu->w = MAX(menu->w, labelwidth); + /* + * set menu width + * + * the item width depends on the size of its label (ext.xOff), + * and it is only used to calculate the width of the menu (which + * is equal to the width of the largest item). + * + * the horizontal padding appears 4 times through the width of a + * item: before and after its icon, and before and after its triangle + * if the iflag is set (icons are disabled) then the horizontal + * padding appears before the label and around the triangle. + */ + itemwidth = ext.xOff + config.triangle_width + config.horzpadding * 3; + itemwidth += (iflag) ? 0 : config.iconsize + config.horzpadding; + menu->w = MAX(menu->w, itemwidth); /* create icon */ - if (item->file != NULL) - item->icon = loadicon(item->file, item->h - config.iconpadding * 2); + if (item->file != NULL && !iflag) + item->icon = loadicon(item->file); } } @@ -539,7 +560,7 @@ setupmenu(struct Menu *menu, XClassHint *classh) XTextProperty wintitle; /* setup size and position of menus */ - setupmenusize(menu); + setupitems(menu); setupmenupos(menu); /* update menu geometry */ @@ -685,7 +706,8 @@ drawseparator(struct Menu *menu, struct Item *item) y = item->y + item->h/2; XSetForeground(dpy, dc.gc, dc.separator.pixel); - XDrawLine(dpy, menu->pixmap, dc.gc, 0, y, menu->w, y); + XDrawLine(dpy, menu->pixmap, dc.gc, config.horzpadding, y, + menu->w - config.horzpadding, y); } /* draw regular item */ @@ -694,7 +716,8 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color) { int x, y; - x = item->h; + x = config.horzpadding; + x += (iflag) ? 0 : config.horzpadding + config.iconsize; y = item->y + (item->h + dc.font->ascent) / 2; XSetForeground(dpy, dc.gc, color[ColorFG].pixel); XftDrawStringUtf8(menu->draw, &color[ColorFG], dc.font, @@ -702,7 +725,7 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color) /* draw triangle, if item contains a submenu */ if (item->submenu != NULL) { - x = menu->w - (item->h + config.triangle_width + 1) / 2; + x = menu->w - config.triangle_width - config.horzpadding; y = item->y + (item->h - config.triangle_height + 1) / 2; XPoint triangle[] = { @@ -717,8 +740,8 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color) } /* draw icon */ - if (item->file != NULL) { - x = config.iconpadding; + if (item->icon != NULL) { + x = config.horzpadding; y = item->y + config.iconpadding; imlib_context_set_drawable(menu->pixmap); imlib_context_set_image(item->icon); @@ -997,6 +1020,6 @@ cleanup(void) static void usage(void) { - (void)fprintf(stderr, "usage: xmenu [-w] [title]\n"); + (void)fprintf(stderr, "usage: xmenu [-iw] [title]\n"); exit(1); } diff --git a/xmenu.h b/xmenu.h index 11fd29f..b636114 100644 --- a/xmenu.h +++ b/xmenu.h @@ -36,6 +36,9 @@ struct Config { int triangle_height; int iconpadding; + int horzpadding; + + int iconsize; int cursx, cursy; /* cursor position */ int screenw, screenh; /* screen width and height */