bar.c (5518B)
1 /* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail> 2 * See LICENSE file for license details. 3 */ 4 #include "dat.h" 5 #include "fns.h" 6 7 static Handlers handlers; 8 9 #define foreach_bar(s, b) \ 10 for(int __bar_n=0; __bar_n < nelem((s)->bar); __bar_n++) \ 11 for((b)=(s)->bar[__bar_n]; (b); (b)=(b)->next) 12 13 void 14 bar_init(WMScreen *s) { 15 WinAttr wa; 16 17 if(s->barwin && (s->barwin->depth == 32) == s->barwin_rgba) 18 return; 19 20 s->brect = s->r; 21 s->brect.min.y = s->brect.max.y - labelh(def.font); 22 23 wa.override_redirect = 1; 24 wa.event_mask = ExposureMask 25 | ButtonPressMask 26 | ButtonReleaseMask 27 | FocusChangeMask; 28 if(s->barwin_rgba) 29 s->barwin = createwindow_rgba(&scr.root, s->brect, 30 &wa, CWOverrideRedirect 31 | CWEventMask); 32 else 33 s->barwin = createwindow(&scr.root, s->brect, scr.depth, InputOutput, 34 &wa, CWOverrideRedirect 35 | CWEventMask); 36 s->barwin->aux = s; 37 xdnd_initwindow(s->barwin); 38 sethandler(s->barwin, &handlers); 39 if(s == screens[0]) 40 mapwin(s->barwin); 41 } 42 43 void 44 bar_resize(WMScreen *s) { 45 46 s->brect = s->r; 47 s->brect.min.y = s->r.max.y - labelh(def.font); 48 if(s == screens[0]) 49 reshapewin(s->barwin, s->brect); 50 else 51 s->brect.min.y = s->r.max.y; 52 /* FIXME: view_arrange. */ 53 } 54 55 void 56 bar_setbounds(WMScreen *s, int left, int right) { 57 Rectangle *r; 58 59 if(s != screens[0]) 60 return; 61 62 r = &s->brect; 63 r->min.x = left; 64 r->max.x = right; 65 if(Dy(*r)) 66 reshapewin(s->barwin, *r); 67 } 68 69 void 70 bar_sety(WMScreen *s, int y) { 71 Rectangle *r; 72 int dy; 73 74 r = &s->brect; 75 76 dy = Dy(*r); 77 r->min.y = y; 78 r->max.y = y + dy; 79 if(Dy(*r)) 80 reshapewin(s->barwin, *r); 81 } 82 83 Bar* 84 bar_create(Bar **bp, const char *name) { 85 static uint id = 1; 86 WMScreen *s, **sp; 87 Bar *b; 88 uint i; 89 90 b = bar_find(*bp, name);; 91 if(b) 92 return b; 93 94 b = emallocz(sizeof *b); 95 b->id = id++; 96 utflcpy(b->name, name, sizeof b->name); 97 b->colors = def.normcolor; 98 99 strlcat(b->buf, b->colors.colstr, sizeof b->buf); 100 strlcat(b->buf, " ", sizeof b->buf); 101 strlcat(b->buf, b->text, sizeof b->buf); 102 103 SET(i); 104 for(sp=screens; (s = *sp); sp++) { 105 i = bp - s->bar; 106 if(i < nelem(s->bar)) 107 break; 108 } 109 b->bar = i; 110 b->screen = s; 111 112 for(; *bp; bp = &bp[0]->next) 113 if(strcmp(bp[0]->name, name) >= 0) 114 break; 115 b->next = *bp; 116 *bp = b; 117 118 return b; 119 } 120 121 void 122 bar_destroy(Bar **bp, Bar *b) { 123 Bar **p; 124 125 for(p = bp; *p; p = &p[0]->next) 126 if(*p == b) break; 127 *p = b->next; 128 free(b); 129 } 130 131 void 132 bar_draw(WMScreen *s) { 133 Bar *b, *tb, *largest, **pb; 134 Image *ibuf; 135 Rectangle r; 136 Align align; 137 uint width, tw; 138 float shrink; 139 140 /* To do: Generalize this. */ 141 142 largest = nil; 143 width = 0; 144 s->barwin_rgba = false; 145 foreach_bar(s, b) { 146 b->r.min = ZP; 147 b->r.max.y = Dy(s->brect); 148 b->r.max.x = (def.font->height & ~1) + def.font->pad.min.x + def.font->pad.max.x; 149 if(b->text && strlen(b->text)) 150 b->r.max.x += textwidth(def.font, b->text); 151 width += Dx(b->r); 152 s->barwin_rgba += RGBA_P(b->colors); 153 } 154 155 if(width > Dx(s->brect)) { /* Not enough room. Shrink bars until they all fit. */ 156 foreach_bar(s, b) { 157 for(pb=&largest; *pb; pb=&pb[0]->smaller) 158 if(Dx(pb[0]->r) < Dx(b->r)) 159 break; 160 b->smaller = *pb; 161 *pb = b; 162 } 163 SET(shrink); 164 tw = 0; 165 for(tb=largest; tb; tb=tb->smaller) { 166 width -= Dx(tb->r); 167 tw += Dx(tb->r); 168 shrink = (Dx(s->brect) - width) / (float)tw; 169 if(tb->smaller && Dx(tb->r) * shrink < Dx(tb->smaller->r)) 170 continue; 171 if(width + (int)(tw * shrink) <= Dx(s->brect)) 172 break; 173 } 174 if(tb) 175 for(b=largest; b != tb->smaller; b=b->smaller) 176 b->r.max.x *= shrink; 177 width += tw * shrink; 178 } 179 180 if(s->bar[BRight]) 181 s->bar[BRight]->r.max.x += Dx(s->brect) - width; 182 tb = nil; 183 foreach_bar(s, b) { 184 if(tb) 185 b->r = rectaddpt(b->r, Pt(tb->r.max.x, 0)); 186 tb = b; 187 } 188 189 ibuf = s->barwin_rgba ? disp.ibuf32 : disp.ibuf; 190 191 r = rectsubpt(s->brect, s->brect.min); 192 fill(ibuf, r, &def.normcolor.bg); 193 border(ibuf, r, 1, &def.normcolor.border); 194 foreach_bar(s, b) { 195 align = Center; 196 if(b == s->bar[BRight]) 197 align = East; 198 fillstring(ibuf, def.font, b->r, align, b->text, &b->colors, 1); 199 } 200 201 if(s->barwin_rgba != (s->barwin->depth == 32)) 202 bar_init(s); 203 copyimage(s->barwin, r, ibuf, ZP); 204 } 205 206 Bar* 207 bar_find(Bar *bp, const char *name) { 208 Bar *b; 209 210 for(b=bp; b; b=b->next) 211 if(!strcmp(b->name, name)) 212 break; 213 return b; 214 } 215 216 static char *barside[] = { 217 [BLeft] = "Left", 218 [BRight] = "Right", 219 }; 220 221 static Bar* 222 findbar(WMScreen *s, Point p) { 223 Bar *b; 224 225 foreach_bar(s, b) 226 if(rect_haspoint_p(b->r, p)) 227 return b; 228 return nil; 229 } 230 231 static bool 232 bdown_event(Window *w, void *aux, XButtonPressedEvent *e) { 233 WMScreen *s; 234 Bar *b; 235 236 /* Ungrab so a menu can receive events before the button is released */ 237 XUngrabPointer(display, e->time); 238 sync(); 239 240 s = aux; 241 b = findbar(s, Pt(e->x, e->y)); 242 if(b) 243 event("%sBarMouseDown %d %s\n", barside[b->bar], e->button, b->name); 244 return false; 245 } 246 247 static bool 248 bup_event(Window *w, void *aux, XButtonPressedEvent *e) { 249 WMScreen *s; 250 Bar *b; 251 252 s = aux; 253 b = findbar(s, Pt(e->x, e->y)); 254 if(b) 255 event("%sBarClick %d %s\n", barside[b->bar], e->button, b->name); 256 return false; 257 } 258 259 static Rectangle 260 dndmotion_event(Window *w, void *aux, Point p) { 261 WMScreen *s; 262 Bar *b; 263 264 s = aux; 265 b = findbar(s, p); 266 if(b) { 267 event("%sBarDND 1 %s\n", barside[b->bar], b->name); 268 return b->r; 269 } 270 return ZR; 271 } 272 273 static bool 274 expose_event(Window *w, void *aux, XExposeEvent *e) { 275 USED(w, e); 276 bar_draw(aux); 277 return false; 278 } 279 280 static Handlers handlers = { 281 .bdown = bdown_event, 282 .bup = bup_event, 283 .dndmotion = dndmotion_event, 284 .expose = expose_event, 285 }; 286