wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

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