Adding icons patch
authorphillbush <phillbush@cock.li>
Sat, 30 May 2020 14:04:03 +0000 (11:04 -0300)
committerphillbush <phillbush@cock.li>
Sat, 30 May 2020 14:04:03 +0000 (11:04 -0300)
patches/icons.diff [new file with mode: 0644]
web.png [new file with mode: 0644]

diff --git a/patches/icons.diff b/patches/icons.diff
new file mode 100644 (file)
index 0000000..2663eff
--- /dev/null
@@ -0,0 +1,315 @@
+diff --git a/config.h b/config.h
+index a3e4f95..ca7c903 100644
+--- a/config.h
++++ b/config.h
+@@ -18,3 +18,6 @@ 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;
++
++/* sum of padding around both sides of the image */
++static const int imgpadding = 8;
+diff --git a/config.mk b/config.mk
+index f86aa34..0ffc8c5 100644
+--- a/config.mk
++++ b/config.mk
+@@ -14,8 +14,8 @@ FREETYPELIB = -lfontconfig -lXft
+ #FREETYPEINC = $(X11INC)/freetype2
+ # includes and libs
+-INCS = -I${X11INC} -I${FREETYPEINC}
+-LIBS = -L${X11LIB} -L${FREETYPELIB} -lX11
++INCS = -I/usr/local/include -I${X11INC} -I${FREETYPEINC}
++LIBS = -L/usr/local/lib -L${X11LIB} -L${FREETYPELIB} -lX11 -lImlib2
+ # flags
+ CPPFLAGS =
+diff --git a/xmenu.1 b/xmenu.1
+index d114668..5201032 100644
+--- a/xmenu.1
++++ b/xmenu.1
+@@ -13,17 +13,21 @@ and outputs the item selected to stdout.
+ Each item read from stdin has the following format:
+ .IP
+ .EX
+-ITEM := [TABS] [LABEL [TABS OUTPUT]] NEWLINE
++ITEM := [TABS] [[IMAGE TABS] LABEL [TABS OUTPUT]] NEWLINE
+ .EE
+ .PP
+ 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.
+ .IP
+ The initial tabs indicate the menu hierarchy:
+ 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.
+ .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.
+ 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.
+@@ -104,14 +108,14 @@ creating a command to be run by the shell.
+ cat <<EOF | xmenu | sh &
+ Applications
+-      Web Browser     firefox
+-      Image editor    gimp
+-Terminal (xterm)      xterm
+-Terminal (urxvt)      urxvt
+-Terminal (st)         st
++      IMG:./web.png   Web Browser     firefox
++      Image editor                            gimp
++Terminal (xterm)                              xterm
++Terminal (urxvt)                              urxvt
++Terminal (st)                                 st
+-Shutdown                      poweroff
+-Reboot                        reboot
++Shutdown                                              poweroff
++Reboot                                                reboot
+ EOF
+ .EE
+ .PP
+diff --git a/xmenu.c b/xmenu.c
+index abab13d..d70c6b8 100644
+--- a/xmenu.c
++++ b/xmenu.c
+@@ -8,6 +8,7 @@
+ #include <X11/Xresource.h>
+ #include <X11/XKBlib.h>
+ #include <X11/Xft/Xft.h>
++#include <Imlib2.h>
+ #define PROGNAME "xmenu"
+ #define ITEMPREV 0
+@@ -45,12 +46,14 @@ struct Geometry {
+ struct Item {
+       char *label;            /* string to be drawed on menu */
+       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 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 */
++      Imlib_Image image;
+ };
+ /* menu structure */
+@@ -71,9 +74,9 @@ static void getresources(void);
+ static void getcolor(const char *s, XftColor *color);
+ static void setupdc(void);
+ 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 *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 void calcmenu(struct Geometry *geom, struct Menu *menu);
+ static void grabpointer(void);
+@@ -129,6 +132,13 @@ main(int argc, char *argv[])
+       rootwin = RootWindow(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 */
+       getresources();
+       setupdc();
+@@ -247,7 +257,7 @@ calcgeom(struct Geometry *geom)
+ /* allocate an item */
+ static struct Item *
+-allocitem(const char *label, const char *output)
++allocitem(const char *label, const char *output, char *file)
+ {
+       struct Item *item;
+@@ -266,6 +276,12 @@ allocitem(const char *label, const char *output)
+                               err(1, "strdup");
+               }
+       }
++      if (file == NULL) {
++              item->file = NULL;
++      } else {
++              if ((item->file = strdup(file)) == NULL)
++                      err(1, "strdup");
++      }
+       item->y = 0;
+       item->h = 0;
+       if (item->label == NULL)
+@@ -274,6 +290,7 @@ allocitem(const char *label, const char *output)
+               item->labellen = strlen(item->label);
+       item->next = NULL;
+       item->submenu = NULL;
++      item->image = NULL;
+       return item;
+ }
+@@ -314,7 +331,7 @@ allocmenu(struct Menu *parent, struct Item *list, unsigned level)
+ /* build the menu tree */
+ 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 *rootmenu = NULL;    /* menu to be returned */
+@@ -324,7 +341,7 @@ buildmenutree(unsigned level, const char *label, const char *output)
+       unsigned i;
+       /* create the item */
+-      curritem = allocitem(label, output);
++      curritem = allocitem(label, output, file);
+       /* put the item in the menu tree */
+       if (prevmenu == NULL) {                 /* there is no menu yet */
+@@ -377,7 +394,7 @@ parsestdin(void)
+ {
+       struct Menu *rootmenu;
+       char *s, buf[BUFSIZ];
+-      char *label, *output;
++      char *file, *label, *output;
+       unsigned level = 0;
+       rootmenu = NULL;
+@@ -390,6 +407,13 @@ parsestdin(void)
+               s = level + buf;
+               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 */
+               output = strtok(NULL, "\n");
+               if (output == NULL) {
+@@ -399,12 +423,36 @@ parsestdin(void)
+                               output++;
+               }
+-              rootmenu = buildmenutree(level, label, output);
++              rootmenu = buildmenutree(level, label, output, file);
+       }
+       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;
++}
++
+ /* recursivelly calculate menu geometry and set window hints */
+ static void
+ calcmenu(struct Geometry *geom, struct Menu *menu)
+@@ -430,8 +478,12 @@ calcmenu(struct Geometry *geom, struct Menu *menu)
+               XftTextExtentsUtf8(dpy, dc.font, (XftChar8 *)item->label,
+                                  item->labellen, &ext);
+-              labelwidth = ext.xOff + dc.font->height * 2;
++              labelwidth = ext.xOff + dc.font->height * 2 + imgpadding;
+               menu->w = MAX(menu->w, labelwidth);
++              
++              /* create image */
++              if (item->file != NULL)
++                      item->image = loadimage(item->file, dc.font->height);
+       }
+       /* calculate menu's x and y positions */
+@@ -621,7 +673,7 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color)
+ {
+       int x, y;
+-      x = dc.font->height;
++      x = dc.font->height + imgpadding;
+       y = item->y + item->h/2 + dc.font->ascent/2 - 1;
+       XSetForeground(dpy, dc.gc, color[ColorFG].pixel);
+       XftDrawStringUtf8(menu->draw, &color[ColorFG], dc.font,
+@@ -629,8 +681,8 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color)
+       /* draw triangle, if item contains a submenu */
+       if (item->submenu != NULL) {
+-              x = menu->w - dc.font->height/2 - triangle_width/2;
+-              y = item->y + item->h/2 - triangle_height/2 - 1;
++              x = menu->w - (dc.font->height - triangle_width) / 2;
++              y = item->y + (item->h - triangle_height) / 2;
+               XPoint triangle[] = {
+                       {x, y},
+@@ -642,6 +694,15 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color)
+               XFillPolygon(dpy, menu->pixmap, dc.gc, triangle, LEN(triangle),
+                            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 */
+@@ -831,6 +892,13 @@ freemenu(struct Menu *menu)
+               if (tmp->label != tmp->output)
+                       free(tmp->label);
+               free(tmp->output);
++              if (tmp->file != NULL) {
++                      free(tmp->file);
++                      if (item->image != NULL) {
++                              imlib_context_set_image(item->image);
++                              imlib_free_image();
++                      }
++              }
+               free(tmp);
+       }
+diff --git a/xmenu.sh b/xmenu.sh
+index abd9a41..db08041 100755
+--- a/xmenu.sh
++++ b/xmenu.sh
+@@ -2,7 +2,7 @@
+ cat <<EOF | xmenu | sh &
+ Applications
+-      Web Browser     firefox
++      IMG:./web.png   Web Browser     firefox
+       Image editor    gimp
+ Terminal (xterm)      xterm
+ Terminal (urxvt)      urxvt
diff --git a/web.png b/web.png
new file mode 100644 (file)
index 0000000..a22adb0
Binary files /dev/null and b/web.png differ