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 }