Skip to content

Commit 6d038f5

Browse files
committed
anti-aliased graphics for lines and slices
1 parent 6a416d8 commit 6d038f5

File tree

5 files changed

+164
-87
lines changed

5 files changed

+164
-87
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ all: ${PROG}
88
${PROG}: ${OBJS}
99
${CC} -o $@ ${OBJS} ${LDFLAGS}
1010

11-
${OBJS}: config.h
11+
${OBJS}: ${PROG}.h config.h
1212

1313
.c.o:
1414
${CC} ${CFLAGS} -c $<

config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ static struct Config config = {
1717

1818
/* the values below cannot be set via X resources */
1919

20-
/* sizes from 0 to 1 */
20+
/* sizes between 0 and 1 */
2121
.separatorbeg = 0.14, /* beginning of the separator */
2222
.separatorend = 0.37 /* end of the separator */
2323
};

config.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ FREETYPEINC = /usr/include/freetype2
1717

1818
# includes and libs
1919
INCS = -I${LOCALINC} -I${X11INC} -I${FREETYPEINC}
20-
LIBS = -L${LOCALLIB} -L${X11LIB} -lm -lfontconfig -lXft -lX11 -lXinerama -lXext -lImlib2
20+
LIBS = -L${LOCALLIB} -L${X11LIB} -lm -lfontconfig -lXft -lX11 -lXinerama -lXrender -lXext -lImlib2
2121

2222
# flags
2323
CPPFLAGS =

pmenu.c

Lines changed: 147 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ static Visual *visual;
2222
static Window rootwin;
2323
static Colormap colormap;
2424
static XrmDatabase xdb;
25+
static XRenderPictFormat *xformat;
2526
static char *xrm;
2627
static int screen;
2728
static int depth;
@@ -173,6 +174,7 @@ static void
173174
initdc(void)
174175
{
175176
XGCValues values;
177+
Pixmap pbg, pselbg, separator;
176178
unsigned long valuemask;
177179

178180
/* get color pixels */
@@ -191,6 +193,22 @@ initdc(void)
191193
values.line_width = config.separator_pixels;
192194
valuemask = GCLineWidth | GCArcMode;
193195
dc.gc = XCreateGC(dpy, rootwin, valuemask, &values);
196+
197+
/* create color source Pictures */
198+
dc.pictattr.repeat = 1;
199+
dc.pictattr.poly_edge = PolyEdgeSmooth;
200+
pbg = XCreatePixmap(dpy, rootwin, 1, 1, depth);
201+
pselbg = XCreatePixmap(dpy, rootwin, 1, 1, depth);
202+
separator = XCreatePixmap(dpy, rootwin, 1, 1, depth);
203+
pie.bg = XRenderCreatePicture(dpy, pbg, xformat, CPRepeat, &dc.pictattr);
204+
pie.selbg = XRenderCreatePicture(dpy, pselbg, xformat, CPRepeat, &dc.pictattr);
205+
pie.separator = XRenderCreatePicture(dpy, separator, xformat, CPRepeat, &dc.pictattr);
206+
XRenderFillRectangle(dpy, PictOpOver, pie.bg, &dc.normal[ColorBG].color, 0, 0, 1, 1);
207+
XRenderFillRectangle(dpy, PictOpOver, pie.selbg, &dc.selected[ColorBG].color, 0, 0, 1, 1);
208+
XRenderFillRectangle(dpy, PictOpOver, pie.separator, &dc.separator.color, 0, 0, 1, 1);
209+
XFreePixmap(dpy, pbg);
210+
XFreePixmap(dpy, pselbg);
211+
XFreePixmap(dpy, separator);
194212
}
195213

196214
/* setup pie */
@@ -207,12 +225,10 @@ initpie(void)
207225
pie.fulldiameter = pie.diameter + (pie.border * 2);
208226

209227
/* set the separator beginning and end */
210-
pie.separatorbeg = config.separatorbeg;
211-
pie.separatorend = config.separatorend;
212-
213-
/* set the inner circle position */
214-
pie.innercircley = pie.innercirclex = pie.radius - pie.radius * pie.separatorbeg;
215-
pie.innercirclediameter = (pie.radius * pie.separatorbeg) * 2;
228+
pie.separatorbeg = pie.radius * config.separatorbeg;
229+
pie.separatorend = pie.radius * config.separatorend;
230+
pie.innerangle = atan(config.separator_pixels / (2.0 * pie.separatorbeg));
231+
pie.outerangle = atan(config.separator_pixels / (2.0 * pie.separatorend));
216232

217233
/* Create a simple bitmap mask (depth = 1) */
218234
pie.clip = XCreatePixmap(dpy, rootwin, pie.diameter, pie.diameter, 1);
@@ -320,7 +336,10 @@ allocmenu(struct Menu *parent, struct Slice *list, unsigned level)
320336
menu->x = 0; /* calculated by setupmenu() */
321337
menu->y = 0; /* calculated by setupmenu() */
322338
menu->level = level;
339+
340+
/* create pixmap and picture */
323341
menu->pixmap = XCreatePixmap(dpy, menu->win, pie.diameter, pie.diameter, depth);
342+
menu->picture = XRenderCreatePicture(dpy, menu->pixmap, xformat, CPPolyEdge | CPRepeat, &dc.pictattr);
324343
menu->drawn = 0;
325344

326345
return menu;
@@ -640,78 +659,58 @@ static void
640659
setslices(struct Menu *menu)
641660
{
642661
struct Slice *slice;
643-
double anglerad; /* angle in radians */
662+
double a = 0.0;
644663
unsigned n = 0;
645-
int angle = 0;
646664
int textwidth;
647665

648-
menu->halfslice = (360 * 64) / (menu->nslices * 2);
666+
menu->half = M_PI / menu->nslices;
649667
for (slice = menu->list; slice; slice = slice->next) {
650-
n++;
668+
slice->slicen = n++;
651669

652-
slice->angle1 = angle - menu->halfslice;
653-
if (slice->angle1 < 0)
654-
slice->angle1 += 360 * 64;
655-
slice->angle2 = menu->halfslice * 2;
670+
slice->anglea = a - menu->half;
671+
slice->angleb = a + menu->half;
656672

657673
/* get length of slice->label rendered in the font */
658674
textwidth = (slice->label) ? drawtext(NULL, NULL, 0, 0, slice->label): 0;
659675

660-
/* anglerad is now the angle in radians of the middle of the slice */
661-
anglerad = (angle * M_PI) / (180 * 64);
662-
663676
/* get position of slice's label */
664-
slice->labelx = pie.radius + ((pie.radius*2)/3 * cos(anglerad)) - (textwidth / 2);
665-
slice->labely = pie.radius - ((pie.radius*2)/3 * sin(anglerad));
677+
slice->labelx = pie.radius + ((pie.radius*2)/3 * cos(a)) - (textwidth / 2);
678+
slice->labely = pie.radius - ((pie.radius*2)/3 * sin(a));
666679

667680
/* get position of submenu */
668-
slice->x = pie.radius + (pie.diameter * (cos(anglerad) * 0.9));
669-
slice->y = pie.radius - (pie.diameter * (sin(anglerad) * 0.9));
681+
slice->x = pie.radius + (pie.diameter * (cos(a) * 0.9));
682+
slice->y = pie.radius - (pie.diameter * (sin(a) * 0.9));
670683

671684
/* create icon */
672685
if (slice->file != NULL) {
673686
int maxiconsize = (pie.radius + 1) / 2;
674-
double sliceanglerad; /* inner angle of a slice */
675687
int iconw, iconh; /* icon width and height */
676688
int iconsize; /* requested icon size */
677689
int xdiff, ydiff;
678690

679-
sliceanglerad = (slice->angle2 * M_PI) / (180 * 64);
680-
681-
xdiff = pie.radius * 0.5 - (pie.radius * (cos(sliceanglerad) * 0.5));
682-
ydiff = pie.radius * (sin(sliceanglerad) * 0.5);
691+
xdiff = pie.radius * 0.5 - (pie.radius * (cos(menu->half) * 0.75));
692+
ydiff = pie.radius * (sin(menu->half) * 0.75);
683693

684694
iconsize = sqrt(xdiff * xdiff + ydiff * ydiff);
685695
iconsize = MIN(maxiconsize, iconsize);
686696

687697
slice->icon = loadicon(slice->file, iconsize, &iconw, &iconh);
688698

689-
slice->iconx = pie.radius + (pie.radius * (cos(anglerad) * 0.6)) - iconw / 2;
690-
slice->icony = pie.radius - (pie.radius * (sin(anglerad) * 0.6)) - iconh / 2;
699+
slice->iconx = pie.radius + (pie.radius * (cos(a) * 0.6)) - iconw / 2;
700+
slice->icony = pie.radius - (pie.radius * (sin(a) * 0.6)) - iconh / 2;
691701
}
692702

693-
/* anglerad is now the angle in radians of angle1 */
694-
anglerad = (slice->angle1 * M_PI) / (180 * 64);
695-
696-
/* set position of the line segment separating slices */
697-
slice->linexi = pie.radius + pie.radius * (cos(anglerad) * pie.separatorbeg);
698-
slice->lineyi = pie.radius + pie.radius * (sin(anglerad) * pie.separatorbeg);
699-
slice->linexo = pie.radius + pie.radius * (cos(anglerad) * pie.separatorend);
700-
slice->lineyo = pie.radius + pie.radius * (sin(anglerad) * pie.separatorend);
701-
if (abs(slice->linexo - slice->linexi) <= 2)
702-
slice->linexo = slice->linexi;
703-
704-
/* set position of the icon */
705-
angle = (360 * 64 * n) / menu->nslices;
706-
707703
/* create and draw pixmap */
708704
slice->pixmap = XCreatePixmap(dpy, menu->win, pie.diameter, pie.diameter, depth);
705+
slice->picture = XRenderCreatePicture(dpy, slice->pixmap, xformat, CPPolyEdge | CPRepeat, &dc.pictattr);
709706
slice->drawn = 0;
710707

711708
/* call recursivelly */
712709
if (slice->submenu != NULL) {
713710
setslices(slice->submenu);
714711
}
712+
713+
a += menu->half * 2;
715714
}
716715
}
717716

@@ -847,8 +846,7 @@ static struct Slice *
847846
getslice(struct Menu *menu, int x, int y)
848847
{
849848
struct Slice *slice;
850-
double phi;
851-
int angle;
849+
double angle;
852850
int r;
853851

854852
if (menu == NULL)
@@ -860,18 +858,17 @@ getslice(struct Menu *menu, int x, int y)
860858

861859
/* if the cursor is in the middle circle, it is in no slice */
862860
r = sqrt(x * x + y * y);
863-
if (r <= pie.radius * pie.separatorbeg)
861+
if (r <= pie.separatorbeg)
864862
return NULL;
865863

866-
phi = atan2(y, x);
867-
if (y < 0)
868-
phi += 2 * M_PI;
869-
angle = ((phi * 180 * 64) / M_PI);
870-
871-
if (angle < menu->halfslice)
872-
return menu->list;
873-
for (slice = menu->list; slice != NULL; slice = slice->next)
874-
if (angle >= slice->angle1 && angle < slice->angle1 + slice->angle2)
864+
angle = atan2(y, x);
865+
if (angle < 0.0) {
866+
if (angle > -menu->half)
867+
return menu->list;
868+
angle = (2 * M_PI) + angle;
869+
}
870+
for (slice = menu->list; slice; slice = slice->next)
871+
if (angle >= slice->anglea && angle < slice->angleb)
875872
return slice;
876873

877874
return NULL;
@@ -941,6 +938,92 @@ unmapmenu(struct Menu *currmenu)
941938
}
942939
}
943940

941+
/* draw background of selected slice */
942+
static void
943+
drawslice(struct Menu *menu, struct Slice *slice)
944+
{
945+
XPointDouble *p;
946+
int i, n;
947+
double hd, a, b, c;
948+
949+
if (slice == NULL)
950+
return;
951+
952+
/* determine number of segments to draw */
953+
hd = hypot(pie.radius, pie.radius)/2;
954+
n = ((2 * M_PI) / (menu->nslices * acos(hd/(hd+1.0)))) + 0.5;
955+
956+
/* angles */
957+
a = ((2 * M_PI) / (menu->nslices * n));
958+
b = ((2 * M_PI) / menu->nslices);
959+
c = b * slice->slicen;
960+
961+
p = emalloc((n + 2) * sizeof *p);
962+
p[0].x = pie.radius;
963+
p[0].y = pie.radius;
964+
for (i = 0; i < n + 1; i++) {
965+
p[i+1].x = pie.radius + (pie.radius + 1) * cos((i - (n / 2.0)) * a - c);
966+
p[i+1].y = pie.radius + (pie.radius + 1) * sin((i - (n / 2.0)) * a - c);
967+
}
968+
969+
XRenderCompositeDoublePoly(dpy, PictOpOver, pie.selbg, slice->picture,
970+
XRenderFindStandardFormat(dpy, PictStandardA8),
971+
0, 0, 0, 0, p, n + 2, 0);
972+
973+
free(p);
974+
}
975+
976+
/* draw circle */
977+
static void
978+
drawcircle(Picture picture, int radius)
979+
{
980+
XPointDouble *p;
981+
int i, n;
982+
double hd, a;
983+
984+
/* determine number of segments to draw */
985+
hd = hypot(radius, radius)/2;
986+
n = ((2 * M_PI) / (acos(hd/(hd+1.0)))) + 0.5;
987+
988+
/* angles */
989+
a = ((2 * M_PI) / n);
990+
991+
p = emalloc((n + 2) * sizeof *p);
992+
p[0].x = pie.radius;
993+
p[0].y = pie.radius;
994+
for (i = 0; i < n + 1; i++) {
995+
p[i+1].x = pie.radius + (radius + 1) * cos(i * a);
996+
p[i+1].y = pie.radius + (radius + 1) * sin(i * a);
997+
}
998+
999+
XRenderCompositeDoublePoly(dpy, PictOpOver, pie.bg, picture,
1000+
XRenderFindStandardFormat(dpy, PictStandardA8),
1001+
0, 0, 0, 0, p, n + 2, 0);
1002+
1003+
free(p);
1004+
}
1005+
1006+
/* draw separator before slice */
1007+
static void
1008+
drawseparator(Picture picture, struct Menu *menu, struct Slice *slice)
1009+
{
1010+
XPointDouble p[4];
1011+
double a;
1012+
1013+
a = (M_PI / menu->nslices) + ((2 * M_PI) / menu->nslices) * slice->slicen;
1014+
p[0].x = pie.radius + pie.separatorbeg * cos(a - pie.innerangle);
1015+
p[0].y = pie.radius + pie.separatorbeg * sin(a - pie.innerangle);
1016+
p[1].x = pie.radius + pie.separatorbeg * cos(a + pie.innerangle);
1017+
p[1].y = pie.radius + pie.separatorbeg * sin(a + pie.innerangle);
1018+
p[2].x = pie.radius + pie.separatorend * cos(a + pie.outerangle);
1019+
p[2].y = pie.radius + pie.separatorend * sin(a + pie.outerangle);
1020+
p[3].x = pie.radius + pie.separatorend * cos(a - pie.outerangle);
1021+
p[3].y = pie.radius + pie.separatorend * sin(a - pie.outerangle);
1022+
XRenderCompositeDoublePoly(dpy, PictOpOver, pie.separator, picture,
1023+
XRenderFindStandardFormat(dpy, PictStandardA8),
1024+
0, 0, 0, 0, p, 4, 0);
1025+
}
1026+
9441027
/* draw regular slice */
9451028
static void
9461029
drawmenu(struct Menu *menu, struct Slice *selected)
@@ -949,27 +1032,22 @@ drawmenu(struct Menu *menu, struct Slice *selected)
9491032
XftColor *color;
9501033
XftDraw *draw;
9511034
Drawable pixmap;
1035+
Picture picture;
9521036

9531037
if (selected) {
9541038
pixmap = selected->pixmap;
1039+
picture = selected->picture;
9551040
selected->drawn = 1;
9561041
} else {
9571042
pixmap = menu->pixmap;
1043+
picture = menu->picture;
9581044
menu->drawn = 1;
9591045
}
9601046

961-
/* draw slice background */
962-
for (slice = menu->list; slice; slice = slice->next) {
963-
if (slice == selected)
964-
color = dc.selected;
965-
else
966-
color = dc.normal;
967-
968-
XSetForeground(dpy, dc.gc, color[ColorBG].pixel);
969-
XFillArc(dpy, pixmap, dc.gc, 0, 0,
970-
pie.diameter, pie.diameter,
971-
slice->angle1, slice->angle2);
972-
}
1047+
/* draw background */
1048+
XSetForeground(dpy, dc.gc, dc.normal[ColorBG].pixel);
1049+
XFillRectangle(dpy, pixmap, dc.gc, 0, 0, pie.diameter, pie.diameter);
1050+
drawslice(menu, selected);
9731051

9741052
/* draw slice foreground */
9751053
for (slice = menu->list; slice; slice = slice->next) {
@@ -991,18 +1069,11 @@ drawmenu(struct Menu *menu, struct Slice *selected)
9911069
}
9921070

9931071
/* draw separator */
994-
XSetForeground(dpy, dc.gc, dc.separator.pixel);
995-
XDrawLine(dpy, pixmap, dc.gc,
996-
slice->linexi, slice->lineyi,
997-
slice->linexo, slice->lineyo);
1072+
drawseparator(picture, menu, slice);
9981073
}
9991074

10001075
/* draw inner circle */
1001-
XSetForeground(dpy, dc.gc, dc.normal[ColorBG].pixel);
1002-
XFillArc(dpy, pixmap, dc.gc,
1003-
pie.innercirclex, pie.innercircley,
1004-
pie.innercirclediameter, pie.innercirclediameter,
1005-
0, 360 * 64);
1076+
drawcircle(picture, pie.separatorbeg);
10061077
}
10071078

10081079
/* draw slices of the current menu and of its ancestors */
@@ -1273,6 +1344,7 @@ main(int argc, char *argv[])
12731344
rootwin = RootWindow(dpy, screen);
12741345
colormap = DefaultColormap(dpy, screen);
12751346
depth = DefaultDepth(dpy, screen);
1347+
xformat = XRenderFindVisualFormat(dpy, visual);
12761348
if ((xrm = XResourceManagerString(dpy)) != NULL)
12771349
xdb = XrmGetStringDatabase(xrm);
12781350

0 commit comments

Comments
 (0)