Browse Source

Refactored code, changed resources and config.h

master
phillbush 4 years ago
parent
commit
fd530f3f68
3 changed files with 162 additions and 140 deletions
  1. +20
    -11
      config.h
  2. +4
    -4
      xmenu.1
  3. +138
    -125
      xmenu.c

+ 20
- 11
config.h View File

@@ -1,11 +1,20 @@
static const char *font = "monospace:size=9";
static const char *background = "#FFFFFF";
static const char *foreground = "#2E3436";
static const char *selbackground = "#3584E4";
static const char *selforeground = "#FFFFFF";
static const char *separator = "#CDC7C2";
static const char *border = "#E6E6E6";
static int width = 130;
static int itemborder = 4;
static int menuborder = 1;
static int separatorsize = 1;
/* font */
static const char *font = "monospace:size=9"; /* for regular items */

/* colors */
static const char *background_color = "#FFFFFF";
static const char *foreground_color = "#2E3436";
static const char *selbackground_color = "#3584E4";
static const char *selforeground_color = "#FFFFFF";
static const char *separator_color = "#CDC7C2";
static const char *border_color = "#E6E6E6";

/* sizes in pixels */
static int width_pixels = 130; /* minimum width of a menu */
static int padding_pixels = 4; /* padding around label in a item */
static int border_pixels = 1; /* menu border */
static int separator_pixels = 3; /* space around separator */

/* geometry of the right-pointing isoceles triangle for submenus */
static const int triangle_width = 3;
static const int triangle_height = 7;

+ 4
- 4
xmenu.1 View File

@@ -94,13 +94,13 @@ The color of the separator between itens in the menu.
.B xmenu.width .B xmenu.width
The minimum width, in pixels, of the items in the menu. The minimum width, in pixels, of the items in the menu.
.TP .TP
.B xmenu.itemborder
The size in pixels of the border around the label text in items in the menu.
.B xmenu.padding
The size in pixels of the padding around the label text in items in the menu.
.TP .TP
.B xmenu.menuborder
.B xmenu.borderWidth
The size in pixels of the border around the menu. The size in pixels of the border around the menu.
.TP .TP
.B xmenu.separatorsize
.B xmenu.separatorWidth
The size in pixels of the item separator. The size in pixels of the item separator.


.SH EXAMPLES .SH EXAMPLES


+ 138
- 125
xmenu.c View File

@@ -25,7 +25,8 @@ enum {ColorFG, ColorBG, ColorLast};
struct DC { struct DC {
XftColor normal[ColorLast]; XftColor normal[ColorLast];
XftColor selected[ColorLast]; XftColor selected[ColorLast];
XftColor decoration[ColorLast];
XftColor border;
XftColor separator;


Drawable d; Drawable d;
GC gc; GC gc;
@@ -33,7 +34,7 @@ struct DC {
}; };


/* menu geometry structure */ /* menu geometry structure */
struct Geometry {
struct MenuGeometry {
int itemb; /* item border */ int itemb; /* item border */
int itemw; /* item width */ int itemw; /* item width */
int itemh; /* item height */ int itemh; /* item height */
@@ -80,6 +81,8 @@ static void setupgeom(void);
static struct Item *allocitem(const char *label, const char *output); static struct Item *allocitem(const char *label, const char *output);
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 void getmenuitem(Window win, int y, struct Menu **menu_ret, struct Item **item_ret); static void getmenuitem(Window win, int y, struct Menu **menu_ret, struct Item **item_ret);
static void drawseparator(struct Menu *menu, struct Item *item);
static void drawitem(struct Menu *menu, struct Item *item, XftColor *color);
static void drawmenu(void); static void drawmenu(void);
static void calcscreengeom(void); static void calcscreengeom(void);
static void calcmenu(struct Menu *menu); static void calcmenu(struct Menu *menu);
@@ -99,16 +102,14 @@ static Visual *visual;
static Window rootwin; static Window rootwin;
static int screen; static int screen;
static struct DC dc; static struct DC dc;
static struct ScreenGeometry screengeom;


/* menu variables */ /* menu variables */
static struct Menu *rootmenu = NULL; static struct Menu *rootmenu = NULL;
static struct Menu *currmenu = NULL; static struct Menu *currmenu = NULL;
static char **menutitle; static char **menutitle;
static int menutitlecount; static int menutitlecount;

/* geometry variables */
static struct Geometry geom;
static struct ScreenGeometry screengeom;
static struct MenuGeometry geom;


#include "config.h" #include "config.h"


@@ -154,10 +155,6 @@ main(int argc, char *argv[])
grabpointer(); grabpointer();
grabkeyboard(); grabkeyboard();


/* map root menu */
setcurrmenu(rootmenu);
XMapWindow(dpy, rootmenu->win);

/* run event loop */ /* run event loop */
run(); run();


@@ -171,44 +168,44 @@ getresources(void)
{ {
char *xrm; char *xrm;
long n; long n;
char *type;
XrmDatabase xdb;
XrmValue xval;


XrmInitialize(); XrmInitialize();
if ((xrm = XResourceManagerString(dpy))) {
char *type;
XrmDatabase xdb;
XrmValue xval;

xdb = XrmGetStringDatabase(xrm);

if (XrmGetResource(xdb, "xmenu.menuborder", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
menuborder = n;
if (XrmGetResource(xdb, "xmenu.separatorsize", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
separatorsize = n;
if (XrmGetResource(xdb, "xmenu.itemborder", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
itemborder = n;
if (XrmGetResource(xdb, "xmenu.width", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
width = n;
if (XrmGetResource(xdb, "xmenu.background", "*", &type, &xval) == True)
background = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.foreground", "*", &type, &xval) == True)
foreground = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.selbackground", "*", &type, &xval) == True)
selbackground = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.selforeground", "*", &type, &xval) == True)
selforeground = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.separator", "*", &type, &xval) == True)
separator = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.border", "*", &type, &xval) == True)
border = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.font", "*", &type, &xval) == True)
font = strdup(xval.addr);

XrmDestroyDatabase(xdb);
}
if ((xrm = XResourceManagerString(dpy)) == NULL)
return;

xdb = XrmGetStringDatabase(xrm);

if (XrmGetResource(xdb, "xmenu.borderWidth", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
border_pixels = n;
if (XrmGetResource(xdb, "xmenu.separatorWidth", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
separator_pixels = n;
if (XrmGetResource(xdb, "xmenu.padding", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
padding_pixels = n;
if (XrmGetResource(xdb, "xmenu.width", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
width_pixels = n;
if (XrmGetResource(xdb, "xmenu.background", "*", &type, &xval) == True)
background_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.foreground", "*", &type, &xval) == True)
foreground_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.selbackground", "*", &type, &xval) == True)
selbackground_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.selforeground", "*", &type, &xval) == True)
selforeground_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.separator", "*", &type, &xval) == True)
separator_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.border", "*", &type, &xval) == True)
border_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.font", "*", &type, &xval) == True)
font = strdup(xval.addr);

XrmDestroyDatabase(xdb);
} }


/* get color from color string */ /* get color from color string */
@@ -224,18 +221,18 @@ static void
setupdc(void) setupdc(void)
{ {
/* get color pixels */ /* get color pixels */
getcolor(background, &dc.normal[ColorBG]);
getcolor(foreground, &dc.normal[ColorFG]);
getcolor(selbackground, &dc.selected[ColorBG]);
getcolor(selforeground, &dc.selected[ColorFG]);
getcolor(separator, &dc.decoration[ColorBG]);
getcolor(border, &dc.decoration[ColorFG]);
getcolor(background_color, &dc.normal[ColorBG]);
getcolor(foreground_color, &dc.normal[ColorFG]);
getcolor(selbackground_color, &dc.selected[ColorBG]);
getcolor(selforeground_color, &dc.selected[ColorFG]);
getcolor(separator_color, &dc.separator);
getcolor(border_color, &dc.border);


/* try to get font */ /* try to get font */
if ((dc.font = XftFontOpenName(dpy, screen, font)) == NULL) if ((dc.font = XftFontOpenName(dpy, screen, font)) == NULL)
errx(1, "cannot load font"); errx(1, "cannot load font");


/* create GC */
/* create common GC */
dc.gc = XCreateGC(dpy, rootwin, 0, NULL); dc.gc = XCreateGC(dpy, rootwin, 0, NULL);
} }


@@ -243,11 +240,11 @@ setupdc(void)
static void static void
setupgeom(void) setupgeom(void)
{ {
geom.itemb = itemborder;
geom.itemh = dc.font->height + itemborder * 2;
geom.itemw = width;
geom.border = menuborder;
geom.separator = separatorsize;
geom.itemb = padding_pixels;
geom.itemh = dc.font->height + padding_pixels * 2;
geom.itemw = width_pixels;
geom.border = border_pixels;
geom.separator = separator_pixels;
} }


/* allocate an item */ /* allocate an item */
@@ -299,13 +296,15 @@ allocmenu(struct Menu *parent, struct Item *list, unsigned level)
menu->level = level; menu->level = level;


swa.override_redirect = True; swa.override_redirect = True;
swa.background_pixel = dc.decoration[ColorBG].pixel;
swa.border_pixel = dc.decoration[ColorFG].pixel;
swa.background_pixel = dc.normal[ColorBG].pixel;
swa.border_pixel = dc.border.pixel;
swa.save_under = True; /* pop-up windows should save_under*/
swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask
| PointerMotionMask | LeaveWindowMask; | PointerMotionMask | LeaveWindowMask;
menu->win = XCreateWindow(dpy, rootwin, 0, 0, geom.itemw, geom.itemh, geom.border, menu->win = XCreateWindow(dpy, rootwin, 0, 0, geom.itemw, geom.itemh, geom.border,
CopyFromParent, CopyFromParent, CopyFromParent, CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWEventMask,
CWOverrideRedirect | CWBackPixel |
CWBorderPixel | CWEventMask | CWSaveUnder,
&swa); &swa);


return menu; return menu;
@@ -573,6 +572,7 @@ setcurrmenu(struct Menu *currmenu_new)
/* if there was no currmenu, skip calculations */ /* if there was no currmenu, skip calculations */
if (currmenu == NULL) { if (currmenu == NULL) {
currmenu = currmenu_new; currmenu = currmenu_new;
XMapWindow(dpy, currmenu->win);
return; return;
} }


@@ -607,9 +607,49 @@ setcurrmenu(struct Menu *currmenu_new)
item = NULL; item = NULL;
for (menu = currmenu; menu != lcamenu; menu = menu->parent) { for (menu = currmenu; menu != lcamenu; menu = menu->parent) {
XMapWindow(dpy, menu->win); XMapWindow(dpy, menu->win);
if (item != NULL)
menu->selected = item;
item = menu->caller;
}
}

/* draw separator item */
static void
drawseparator(struct Menu *menu, struct Item *item)
{
int linex, liney, linew;

linex = dc.font->height;
liney = item->y + item->h/2;
linew = menu->w - dc.font->height;

XSetForeground(dpy, dc.gc, dc.separator.pixel);
XDrawLine(dpy, menu->pixmap, dc.gc, linex, liney, linew, liney);
}

/* draw regular item */
static void
drawitem(struct Menu *menu, struct Item *item, XftColor *color)
{
int x, y;

x = 0 + dc.font->height;
y = item->y + dc.font->height + geom.itemb / 2;
XSetForeground(dpy, dc.gc, color[ColorFG].pixel);
XftDrawStringUtf8(menu->draw, &color[ColorFG], dc.font,
x, y, item->label, item->labellen);

/* draw triangle, if item contains a submenu */
if (item->submenu != NULL) {
x = menu->w - dc.font->height + geom.itemb - 1;
y = item->y + geom.itemh/2 - triangle_height/2 - 1;

XPoint triangle[] = {
{x, y},
{x + triangle_width, y + triangle_height/2},
{x, y + triangle_height},
{x, y}
};

XFillPolygon(dpy, menu->pixmap, dc.gc, triangle, LEN(triangle),
Convex, CoordModeOrigin);
} }
} }


@@ -623,52 +663,26 @@ drawmenu(void)
for (menu = currmenu; menu != NULL; menu = menu->parent) { for (menu = currmenu; menu != NULL; menu = menu->parent) {
for (item = menu->list; item != NULL; item = item->next) { for (item = menu->list; item != NULL; item = item->next) {
XftColor *color; XftColor *color;
int labelx, labely;


/* determine item color */ /* determine item color */
if (item == menu->selected)
if (item == menu->selected && item->label != NULL)
color = dc.selected; color = dc.selected;
else else
color = dc.normal; color = dc.normal;


/* continue if item is a separator */
if (item->label == NULL)
continue;

/* draw item box */ /* draw item box */
XSetForeground(dpy, dc.gc, color[ColorBG].pixel); XSetForeground(dpy, dc.gc, color[ColorBG].pixel);
XDrawRectangle(dpy, menu->pixmap, dc.gc, 0, item->y,
menu->w, item->h);
XFillRectangle(dpy, menu->pixmap, dc.gc, 0, item->y, XFillRectangle(dpy, menu->pixmap, dc.gc, 0, item->y,
menu->w, item->h); menu->w, item->h);


/* draw item label */
labelx = 0 + dc.font->height;
labely = item->y + dc.font->height + geom.itemb / 2;
XSetForeground(dpy, dc.gc, color[ColorFG].pixel);
XftDrawStringUtf8(menu->draw, &color[ColorFG], dc.font,
labelx, labely, item->label,
item->labellen);

/* draw triangle, if item contains a submenu */
if (item->submenu != NULL) {
int trianglex = menu->w - dc.font->height + geom.itemb - 1;
int triangley = item->y + (3 * item->h)/8 -1;

XPoint triangle[] = {
{trianglex, triangley},
{trianglex + item->h/8 + 1, item->y + item->h/2},
{trianglex, triangley + item->h/4 + 2},
{trianglex, triangley}
};

XFillPolygon(dpy, menu->pixmap, dc.gc, triangle, LEN(triangle),
Convex, CoordModeOrigin);
}

XCopyArea(dpy, menu->pixmap, menu->win, dc.gc, 0, item->y,
menu->w, item->h, 0, item->y);
if (item->label == NULL) /* item is a separator */
drawseparator(menu, item);
else /* item is a regular item */
drawitem(menu, item, color);
} }

XCopyArea(dpy, menu->pixmap, menu->win, dc.gc, 0, 0,
menu->w, menu->h, 0, 0);
} }
} }


@@ -723,6 +737,8 @@ run(void)
KeySym ksym; KeySym ksym;
XEvent ev; XEvent ev;


setcurrmenu(rootmenu);

while (!XNextEvent(dpy, &ev)) { while (!XNextEvent(dpy, &ev)) {
switch(ev.type) { switch(ev.type) {
case Expose: case Expose:
@@ -731,38 +747,34 @@ run(void)
break; break;
case MotionNotify: case MotionNotify:
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item); getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item);
if (menu != NULL && item != NULL) {
if (previtem != item) {
if (item->submenu != NULL)
setcurrmenu(item->submenu);
else
setcurrmenu(menu);
previtem = item;
drawmenu();
} else if (menu->selected != item) {
menu->selected = item;
drawmenu();
}
if (menu == NULL || item == NULL)
break;
if (previtem != item) {
menu->selected = item;
if (item->submenu != NULL)
setcurrmenu(item->submenu);
else
setcurrmenu(menu);
previtem = item;
drawmenu();
} }
break; break;
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) {
selectitem:
if (item->label == NULL)
break; /* ignore separators */
if (item->submenu != NULL) {
setcurrmenu(item->submenu);
} else {
printf("%s\n", item->output);
return;
}
currmenu->selected = currmenu->list;
drawmenu();
if (menu == NULL || item == NULL)
break; break;
selectitem:
if (item->label == NULL)
break; /* ignore separators */
if (item->submenu != NULL) {
setcurrmenu(item->submenu);
} else { } else {
printf("%s\n", item->output);
return; return;
} }
currmenu->selected = currmenu->list;
drawmenu();
break;
case ButtonPress: case ButtonPress:
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)
@@ -798,6 +810,7 @@ selectitem:
drawmenu(); drawmenu();
break; break;
case LeaveNotify: case LeaveNotify:
previtem = NULL;
currmenu->selected = NULL; currmenu->selected = NULL;
drawmenu(); drawmenu();
break; break;
@@ -805,7 +818,7 @@ selectitem:
} }
} }


/* recursivelly free a pixmap */
/* recursivelly free pixmaps and destroy windows */
static void static void
freewindow(struct Menu *menu) freewindow(struct Menu *menu)
{ {
@@ -830,8 +843,8 @@ cleanup(void)
XftColorFree(dpy, visual, colormap, &dc.normal[ColorFG]); XftColorFree(dpy, visual, colormap, &dc.normal[ColorFG]);
XftColorFree(dpy, visual, colormap, &dc.selected[ColorBG]); XftColorFree(dpy, visual, colormap, &dc.selected[ColorBG]);
XftColorFree(dpy, visual, colormap, &dc.selected[ColorFG]); XftColorFree(dpy, visual, colormap, &dc.selected[ColorFG]);
XftColorFree(dpy, visual, colormap, &dc.decoration[ColorBG]);
XftColorFree(dpy, visual, colormap, &dc.decoration[ColorFG]);
XftColorFree(dpy, visual, colormap, &dc.separator);
XftColorFree(dpy, visual, colormap, &dc.border);


XFreeGC(dpy, dc.gc); XFreeGC(dpy, dc.gc);
XCloseDisplay(dpy); XCloseDisplay(dpy);


Loading…
Cancel
Save