Drawing menus on demand, reordering functions
This commit is contained in:
		
							
								
								
									
										290
									
								
								xmenu.c
									
									
									
									
									
								
							
							
						
						
									
										290
									
								
								xmenu.c
									
									
									
									
									
								
							@@ -37,15 +37,9 @@ static struct Menu *allocmenu(struct Menu *parent, struct Item *list, unsigned l
 | 
				
			|||||||
static struct Menu *buildmenutree(unsigned level, const char *label, const char *output, char *file);
 | 
					static struct Menu *buildmenutree(unsigned level, const char *label, const char *output, char *file);
 | 
				
			||||||
static struct Menu *parsestdin(void);
 | 
					static struct Menu *parsestdin(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* image loader */
 | 
					/* text drawer, and its helper routine */
 | 
				
			||||||
static Imlib_Image loadicon(const char *file);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* utf8 utils */
 | 
					 | 
				
			||||||
static FcChar32 getnextutf8char(const char *s, const char **end_ret);
 | 
					static FcChar32 getnextutf8char(const char *s, const char **end_ret);
 | 
				
			||||||
 | 
					 | 
				
			||||||
/* pixmap drawers */
 | 
					 | 
				
			||||||
static int drawtext(XftDraw *draw, XftColor *color, int x, int y, unsigned h, const char *text);
 | 
					static int drawtext(XftDraw *draw, XftColor *color, int x, int y, unsigned h, const char *text);
 | 
				
			||||||
static void drawitems(struct Menu *menu);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* structure setters, and their helper routines */
 | 
					/* structure setters, and their helper routines */
 | 
				
			||||||
static void setupitems(struct Menu *menu);
 | 
					static void setupitems(struct Menu *menu);
 | 
				
			||||||
@@ -56,9 +50,13 @@ static void setupmenu(struct Menu *menu, XClassHint *classh);
 | 
				
			|||||||
static void grabpointer(void);
 | 
					static void grabpointer(void);
 | 
				
			||||||
static void grabkeyboard(void);
 | 
					static void grabkeyboard(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* window drawers and mappers */
 | 
					/* item drawer, and its helper routine */
 | 
				
			||||||
 | 
					static Imlib_Image loadicon(const char *file);
 | 
				
			||||||
 | 
					static void drawitems(struct Menu *menu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* menu drawers and mappers */
 | 
				
			||||||
 | 
					static void drawmenus(struct Menu *currmenu);
 | 
				
			||||||
static void mapmenu(struct Menu *currmenu);
 | 
					static void mapmenu(struct Menu *currmenu);
 | 
				
			||||||
static void copypixmaps(struct Menu *currmenu);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* getters */
 | 
					/* getters */
 | 
				
			||||||
static struct Menu *getmenu(struct Menu *currmenu, Window win);
 | 
					static struct Menu *getmenu(struct Menu *currmenu, Window win);
 | 
				
			||||||
@@ -407,6 +405,7 @@ allocmenu(struct Menu *parent, struct Item *list, unsigned level)
 | 
				
			|||||||
	menu->x = 0;    /* calculated by setupmenu() */
 | 
						menu->x = 0;    /* calculated by setupmenu() */
 | 
				
			||||||
	menu->y = 0;    /* calculated by setupmenu() */
 | 
						menu->y = 0;    /* calculated by setupmenu() */
 | 
				
			||||||
	menu->level = level;
 | 
						menu->level = level;
 | 
				
			||||||
 | 
						menu->drawn = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	swa.override_redirect = (wflag) ? False : True;
 | 
						swa.override_redirect = (wflag) ? False : True;
 | 
				
			||||||
	swa.background_pixel = dc.normal[ColorBG].pixel;
 | 
						swa.background_pixel = dc.normal[ColorBG].pixel;
 | 
				
			||||||
@@ -525,43 +524,15 @@ parsestdin(void)
 | 
				
			|||||||
	return rootmenu;
 | 
						return rootmenu;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* load and scale icon */
 | 
					/* get next utf8 char from s return its codepoint and set next_ret to pointer to end of character */
 | 
				
			||||||
static Imlib_Image
 | 
					 | 
				
			||||||
loadicon(const char *file)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	Imlib_Image icon;
 | 
					 | 
				
			||||||
	int width;
 | 
					 | 
				
			||||||
	int height;
 | 
					 | 
				
			||||||
	int imgsize;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	icon = imlib_load_image(file);
 | 
					 | 
				
			||||||
	if (icon == NULL)
 | 
					 | 
				
			||||||
		errx(1, "cannot load icon %s", file);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	imlib_context_set_image(icon);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	width = imlib_image_get_width();
 | 
					 | 
				
			||||||
	height = imlib_image_get_height();
 | 
					 | 
				
			||||||
	imgsize = MIN(width, height);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	icon = imlib_create_cropped_scaled_image(0, 0, imgsize, imgsize,
 | 
					 | 
				
			||||||
	                                         config.iconsize,
 | 
					 | 
				
			||||||
	                                         config.iconsize);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return icon;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* get next utf8 char from s return its codepoint and set next_ret to pointer to next character */
 | 
					 | 
				
			||||||
static FcChar32
 | 
					static FcChar32
 | 
				
			||||||
getnextutf8char(const char *s, const char **next_ret)
 | 
					getnextutf8char(const char *s, const char **next_ret)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* */
 | 
					 | 
				
			||||||
	static const unsigned char utfbyte[] = {0x80, 0x00, 0xC0, 0xE0, 0xF0};
 | 
						static const unsigned char utfbyte[] = {0x80, 0x00, 0xC0, 0xE0, 0xF0};
 | 
				
			||||||
	/* */
 | 
					 | 
				
			||||||
	static const unsigned char utfmask[] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
 | 
						static const unsigned char utfmask[] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
 | 
				
			||||||
	/* 0xFFFD is the replacement character, used to represent unknown characters */
 | 
					 | 
				
			||||||
	static const FcChar32 utfmin[] = {0, 0x00,  0x80,  0x800,  0x10000};
 | 
						static const FcChar32 utfmin[] = {0, 0x00,  0x80,  0x800,  0x10000};
 | 
				
			||||||
	static const FcChar32 utfmax[] = {0, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
 | 
						static const FcChar32 utfmax[] = {0, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
 | 
				
			||||||
 | 
						/* 0xFFFD is the replacement character, used to represent unknown characters */
 | 
				
			||||||
	static const FcChar32 unknown = 0xFFFD;
 | 
						static const FcChar32 unknown = 0xFFFD;
 | 
				
			||||||
	FcChar32 ucode;         /* FcChar32 type holds 32 bits */
 | 
						FcChar32 ucode;         /* FcChar32 type holds 32 bits */
 | 
				
			||||||
	size_t usize = 0;       /* n' of bytes of the utf8 character */
 | 
						size_t usize = 0;       /* n' of bytes of the utf8 character */
 | 
				
			||||||
@@ -649,84 +620,6 @@ drawtext(XftDraw *draw, XftColor *color, int x, int y, unsigned h, const char *t
 | 
				
			|||||||
	return textlen;
 | 
						return textlen;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* draw pixmap for the selected and unselected version of each item on menu */
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
drawitems(struct Menu *menu)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct Item *item;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (item = menu->list; item != NULL; item = item->next) {
 | 
					 | 
				
			||||||
		XftDraw *dsel, *dunsel;
 | 
					 | 
				
			||||||
		int x, y;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		item->unsel = XCreatePixmap(dpy, menu->win, menu->w, item->h,
 | 
					 | 
				
			||||||
		                          DefaultDepth(dpy, screen));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		XSetForeground(dpy, dc.gc, dc.normal[ColorBG].pixel);
 | 
					 | 
				
			||||||
		XFillRectangle(dpy, item->unsel, dc.gc, 0, 0, menu->w, item->h);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (item->label == NULL) { /* item is separator */
 | 
					 | 
				
			||||||
			y = item->h/2;
 | 
					 | 
				
			||||||
			XSetForeground(dpy, dc.gc, dc.separator.pixel);
 | 
					 | 
				
			||||||
			XDrawLine(dpy, item->unsel, dc.gc, config.horzpadding, y,
 | 
					 | 
				
			||||||
			          menu->w - config.horzpadding, y);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			item->sel = item->unsel;
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			item->sel = XCreatePixmap(dpy, menu->win, menu->w, item->h,
 | 
					 | 
				
			||||||
			                          DefaultDepth(dpy, screen));
 | 
					 | 
				
			||||||
			XSetForeground(dpy, dc.gc, dc.selected[ColorBG].pixel);
 | 
					 | 
				
			||||||
			XFillRectangle(dpy, item->sel, dc.gc, 0, 0, menu->w, item->h);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/* draw text */
 | 
					 | 
				
			||||||
			x = config.horzpadding;
 | 
					 | 
				
			||||||
			x += (iflag) ? 0 : config.horzpadding + config.iconsize;
 | 
					 | 
				
			||||||
			dsel = XftDrawCreate(dpy, item->sel, visual, colormap);
 | 
					 | 
				
			||||||
			dunsel = XftDrawCreate(dpy, item->unsel, visual, colormap);
 | 
					 | 
				
			||||||
			XSetForeground(dpy, dc.gc, dc.selected[ColorFG].pixel);
 | 
					 | 
				
			||||||
			drawtext(dsel, &dc.selected[ColorFG], x, 0, item->h, item->label);
 | 
					 | 
				
			||||||
			XSetForeground(dpy, dc.gc, dc.normal[ColorFG].pixel);
 | 
					 | 
				
			||||||
			drawtext(dunsel, &dc.normal[ColorFG], x, 0, item->h, item->label);
 | 
					 | 
				
			||||||
			XftDrawDestroy(dsel);
 | 
					 | 
				
			||||||
			XftDrawDestroy(dunsel);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/* draw triangle */
 | 
					 | 
				
			||||||
			if (item->submenu != NULL) {
 | 
					 | 
				
			||||||
				x = menu->w - config.triangle_width - config.horzpadding;
 | 
					 | 
				
			||||||
				y = (item->h - config.triangle_height + 1) / 2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				XPoint triangle[] = {
 | 
					 | 
				
			||||||
					{x, y},
 | 
					 | 
				
			||||||
					{x + config.triangle_width, y + config.triangle_height/2},
 | 
					 | 
				
			||||||
					{x, y + config.triangle_height},
 | 
					 | 
				
			||||||
					{x, y}
 | 
					 | 
				
			||||||
				};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				XSetForeground(dpy, dc.gc, dc.selected[ColorFG].pixel);
 | 
					 | 
				
			||||||
				XFillPolygon(dpy, item->sel, dc.gc, triangle, LEN(triangle),
 | 
					 | 
				
			||||||
				             Convex, CoordModeOrigin);
 | 
					 | 
				
			||||||
				XSetForeground(dpy, dc.gc, dc.normal[ColorFG].pixel);
 | 
					 | 
				
			||||||
				XFillPolygon(dpy, item->unsel, dc.gc, triangle, LEN(triangle),
 | 
					 | 
				
			||||||
				             Convex, CoordModeOrigin);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			/* draw icon */
 | 
					 | 
				
			||||||
			if (item->file != NULL && !iflag) {
 | 
					 | 
				
			||||||
				item->icon = loadicon(item->file);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				imlib_context_set_drawable(item->sel);
 | 
					 | 
				
			||||||
				imlib_context_set_image(item->icon);
 | 
					 | 
				
			||||||
				imlib_render_image_on_drawable(config.horzpadding, config.iconpadding);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				imlib_context_set_drawable(item->unsel);
 | 
					 | 
				
			||||||
				imlib_context_set_image(item->icon);
 | 
					 | 
				
			||||||
				imlib_render_image_on_drawable(config.horzpadding, config.iconpadding);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* setup the height, width and icon of the items of a menu */
 | 
					/* setup the height, width and icon of the items of a menu */
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
setupitems(struct Menu *menu)
 | 
					setupitems(struct Menu *menu)
 | 
				
			||||||
@@ -814,7 +707,6 @@ setupmenu(struct Menu *menu, XClassHint *classh)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/* setup size and position of menus */
 | 
						/* setup size and position of menus */
 | 
				
			||||||
	setupitems(menu);
 | 
						setupitems(menu);
 | 
				
			||||||
	drawitems(menu);
 | 
					 | 
				
			||||||
	setupmenupos(menu);
 | 
						setupmenupos(menu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* update menu geometry */
 | 
						/* update menu geometry */
 | 
				
			||||||
@@ -887,6 +779,131 @@ grabkeyboard(void)
 | 
				
			|||||||
	errx(1, "cannot grab keyboard");
 | 
						errx(1, "cannot grab keyboard");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* load and scale icon */
 | 
				
			||||||
 | 
					static Imlib_Image
 | 
				
			||||||
 | 
					loadicon(const char *file)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						Imlib_Image icon;
 | 
				
			||||||
 | 
						int width;
 | 
				
			||||||
 | 
						int height;
 | 
				
			||||||
 | 
						int imgsize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						icon = imlib_load_image(file);
 | 
				
			||||||
 | 
						if (icon == NULL)
 | 
				
			||||||
 | 
							errx(1, "cannot load icon %s", file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						imlib_context_set_image(icon);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						width = imlib_image_get_width();
 | 
				
			||||||
 | 
						height = imlib_image_get_height();
 | 
				
			||||||
 | 
						imgsize = MIN(width, height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						icon = imlib_create_cropped_scaled_image(0, 0, imgsize, imgsize,
 | 
				
			||||||
 | 
						                                         config.iconsize,
 | 
				
			||||||
 | 
						                                         config.iconsize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return icon;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* draw pixmap for the selected and unselected version of each item on menu */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					drawitems(struct Menu *menu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct Item *item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (item = menu->list; item != NULL; item = item->next) {
 | 
				
			||||||
 | 
							XftDraw *dsel, *dunsel;
 | 
				
			||||||
 | 
							int x, y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							item->unsel = XCreatePixmap(dpy, menu->win, menu->w, item->h,
 | 
				
			||||||
 | 
							                          DefaultDepth(dpy, screen));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							XSetForeground(dpy, dc.gc, dc.normal[ColorBG].pixel);
 | 
				
			||||||
 | 
							XFillRectangle(dpy, item->unsel, dc.gc, 0, 0, menu->w, item->h);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (item->label == NULL) { /* item is separator */
 | 
				
			||||||
 | 
								y = item->h/2;
 | 
				
			||||||
 | 
								XSetForeground(dpy, dc.gc, dc.separator.pixel);
 | 
				
			||||||
 | 
								XDrawLine(dpy, item->unsel, dc.gc, config.horzpadding, y,
 | 
				
			||||||
 | 
								          menu->w - config.horzpadding, y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								item->sel = item->unsel;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								item->sel = XCreatePixmap(dpy, menu->win, menu->w, item->h,
 | 
				
			||||||
 | 
								                          DefaultDepth(dpy, screen));
 | 
				
			||||||
 | 
								XSetForeground(dpy, dc.gc, dc.selected[ColorBG].pixel);
 | 
				
			||||||
 | 
								XFillRectangle(dpy, item->sel, dc.gc, 0, 0, menu->w, item->h);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* draw text */
 | 
				
			||||||
 | 
								x = config.horzpadding;
 | 
				
			||||||
 | 
								x += (iflag) ? 0 : config.horzpadding + config.iconsize;
 | 
				
			||||||
 | 
								dsel = XftDrawCreate(dpy, item->sel, visual, colormap);
 | 
				
			||||||
 | 
								dunsel = XftDrawCreate(dpy, item->unsel, visual, colormap);
 | 
				
			||||||
 | 
								XSetForeground(dpy, dc.gc, dc.selected[ColorFG].pixel);
 | 
				
			||||||
 | 
								drawtext(dsel, &dc.selected[ColorFG], x, 0, item->h, item->label);
 | 
				
			||||||
 | 
								XSetForeground(dpy, dc.gc, dc.normal[ColorFG].pixel);
 | 
				
			||||||
 | 
								drawtext(dunsel, &dc.normal[ColorFG], x, 0, item->h, item->label);
 | 
				
			||||||
 | 
								XftDrawDestroy(dsel);
 | 
				
			||||||
 | 
								XftDrawDestroy(dunsel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* draw triangle */
 | 
				
			||||||
 | 
								if (item->submenu != NULL) {
 | 
				
			||||||
 | 
									x = menu->w - config.triangle_width - config.horzpadding;
 | 
				
			||||||
 | 
									y = (item->h - config.triangle_height + 1) / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									XPoint triangle[] = {
 | 
				
			||||||
 | 
										{x, y},
 | 
				
			||||||
 | 
										{x + config.triangle_width, y + config.triangle_height/2},
 | 
				
			||||||
 | 
										{x, y + config.triangle_height},
 | 
				
			||||||
 | 
										{x, y}
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									XSetForeground(dpy, dc.gc, dc.selected[ColorFG].pixel);
 | 
				
			||||||
 | 
									XFillPolygon(dpy, item->sel, dc.gc, triangle, LEN(triangle),
 | 
				
			||||||
 | 
									             Convex, CoordModeOrigin);
 | 
				
			||||||
 | 
									XSetForeground(dpy, dc.gc, dc.normal[ColorFG].pixel);
 | 
				
			||||||
 | 
									XFillPolygon(dpy, item->unsel, dc.gc, triangle, LEN(triangle),
 | 
				
			||||||
 | 
									             Convex, CoordModeOrigin);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/* draw icon */
 | 
				
			||||||
 | 
								if (item->file != NULL && !iflag) {
 | 
				
			||||||
 | 
									item->icon = loadicon(item->file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									imlib_context_set_drawable(item->sel);
 | 
				
			||||||
 | 
									imlib_context_set_image(item->icon);
 | 
				
			||||||
 | 
									imlib_render_image_on_drawable(config.horzpadding, config.iconpadding);
 | 
				
			||||||
 | 
									imlib_context_set_drawable(item->unsel);
 | 
				
			||||||
 | 
									imlib_render_image_on_drawable(config.horzpadding, config.iconpadding);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* copy pixmaps of items of the current menu and of its ancestors into menu window */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					drawmenus(struct Menu *currmenu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct Menu *menu;
 | 
				
			||||||
 | 
						struct Item *item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (menu = currmenu; menu != NULL; menu = menu->parent) {
 | 
				
			||||||
 | 
							if (!menu->drawn) {
 | 
				
			||||||
 | 
								drawitems(menu);
 | 
				
			||||||
 | 
								menu->drawn = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for (item = menu->list; item != NULL; item = item->next) {
 | 
				
			||||||
 | 
								if (item == menu->selected)
 | 
				
			||||||
 | 
									XCopyArea(dpy, item->sel, menu->win, dc.gc, 0, 0,
 | 
				
			||||||
 | 
									          menu->w, item->h, 0, item->y);
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									XCopyArea(dpy, item->unsel, menu->win, dc.gc, 0, 0,
 | 
				
			||||||
 | 
									          menu->w, item->h, 0, item->y);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* umap previous menus and map current menu and its parents */
 | 
					/* umap previous menus and map current menu and its parents */
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
mapmenu(struct Menu *currmenu)
 | 
					mapmenu(struct Menu *currmenu)
 | 
				
			||||||
@@ -946,25 +963,6 @@ mapmenu(struct Menu *currmenu)
 | 
				
			|||||||
	prevmenu = currmenu;
 | 
						prevmenu = currmenu;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* copy pixmaps of items of the current menu and of its ancestors into menu window */
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
copypixmaps(struct Menu *currmenu)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct Menu *menu;
 | 
					 | 
				
			||||||
	struct Item *item;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (menu = currmenu; menu != NULL; menu = menu->parent) {
 | 
					 | 
				
			||||||
		for (item = menu->list; item != NULL; item = item->next) {
 | 
					 | 
				
			||||||
			if (item == menu->selected)
 | 
					 | 
				
			||||||
				XCopyArea(dpy, item->sel, menu->win, dc.gc, 0, 0,
 | 
					 | 
				
			||||||
				          menu->w, item->h, 0, item->y);
 | 
					 | 
				
			||||||
			else
 | 
					 | 
				
			||||||
				XCopyArea(dpy, item->unsel, menu->win, dc.gc, 0, 0,
 | 
					 | 
				
			||||||
				          menu->w, item->h, 0, item->y);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* get menu of given window */
 | 
					/* get menu of given window */
 | 
				
			||||||
static struct Menu *
 | 
					static struct Menu *
 | 
				
			||||||
getmenu(struct Menu *currmenu, Window win)
 | 
					getmenu(struct Menu *currmenu, Window win)
 | 
				
			||||||
@@ -1051,7 +1049,7 @@ run(struct Menu *currmenu)
 | 
				
			|||||||
		switch(ev.type) {
 | 
							switch(ev.type) {
 | 
				
			||||||
		case Expose:
 | 
							case Expose:
 | 
				
			||||||
			if (ev.xexpose.count == 0)
 | 
								if (ev.xexpose.count == 0)
 | 
				
			||||||
				copypixmaps(currmenu);
 | 
									drawmenus(currmenu);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case MotionNotify:
 | 
							case MotionNotify:
 | 
				
			||||||
			menu = getmenu(currmenu, ev.xbutton.window);
 | 
								menu = getmenu(currmenu, ev.xbutton.window);
 | 
				
			||||||
@@ -1067,7 +1065,7 @@ run(struct Menu *currmenu)
 | 
				
			|||||||
				currmenu = menu;
 | 
									currmenu = menu;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			mapmenu(currmenu);
 | 
								mapmenu(currmenu);
 | 
				
			||||||
			copypixmaps(currmenu);
 | 
								drawmenus(currmenu);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case ButtonRelease:
 | 
							case ButtonRelease:
 | 
				
			||||||
			menu = getmenu(currmenu, ev.xbutton.window);
 | 
								menu = getmenu(currmenu, ev.xbutton.window);
 | 
				
			||||||
@@ -1085,7 +1083,7 @@ selectitem:
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			mapmenu(currmenu);
 | 
								mapmenu(currmenu);
 | 
				
			||||||
			currmenu->selected = currmenu->list;
 | 
								currmenu->selected = currmenu->list;
 | 
				
			||||||
			copypixmaps(currmenu);
 | 
								drawmenus(currmenu);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case ButtonPress:
 | 
							case ButtonPress:
 | 
				
			||||||
			menu = getmenu(currmenu, ev.xbutton.window);
 | 
								menu = getmenu(currmenu, ev.xbutton.window);
 | 
				
			||||||
@@ -1121,12 +1119,12 @@ selectitem:
 | 
				
			|||||||
			} else
 | 
								} else
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			currmenu->selected = item;
 | 
								currmenu->selected = item;
 | 
				
			||||||
			copypixmaps(currmenu);
 | 
								drawmenus(currmenu);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case LeaveNotify:
 | 
							case LeaveNotify:
 | 
				
			||||||
			previtem = NULL;
 | 
								previtem = NULL;
 | 
				
			||||||
			currmenu->selected = NULL;
 | 
								currmenu->selected = NULL;
 | 
				
			||||||
			copypixmaps(currmenu);
 | 
								drawmenus(currmenu);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case ConfigureNotify:
 | 
							case ConfigureNotify:
 | 
				
			||||||
			menu = getmenu(currmenu, ev.xconfigure.window);
 | 
								menu = getmenu(currmenu, ev.xconfigure.window);
 | 
				
			||||||
@@ -1161,9 +1159,11 @@ cleanmenu(struct Menu *menu)
 | 
				
			|||||||
		if (item->submenu != NULL)
 | 
							if (item->submenu != NULL)
 | 
				
			||||||
			cleanmenu(item->submenu);
 | 
								cleanmenu(item->submenu);
 | 
				
			||||||
		tmp = item;
 | 
							tmp = item;
 | 
				
			||||||
		XFreePixmap(dpy, item->unsel);
 | 
							if (menu->drawn) {
 | 
				
			||||||
		if (tmp->label != NULL)
 | 
								XFreePixmap(dpy, item->unsel);
 | 
				
			||||||
			XFreePixmap(dpy, item->sel);
 | 
								if (tmp->label != NULL)
 | 
				
			||||||
 | 
									XFreePixmap(dpy, item->sel);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (tmp->label != tmp->output)
 | 
							if (tmp->label != tmp->output)
 | 
				
			||||||
			free(tmp->label);
 | 
								free(tmp->label);
 | 
				
			||||||
		free(tmp->output);
 | 
							free(tmp->output);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								xmenu.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								xmenu.h
									
									
									
									
									
								
							@@ -77,6 +77,7 @@ struct Menu {
 | 
				
			|||||||
	struct Item *list;      /* list of items contained by the menu */
 | 
						struct Item *list;      /* list of items contained by the menu */
 | 
				
			||||||
	struct Item *selected;  /* item currently selected in the menu */
 | 
						struct Item *selected;  /* item currently selected in the menu */
 | 
				
			||||||
	int x, y, w, h;         /* menu geometry */
 | 
						int x, y, w, h;         /* menu geometry */
 | 
				
			||||||
 | 
						int drawn;              /* whether the menu was already drawn */
 | 
				
			||||||
	unsigned level;         /* menu level relative to root */
 | 
						unsigned level;         /* menu level relative to root */
 | 
				
			||||||
	Window win;             /* menu window to map on the screen */
 | 
						Window win;             /* menu window to map on the screen */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user