A mirror of phillbush's xmenu.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 

316 行
9.4 KiB

  1. diff --git a/config.h b/config.h
  2. index a3e4f95..ca7c903 100644
  3. --- a/config.h
  4. +++ b/config.h
  5. @@ -18,3 +18,6 @@ static int separator_pixels = 3; /* space around separator */
  6. /* geometry of the right-pointing isoceles triangle for submenus */
  7. static const int triangle_width = 3;
  8. static const int triangle_height = 7;
  9. +
  10. +/* sum of padding around both sides of the image */
  11. +static const int imgpadding = 8;
  12. diff --git a/config.mk b/config.mk
  13. index f86aa34..0ffc8c5 100644
  14. --- a/config.mk
  15. +++ b/config.mk
  16. @@ -14,8 +14,8 @@ FREETYPELIB = -lfontconfig -lXft
  17. #FREETYPEINC = $(X11INC)/freetype2
  18. # includes and libs
  19. -INCS = -I${X11INC} -I${FREETYPEINC}
  20. -LIBS = -L${X11LIB} -L${FREETYPELIB} -lX11
  21. +INCS = -I/usr/local/include -I${X11INC} -I${FREETYPEINC}
  22. +LIBS = -L/usr/local/lib -L${X11LIB} -L${FREETYPELIB} -lX11 -lImlib2
  23. # flags
  24. CPPFLAGS =
  25. diff --git a/xmenu.1 b/xmenu.1
  26. index d114668..5201032 100644
  27. --- a/xmenu.1
  28. +++ b/xmenu.1
  29. @@ -13,17 +13,21 @@ and outputs the item selected to stdout.
  30. Each item read from stdin has the following format:
  31. .IP
  32. .EX
  33. -ITEM := [TABS] [LABEL [TABS OUTPUT]] NEWLINE
  34. +ITEM := [TABS] [[IMAGE TABS] LABEL [TABS OUTPUT]] NEWLINE
  35. .EE
  36. .PP
  37. That means that each item is composed by
  38. -tabs, followed by a label, followed by more tabs, followed by an output,
  39. +tabs, followed by an optional image specification, followed by tabs
  40. +followed by a label, followed by more tabs, followed by an output,
  41. and ended by a newline. Brackets group optional elements.
  42. .IP
  43. The initial tabs indicate the menu hierarchy:
  44. items indented with a tab is shown in a submenu of the preceding item not indented.
  45. An item without initial tabs is a top-level item.
  46. .IP
  47. +The image is a string of the form "IMG:/path/to/image.png".
  48. +It specifies a image to be shown as icon at the left of the entry.
  49. +.IP
  50. The label is the string that will be shown as a item in the menu.
  51. An item without label is considered a separator and is drawn as a thin line in the menu
  52. separating the item above from the item below.
  53. @@ -104,14 +108,14 @@ creating a command to be run by the shell.
  54. cat <<EOF | xmenu | sh &
  55. Applications
  56. - Web Browser firefox
  57. - Image editor gimp
  58. -Terminal (xterm) xterm
  59. -Terminal (urxvt) urxvt
  60. -Terminal (st) st
  61. + IMG:./web.png Web Browser firefox
  62. + Image editor gimp
  63. +Terminal (xterm) xterm
  64. +Terminal (urxvt) urxvt
  65. +Terminal (st) st
  66. -Shutdown poweroff
  67. -Reboot reboot
  68. +Shutdown poweroff
  69. +Reboot reboot
  70. EOF
  71. .EE
  72. .PP
  73. diff --git a/xmenu.c b/xmenu.c
  74. index abab13d..d70c6b8 100644
  75. --- a/xmenu.c
  76. +++ b/xmenu.c
  77. @@ -8,6 +8,7 @@
  78. #include <X11/Xresource.h>
  79. #include <X11/XKBlib.h>
  80. #include <X11/Xft/Xft.h>
  81. +#include <Imlib2.h>
  82. #define PROGNAME "xmenu"
  83. #define ITEMPREV 0
  84. @@ -45,12 +46,14 @@ struct Geometry {
  85. struct Item {
  86. char *label; /* string to be drawed on menu */
  87. char *output; /* string to be outputed when item is clicked */
  88. + char *file; /* filename of the image */
  89. int y; /* item y position relative to menu */
  90. int h; /* item height */
  91. size_t labellen; /* strlen(label) */
  92. struct Item *prev; /* previous item */
  93. struct Item *next; /* next item */
  94. struct Menu *submenu; /* submenu spawned by clicking on item */
  95. + Imlib_Image image;
  96. };
  97. /* menu structure */
  98. @@ -71,9 +74,9 @@ static void getresources(void);
  99. static void getcolor(const char *s, XftColor *color);
  100. static void setupdc(void);
  101. static void calcgeom(struct Geometry *geom);
  102. -static struct Item *allocitem(const char *label, const char *output);
  103. +static struct Item *allocitem(const char *label, const char *output, char *file);
  104. static struct Menu *allocmenu(struct Menu *parent, struct Item *list, unsigned level);
  105. -static struct Menu *buildmenutree(unsigned level, const char *label, const char *output);
  106. +static struct Menu *buildmenutree(unsigned level, const char *label, const char *output, char *file);
  107. static struct Menu *parsestdin(void);
  108. static void calcmenu(struct Geometry *geom, struct Menu *menu);
  109. static void grabpointer(void);
  110. @@ -129,6 +132,13 @@ main(int argc, char *argv[])
  111. rootwin = RootWindow(dpy, screen);
  112. colormap = DefaultColormap(dpy, screen);
  113. + /* imlib2 stuff */
  114. + imlib_set_cache_size(2048 * 1024);
  115. + imlib_context_set_dither(1);
  116. + imlib_context_set_display(dpy);
  117. + imlib_context_set_visual(visual);
  118. + imlib_context_set_colormap(colormap);
  119. +
  120. /* setup */
  121. getresources();
  122. setupdc();
  123. @@ -247,7 +257,7 @@ calcgeom(struct Geometry *geom)
  124. /* allocate an item */
  125. static struct Item *
  126. -allocitem(const char *label, const char *output)
  127. +allocitem(const char *label, const char *output, char *file)
  128. {
  129. struct Item *item;
  130. @@ -266,6 +276,12 @@ allocitem(const char *label, const char *output)
  131. err(1, "strdup");
  132. }
  133. }
  134. + if (file == NULL) {
  135. + item->file = NULL;
  136. + } else {
  137. + if ((item->file = strdup(file)) == NULL)
  138. + err(1, "strdup");
  139. + }
  140. item->y = 0;
  141. item->h = 0;
  142. if (item->label == NULL)
  143. @@ -274,6 +290,7 @@ allocitem(const char *label, const char *output)
  144. item->labellen = strlen(item->label);
  145. item->next = NULL;
  146. item->submenu = NULL;
  147. + item->image = NULL;
  148. return item;
  149. }
  150. @@ -314,7 +331,7 @@ allocmenu(struct Menu *parent, struct Item *list, unsigned level)
  151. /* build the menu tree */
  152. static struct Menu *
  153. -buildmenutree(unsigned level, const char *label, const char *output)
  154. +buildmenutree(unsigned level, const char *label, const char *output, char *file)
  155. {
  156. static struct Menu *prevmenu = NULL; /* menu the previous item was added to */
  157. static struct Menu *rootmenu = NULL; /* menu to be returned */
  158. @@ -324,7 +341,7 @@ buildmenutree(unsigned level, const char *label, const char *output)
  159. unsigned i;
  160. /* create the item */
  161. - curritem = allocitem(label, output);
  162. + curritem = allocitem(label, output, file);
  163. /* put the item in the menu tree */
  164. if (prevmenu == NULL) { /* there is no menu yet */
  165. @@ -377,7 +394,7 @@ parsestdin(void)
  166. {
  167. struct Menu *rootmenu;
  168. char *s, buf[BUFSIZ];
  169. - char *label, *output;
  170. + char *file, *label, *output;
  171. unsigned level = 0;
  172. rootmenu = NULL;
  173. @@ -390,6 +407,13 @@ parsestdin(void)
  174. s = level + buf;
  175. label = strtok(s, "\t\n");
  176. + /* get the filename */
  177. + file = NULL;
  178. + if (label != NULL && strncmp(label, "IMG:", 4) == 0) {
  179. + file = label + 4;
  180. + label = strtok(NULL, "\t\n");
  181. + }
  182. +
  183. /* get the output */
  184. output = strtok(NULL, "\n");
  185. if (output == NULL) {
  186. @@ -399,12 +423,36 @@ parsestdin(void)
  187. output++;
  188. }
  189. - rootmenu = buildmenutree(level, label, output);
  190. + rootmenu = buildmenutree(level, label, output, file);
  191. }
  192. return rootmenu;
  193. }
  194. +/* load and scale image */
  195. +static Imlib_Image
  196. +loadimage(const char *file, int size)
  197. +{
  198. + Imlib_Image image;
  199. + int width;
  200. + int height;
  201. + int imgsize;
  202. +
  203. + image = imlib_load_image(file);
  204. + if (image == NULL)
  205. + errx(1, "cannot load image %s", file);
  206. +
  207. + imlib_context_set_image(image);
  208. +
  209. + width = imlib_image_get_width();
  210. + height = imlib_image_get_height();
  211. + imgsize = MIN(width, height);
  212. +
  213. + image = imlib_create_cropped_scaled_image(0, 0, imgsize, imgsize, size, size);
  214. +
  215. + return image;
  216. +}
  217. +
  218. /* recursivelly calculate menu geometry and set window hints */
  219. static void
  220. calcmenu(struct Geometry *geom, struct Menu *menu)
  221. @@ -430,8 +478,12 @@ calcmenu(struct Geometry *geom, struct Menu *menu)
  222. XftTextExtentsUtf8(dpy, dc.font, (XftChar8 *)item->label,
  223. item->labellen, &ext);
  224. - labelwidth = ext.xOff + dc.font->height * 2;
  225. + labelwidth = ext.xOff + dc.font->height * 2 + imgpadding;
  226. menu->w = MAX(menu->w, labelwidth);
  227. +
  228. + /* create image */
  229. + if (item->file != NULL)
  230. + item->image = loadimage(item->file, dc.font->height);
  231. }
  232. /* calculate menu's x and y positions */
  233. @@ -621,7 +673,7 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color)
  234. {
  235. int x, y;
  236. - x = dc.font->height;
  237. + x = dc.font->height + imgpadding;
  238. y = item->y + item->h/2 + dc.font->ascent/2 - 1;
  239. XSetForeground(dpy, dc.gc, color[ColorFG].pixel);
  240. XftDrawStringUtf8(menu->draw, &color[ColorFG], dc.font,
  241. @@ -629,8 +681,8 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color)
  242. /* draw triangle, if item contains a submenu */
  243. if (item->submenu != NULL) {
  244. - x = menu->w - dc.font->height/2 - triangle_width/2;
  245. - y = item->y + item->h/2 - triangle_height/2 - 1;
  246. + x = menu->w - (dc.font->height - triangle_width) / 2;
  247. + y = item->y + (item->h - triangle_height) / 2;
  248. XPoint triangle[] = {
  249. {x, y},
  250. @@ -642,6 +694,15 @@ drawitem(struct Menu *menu, struct Item *item, XftColor *color)
  251. XFillPolygon(dpy, menu->pixmap, dc.gc, triangle, LEN(triangle),
  252. Convex, CoordModeOrigin);
  253. }
  254. +
  255. + /* draw image */
  256. + if (item->file != NULL) {
  257. + x = imgpadding / 2;
  258. + y = item->y + (item->h - dc.font->height) / 2;
  259. + imlib_context_set_drawable(menu->pixmap);
  260. + imlib_context_set_image(item->image);
  261. + imlib_render_image_on_drawable(x, y);
  262. + }
  263. }
  264. /* draw items of the current menu and of its ancestors */
  265. @@ -831,6 +892,13 @@ freemenu(struct Menu *menu)
  266. if (tmp->label != tmp->output)
  267. free(tmp->label);
  268. free(tmp->output);
  269. + if (tmp->file != NULL) {
  270. + free(tmp->file);
  271. + if (item->image != NULL) {
  272. + imlib_context_set_image(item->image);
  273. + imlib_free_image();
  274. + }
  275. + }
  276. free(tmp);
  277. }
  278. diff --git a/xmenu.sh b/xmenu.sh
  279. index abd9a41..db08041 100755
  280. --- a/xmenu.sh
  281. +++ b/xmenu.sh
  282. @@ -2,7 +2,7 @@
  283. cat <<EOF | xmenu | sh &
  284. Applications
  285. - Web Browser firefox
  286. + IMG:./web.png Web Browser firefox
  287. Image editor gimp
  288. Terminal (xterm) xterm
  289. Terminal (urxvt) urxvt