shod

mouse-based window manager that can tile windows inside floating containers
Log | Files | Refs | README | LICENSE

xmenu.c (7516B)


      1 #include "shod.h"
      2 
      3 /* create new menu */
      4 static struct Menu *
      5 menunew(Window win, int x, int y, int w, int h, int ignoreunmap)
      6 {
      7 	struct Menu *menu;
      8 
      9 	menu = emalloc(sizeof(*menu));
     10 	*menu = (struct Menu){
     11 		.titlebar = None,
     12 		.button = None,
     13 		.obj.win = win,
     14 		.obj.type = TYPE_MENU,
     15 		.pix = None,
     16 		.pixbutton = None,
     17 		.pixtitlebar = None,
     18 		.x = x - config.borderwidth,
     19 		.y = y - config.borderwidth,
     20 		.w = w + config.borderwidth * 2,
     21 		.h = h + config.borderwidth * 2 + config.titlewidth,
     22 		.ignoreunmap = ignoreunmap,
     23 	};
     24 	menu->frame = XCreateWindow(dpy, root, 0, 0,
     25 	                            w + config.borderwidth * 2,
     26 	                            h + config.borderwidth * 2 + config.titlewidth, 0,
     27 	                            depth, CopyFromParent, visual,
     28 	                            clientmask, &clientswa),
     29 	menu->titlebar = XCreateWindow(dpy, menu->frame, config.borderwidth, config.borderwidth,
     30 	                               max(1, menu->w - 2 * config.borderwidth - config.titlewidth),
     31 	                               config.titlewidth, 0,
     32 	                               depth, CopyFromParent, visual,
     33 	                               clientmask, &clientswa);
     34 	menu->button = XCreateWindow(dpy, menu->frame, menu->w - config.borderwidth - config.titlewidth, config.borderwidth,
     35 	                             config.titlewidth, config.titlewidth, 0,
     36 	                             depth, CopyFromParent, visual,
     37 	                             clientmask, &clientswa);
     38 	menu->pixbutton = XCreatePixmap(dpy, menu->button, config.titlewidth, config.titlewidth, depth);
     39 	XDefineCursor(dpy, menu->button, wm.cursors[CURSOR_PIRATE]);
     40 	XReparentWindow(dpy, menu->obj.win, menu->frame, config.borderwidth, config.borderwidth + config.titlewidth);
     41 	XMapWindow(dpy, menu->obj.win);
     42 	XMapWindow(dpy, menu->button);
     43 	XMapWindow(dpy, menu->titlebar);
     44 	return menu;
     45 }
     46 
     47 /* remove menu from the menu list */
     48 static void
     49 menudelraise(struct Menu *menu)
     50 {
     51 	if (TAILQ_EMPTY(&wm.menuq))
     52 		return;
     53 	TAILQ_REMOVE(&wm.menuq, (struct Object *)menu, entry);
     54 }
     55 
     56 /* configure menu window */
     57 void
     58 menuconfigure(struct Menu *menu, unsigned int valuemask, XWindowChanges *wc)
     59 {
     60 	if (menu == NULL)
     61 		return;
     62 	if (valuemask & CWX)
     63 		menu->x = wc->x;
     64 	if (valuemask & CWY)
     65 		menu->y = wc->y;
     66 	if (valuemask & CWWidth)
     67 		menu->w = wc->width;
     68 	if (valuemask & CWHeight)
     69 		menu->h = wc->height;
     70 	menumoveresize(menu);
     71 	menudecorate(menu, 0);
     72 }
     73 
     74 static void
     75 menunotify(struct Menu *menu)
     76 {
     77 	winnotify(
     78 		menu->obj.win,
     79 		menu->x + config.borderwidth,
     80 		menu->y + config.borderwidth + config.titlewidth,
     81 		menu->w - config.borderwidth * 2,
     82 		menu->h - config.borderwidth * 2 - config.titlewidth
     83 	);
     84 }
     85 
     86 void
     87 menuincrmove(struct Menu *menu, int x, int y)
     88 {
     89 	menu->x += x;
     90 	menu->y += y;
     91 	//snaptoedge(&menu->x, &menu->y, menu->w, menu->h);
     92 	XMoveWindow(dpy, menu->frame, menu->x, menu->y);
     93 	menunotify(menu);
     94 }
     95 
     96 /* commit menu geometry */
     97 void
     98 menumoveresize(struct Menu *menu)
     99 {
    100 	XMoveResizeWindow(dpy, menu->frame, menu->x, menu->y, menu->w, menu->h);
    101 	XMoveWindow(dpy, menu->button, menu->w - config.borderwidth - config.titlewidth, config.borderwidth);
    102 	XResizeWindow(dpy, menu->titlebar, max(1, menu->w - 2 * config.borderwidth - config.titlewidth), config.titlewidth);
    103 	XResizeWindow(dpy, menu->obj.win, menu->w - 2 * config.borderwidth, menu->h - 2 * config.borderwidth - config.titlewidth);
    104 	menu->mon = getmon(menu->x, menu->y);
    105 	menunotify(menu);
    106 }
    107 
    108 /* decorate menu */
    109 void
    110 menudecorate(struct Menu *menu, int titlepressed)
    111 {
    112 	int tw, th;
    113 
    114 	if (menu->pw != menu->w || menu->ph != menu->h || menu->pix == None)
    115 		pixmapnew(&menu->pix, menu->frame, menu->w, menu->h);
    116 	menu->pw = menu->w;
    117 	menu->ph = menu->h;
    118 	tw = max(1, menu->w - 2 * config.borderwidth - config.titlewidth);
    119 	th = config.titlewidth;
    120 	if (menu->tw != tw || menu->th != th || menu->pixtitlebar == None)
    121 		pixmapnew(&menu->pixtitlebar, menu->titlebar, tw, th);
    122 	menu->tw = tw;
    123 	menu->th = th;
    124 
    125 	drawbackground(menu->pix, 0, 0, menu->w, menu->h, FOCUSED);
    126 	drawborders(menu->pix, menu->w, menu->h, FOCUSED);
    127 
    128 	drawbackground(menu->pixtitlebar, 0, 0, menu->tw, menu->th, FOCUSED);
    129 	drawshadow(menu->pixtitlebar, 0, 0, menu->tw, config.titlewidth, FOCUSED, titlepressed);
    130 	/* write menu title */
    131 	if (menu->name != NULL)
    132 		drawtitle(menu->pixtitlebar, menu->name, menu->tw, 0, FOCUSED, 0, 1);
    133 	buttonrightdecorate(menu->button, menu->pixbutton, FOCUSED, 0);
    134 	drawcommit(menu->pix, menu->frame);
    135 	drawcommit(menu->pixtitlebar, menu->titlebar);
    136 }
    137 
    138 void
    139 menufocus(struct Menu *menu)
    140 {
    141 	XSetInputFocus(dpy, menu->obj.win, RevertToParent, CurrentTime);
    142 }
    143 
    144 /* put menu on beginning of menu list */
    145 void
    146 menufocusraise(struct Menu *menu)
    147 {
    148 	menudelraise(menu);
    149 	TAILQ_INSERT_HEAD(&wm.menuq, (struct Object *)menu, entry);
    150 	menufocus(menu);
    151 }
    152 
    153 /* place menu next to its container */
    154 void
    155 menuplace(struct Monitor *mon, struct Menu *menu)
    156 {
    157 	fitmonitor(mon, &menu->x, &menu->y, &menu->w, &menu->h, 1.0);
    158 	menumoveresize(menu);
    159 }
    160 
    161 /* raise desktop menu */
    162 void
    163 menuraise(struct Menu *menu)
    164 {
    165 	Window wins[2];
    166 
    167 	wins[1] = menu->frame;
    168 	wins[0] = wm.layers[LAYER_MENU].frame;
    169 	XRestackWindows(dpy, wins, 2);
    170 }
    171 
    172 /* (un)hide menu */
    173 void
    174 menuhide(struct Menu *menu, int hide)
    175 {
    176 	if (hide)
    177 		XUnmapWindow(dpy, menu->frame);
    178 	else
    179 		XMapWindow(dpy, menu->frame);
    180 	icccmwmstate(menu->obj.win, (hide ? IconicState : NormalState));
    181 }
    182 
    183 /* assign menu to tab */
    184 void
    185 managemenu(struct Tab *tab, struct Monitor *mon, int desk, Window win, Window leader, XRectangle rect, int state, int ignoreunmap)
    186 {
    187 	struct Menu *menu;
    188 
    189 	(void)tab;
    190 	(void)mon;
    191 	(void)desk;
    192 	(void)state;
    193 	menu = menunew(win, rect.x, rect.y, rect.width, rect.height, ignoreunmap);
    194 	menu->leader = leader;
    195 	winupdatetitle(menu->obj.win, &menu->name);
    196 	TAILQ_INSERT_HEAD(&wm.menuq, (struct Object *)menu, entry);
    197 	icccmwmstate(menu->obj.win, NormalState);
    198 	menuplace(mon, menu);           /* this will set menu->mon for us */
    199 	menudecorate(menu, 0);
    200 	menuraise(menu);
    201 	if (menu->leader == None ||
    202 	    (wm.focused != NULL &&
    203 	     istabformenu(wm.focused->selcol->selrow->seltab, menu))) {
    204 		XMapWindow(dpy, menu->frame);
    205 		menufocus(menu);
    206 	}
    207 }
    208 
    209 /* delete menu; return whether menu was deleted */
    210 int
    211 unmanagemenu(struct Object *obj, int ignoreunmap)
    212 {
    213 	struct Menu *menu;
    214 
    215 	menu = (struct Menu *)obj;
    216 	if (ignoreunmap && menu->ignoreunmap) {
    217 		menu->ignoreunmap--;
    218 		return 0;
    219 	}
    220 	menudelraise(menu);
    221 	if (menu->pix != None)
    222 		XFreePixmap(dpy, menu->pix);
    223 	if (menu->pixbutton != None)
    224 		XFreePixmap(dpy, menu->pixbutton);
    225 	if (menu->pixtitlebar != None)
    226 		XFreePixmap(dpy, menu->pixtitlebar);
    227 	icccmdeletestate(menu->obj.win);
    228 	XReparentWindow(dpy, menu->obj.win, root, 0, 0);
    229 	XDestroyWindow(dpy, menu->frame);
    230 	XDestroyWindow(dpy, menu->titlebar);
    231 	XDestroyWindow(dpy, menu->button);
    232 	free(menu->name);
    233 	free(menu);
    234 	return 1;
    235 }
    236 
    237 /* check if given tab accepts given menu */
    238 int
    239 istabformenu(struct Tab *tab, struct Menu *menu)
    240 {
    241 	return (menu->leader == tab->obj.win || menu->leader == tab->leader);
    242 }
    243 
    244 /* map menus for current focused tab */
    245 void
    246 menuupdate(void)
    247 {
    248 	struct Object *obj;
    249 	struct Menu *menu;
    250 
    251 	TAILQ_FOREACH(obj, &wm.menuq, entry) {
    252 		menu = ((struct Menu *)obj);
    253 		if (menu->leader == None)
    254 			continue;
    255 		if (!wm.showingdesk && wm.focused != NULL && istabformenu(wm.focused->selcol->selrow->seltab, menu)) {
    256 			XMapWindow(dpy, menu->frame);
    257 			icccmwmstate(obj->win, NormalState);
    258 		} else {
    259 			XUnmapWindow(dpy, ((struct Menu *)obj)->frame);
    260 			icccmwmstate(obj->win, IconicState);
    261 		}
    262 	}
    263 }