Refactored code, changed resources and config.h

This commit is contained in:
phillbush 2020-05-26 18:43:45 -03:00
parent 2744390027
commit fd530f3f68
3 changed files with 159 additions and 137 deletions

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;

View File

@ -94,13 +94,13 @@ The color of the separator between itens in the menu.
.B xmenu.width
The minimum width, in pixels, of the items in the menu.
.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
.B xmenu.menuborder
.B xmenu.borderWidth
The size in pixels of the border around the menu.
.TP
.B xmenu.separatorsize
.B xmenu.separatorWidth
The size in pixels of the item separator.
.SH EXAMPLES

193
xmenu.c
View File

@ -25,7 +25,8 @@ enum {ColorFG, ColorBG, ColorLast};
struct DC {
XftColor normal[ColorLast];
XftColor selected[ColorLast];
XftColor decoration[ColorLast];
XftColor border;
XftColor separator;
Drawable d;
GC gc;
@ -33,7 +34,7 @@ struct DC {
};
/* menu geometry structure */
struct Geometry {
struct MenuGeometry {
int itemb; /* item border */
int itemw; /* item width */
int itemh; /* item height */
@ -80,6 +81,8 @@ static void setupgeom(void);
static struct Item *allocitem(const char *label, const char *output);
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 drawseparator(struct Menu *menu, struct Item *item);
static void drawitem(struct Menu *menu, struct Item *item, XftColor *color);
static void drawmenu(void);
static void calcscreengeom(void);
static void calcmenu(struct Menu *menu);
@ -99,16 +102,14 @@ static Visual *visual;
static Window rootwin;
static int screen;
static struct DC dc;
static struct ScreenGeometry screengeom;
/* menu variables */
static struct Menu *rootmenu = NULL;
static struct Menu *currmenu = NULL;
static char **menutitle;
static int menutitlecount;
/* geometry variables */
static struct Geometry geom;
static struct ScreenGeometry screengeom;
static struct MenuGeometry geom;
#include "config.h"
@ -154,10 +155,6 @@ main(int argc, char *argv[])
grabpointer();
grabkeyboard();
/* map root menu */
setcurrmenu(rootmenu);
XMapWindow(dpy, rootmenu->win);
/* run event loop */
run();
@ -171,45 +168,45 @@ getresources(void)
{
char *xrm;
long n;
XrmInitialize();
if ((xrm = XResourceManagerString(dpy))) {
char *type;
XrmDatabase xdb;
XrmValue xval;
XrmInitialize();
if ((xrm = XResourceManagerString(dpy)) == NULL)
return;
xdb = XrmGetStringDatabase(xrm);
if (XrmGetResource(xdb, "xmenu.menuborder", "*", &type, &xval) == True)
if (XrmGetResource(xdb, "xmenu.borderWidth", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
menuborder = n;
if (XrmGetResource(xdb, "xmenu.separatorsize", "*", &type, &xval) == True)
border_pixels = n;
if (XrmGetResource(xdb, "xmenu.separatorWidth", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
separatorsize = n;
if (XrmGetResource(xdb, "xmenu.itemborder", "*", &type, &xval) == True)
separator_pixels = n;
if (XrmGetResource(xdb, "xmenu.padding", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
itemborder = n;
padding_pixels = n;
if (XrmGetResource(xdb, "xmenu.width", "*", &type, &xval) == True)
if ((n = strtol(xval.addr, NULL, 10)) > 0)
width = n;
width_pixels = n;
if (XrmGetResource(xdb, "xmenu.background", "*", &type, &xval) == True)
background = strdup(xval.addr);
background_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.foreground", "*", &type, &xval) == True)
foreground = strdup(xval.addr);
foreground_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.selbackground", "*", &type, &xval) == True)
selbackground = strdup(xval.addr);
selbackground_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.selforeground", "*", &type, &xval) == True)
selforeground = strdup(xval.addr);
selforeground_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.separator", "*", &type, &xval) == True)
separator = strdup(xval.addr);
separator_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.border", "*", &type, &xval) == True)
border = strdup(xval.addr);
border_color = strdup(xval.addr);
if (XrmGetResource(xdb, "xmenu.font", "*", &type, &xval) == True)
font = strdup(xval.addr);
XrmDestroyDatabase(xdb);
}
}
/* get color from color string */
static void
@ -224,18 +221,18 @@ static void
setupdc(void)
{
/* 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 */
if ((dc.font = XftFontOpenName(dpy, screen, font)) == NULL)
errx(1, "cannot load font");
/* create GC */
/* create common GC */
dc.gc = XCreateGC(dpy, rootwin, 0, NULL);
}
@ -243,11 +240,11 @@ setupdc(void)
static 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 */
@ -299,13 +296,15 @@ allocmenu(struct Menu *parent, struct Item *list, unsigned level)
menu->level = level;
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
| PointerMotionMask | LeaveWindowMask;
menu->win = XCreateWindow(dpy, rootwin, 0, 0, geom.itemw, geom.itemh, geom.border,
CopyFromParent, CopyFromParent, CopyFromParent,
CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWEventMask,
CWOverrideRedirect | CWBackPixel |
CWBorderPixel | CWEventMask | CWSaveUnder,
&swa);
return menu;
@ -573,6 +572,7 @@ setcurrmenu(struct Menu *currmenu_new)
/* if there was no currmenu, skip calculations */
if (currmenu == NULL) {
currmenu = currmenu_new;
XMapWindow(dpy, currmenu->win);
return;
}
@ -607,9 +607,49 @@ setcurrmenu(struct Menu *currmenu_new)
item = NULL;
for (menu = currmenu; menu != lcamenu; menu = menu->parent) {
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 (item = menu->list; item != NULL; item = item->next) {
XftColor *color;
int labelx, labely;
/* determine item color */
if (item == menu->selected)
if (item == menu->selected && item->label != NULL)
color = dc.selected;
else
color = dc.normal;
/* continue if item is a separator */
if (item->label == NULL)
continue;
/* draw item box */
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,
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);
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, item->y,
menu->w, item->h, 0, item->y);
}
XCopyArea(dpy, menu->pixmap, menu->win, dc.gc, 0, 0,
menu->w, menu->h, 0, 0);
}
}
@ -723,6 +737,8 @@ run(void)
KeySym ksym;
XEvent ev;
setcurrmenu(rootmenu);
while (!XNextEvent(dpy, &ev)) {
switch(ev.type) {
case Expose:
@ -731,23 +747,22 @@ run(void)
break;
case MotionNotify:
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item);
if (menu != NULL && item != NULL) {
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();
} else if (menu->selected != item) {
menu->selected = item;
drawmenu();
}
}
break;
case ButtonRelease:
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item);
if (menu != NULL && item != NULL) {
if (menu == NULL || item == NULL)
break;
selectitem:
if (item->label == NULL)
break; /* ignore separators */
@ -760,9 +775,6 @@ selectitem:
currmenu->selected = currmenu->list;
drawmenu();
break;
} else {
return;
}
case ButtonPress:
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item);
if (menu == NULL || item == NULL)
@ -798,6 +810,7 @@ selectitem:
drawmenu();
break;
case LeaveNotify:
previtem = NULL;
currmenu->selected = NULL;
drawmenu();
break;
@ -805,7 +818,7 @@ selectitem:
}
}
/* recursivelly free a pixmap */
/* recursivelly free pixmaps and destroy windows */
static void
freewindow(struct Menu *menu)
{
@ -830,8 +843,8 @@ cleanup(void)
XftColorFree(dpy, visual, colormap, &dc.normal[ColorFG]);
XftColorFree(dpy, visual, colormap, &dc.selected[ColorBG]);
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);
XCloseDisplay(dpy);