use Xft to draw strings
This commit is contained in:
@@ -3,7 +3,7 @@ CFLAGS=-Wall -g -pthread -DT_TRACER -I.
|
|||||||
|
|
||||||
#CFLAGS += -O3 -ffast-math -fomit-frame-pointer
|
#CFLAGS += -O3 -ffast-math -fomit-frame-pointer
|
||||||
|
|
||||||
LIBS=-lX11 -lm -lpng
|
LIBS=-lX11 -lm -lpng -lXft
|
||||||
|
|
||||||
tracer_remote: remote_old.o plot.o database.o gui.o utils.o gui/gui.a
|
tracer_remote: remote_old.o plot.o database.o gui.o utils.o gui/gui.a
|
||||||
$(CC) $(CFLAGS) -o tracer_remote $^ $(LIBS)
|
$(CC) $(CFLAGS) -o tracer_remote $^ $(LIBS)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-Wall -g -pthread
|
CFLAGS=-Wall -g -pthread -I/usr/include/X11/Xft -I/usr/include/freetype2
|
||||||
|
|
||||||
OBJS=init.o loop.o toplevel_window.o x.o container.o widget.o \
|
OBJS=init.o loop.o toplevel_window.o x.o container.o widget.o \
|
||||||
gui.o label.o event.o xy_plot.o textlist.o notify.o positioner.o \
|
gui.o label.o event.o xy_plot.o textlist.o notify.o positioner.o \
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ typedef void widget;
|
|||||||
#define BACKGROUND_COLOR 0
|
#define BACKGROUND_COLOR 0
|
||||||
#define FOREGROUND_COLOR 1
|
#define FOREGROUND_COLOR 1
|
||||||
|
|
||||||
|
#define DEFAULT_FONT 0
|
||||||
|
|
||||||
/* key modifiers */
|
/* key modifiers */
|
||||||
#define KEY_SHIFT (1<<0)
|
#define KEY_SHIFT (1<<0)
|
||||||
#define KEY_CONTROL (1<<1)
|
#define KEY_CONTROL (1<<1)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ static void paint(gui *_gui, widget *_w)
|
|||||||
struct gui *g = _gui;
|
struct gui *g = _gui;
|
||||||
struct label_widget *l = _w;
|
struct label_widget *l = _w;
|
||||||
LOGD("PAINT label '%s'\n", l->t);
|
LOGD("PAINT label '%s'\n", l->t);
|
||||||
x_draw_string(g->x, g->xwin, l->color,
|
x_draw_string(g->x, g->xwin, DEFAULT_FONT, l->color,
|
||||||
l->common.x, l->common.y + l->baseline, l->t);
|
l->common.x, l->common.y + l->baseline, l->t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +35,8 @@ widget *new_label(gui *_gui, const char *label)
|
|||||||
if (w->t == NULL) OOM;
|
if (w->t == NULL) OOM;
|
||||||
w->color = FOREGROUND_COLOR;
|
w->color = FOREGROUND_COLOR;
|
||||||
|
|
||||||
x_text_get_dimensions(g->x, label, &w->width, &w->height, &w->baseline);
|
x_text_get_dimensions(g->x, DEFAULT_FONT, label,
|
||||||
|
&w->width, &w->height, &w->baseline);
|
||||||
|
|
||||||
w->common.paint = paint;
|
w->common.paint = paint;
|
||||||
w->common.hints = hints;
|
w->common.hints = hints;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ static void paint(gui *_gui, widget *_this)
|
|||||||
this->common.width, this->common.height);
|
this->common.width, this->common.height);
|
||||||
for (i = 0, j = this->starting_line;
|
for (i = 0, j = this->starting_line;
|
||||||
i < this->allocated_nlines && j < this->text_count; i++, j++)
|
i < this->allocated_nlines && j < this->text_count; i++, j++)
|
||||||
x_draw_clipped_string(g->x, g->xwin, this->color[j],
|
x_draw_clipped_string(g->x, g->xwin, DEFAULT_FONT, this->color[j],
|
||||||
this->common.x,
|
this->common.x,
|
||||||
this->common.y + i * this->line_height + this->baseline,
|
this->common.y + i * this->line_height + this->baseline,
|
||||||
this->text[j],
|
this->text[j],
|
||||||
@@ -79,7 +79,8 @@ widget *new_textlist(gui *_gui, int width, int nlines, int bgcol)
|
|||||||
w = new_widget(g, TEXT_LIST, sizeof(struct textlist_widget));
|
w = new_widget(g, TEXT_LIST, sizeof(struct textlist_widget));
|
||||||
|
|
||||||
w->wanted_nlines = nlines;
|
w->wanted_nlines = nlines;
|
||||||
x_text_get_dimensions(g->x, ".", &dummy, &w->line_height, &w->baseline);
|
x_text_get_dimensions(g->x, DEFAULT_FONT, ".",
|
||||||
|
&dummy, &w->line_height, &w->baseline);
|
||||||
w->background_color = bgcol;
|
w->background_color = bgcol;
|
||||||
w->wanted_width = width;
|
w->wanted_width = width;
|
||||||
|
|
||||||
|
|||||||
@@ -33,12 +33,34 @@ int x_new_color(x_connection *_x, char *color)
|
|||||||
{
|
{
|
||||||
struct x_connection *x = _x;
|
struct x_connection *x = _x;
|
||||||
x->ncolors++;
|
x->ncolors++;
|
||||||
|
|
||||||
x->colors = realloc(x->colors, x->ncolors * sizeof(GC));
|
x->colors = realloc(x->colors, x->ncolors * sizeof(GC));
|
||||||
if (x->colors == NULL) OOM;
|
if (x->colors == NULL) OOM;
|
||||||
x->colors[x->ncolors-1] = create_gc(x->d, color);
|
x->colors[x->ncolors-1] = create_gc(x->d, color);
|
||||||
|
|
||||||
|
x->xft_colors = realloc(x->xft_colors, x->ncolors * sizeof(XftColor));
|
||||||
|
if (x->xft_colors == NULL) OOM;
|
||||||
|
if (XftColorAllocName(x->d, DefaultVisual(x->d, DefaultScreen(x->d)),
|
||||||
|
DefaultColormap(x->d, DefaultScreen(x->d)),
|
||||||
|
color, &x->xft_colors[x->ncolors-1]) == False)
|
||||||
|
ERR("could not allocate color '%s'\n", color);
|
||||||
|
|
||||||
return x->ncolors - 1;
|
return x->ncolors - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int x_new_font(x_connection *_x, char *font)
|
||||||
|
{
|
||||||
|
struct x_connection *x = _x;
|
||||||
|
/* TODO: allocate fonts only once */
|
||||||
|
x->nfonts++;
|
||||||
|
x->fonts = realloc(x->fonts, x->nfonts * sizeof(XftFont *));
|
||||||
|
if (x->fonts == NULL) OOM;
|
||||||
|
x->fonts[x->nfonts-1] = XftFontOpenName(x->d, DefaultScreen(x->d), font);
|
||||||
|
if (x->fonts[x->nfonts-1] == NULL)
|
||||||
|
ERR("failed allocating font '%s'\n", font);
|
||||||
|
return x->nfonts - 1;
|
||||||
|
}
|
||||||
|
|
||||||
x_connection *x_open(void)
|
x_connection *x_open(void)
|
||||||
{
|
{
|
||||||
struct x_connection *ret;
|
struct x_connection *ret;
|
||||||
@@ -53,6 +75,8 @@ x_connection *x_open(void)
|
|||||||
x_new_color(ret, "white"); /* background color */
|
x_new_color(ret, "white"); /* background color */
|
||||||
x_new_color(ret, "black"); /* foreground color */
|
x_new_color(ret, "black"); /* foreground color */
|
||||||
|
|
||||||
|
x_new_font(ret, "sans-8");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,6 +102,11 @@ x_window *x_create_window(x_connection *_x, int width, int height,
|
|||||||
XFillRectangle(x->d, ret->p, x->colors[BACKGROUND_COLOR],
|
XFillRectangle(x->d, ret->p, x->colors[BACKGROUND_COLOR],
|
||||||
0, 0, width, height);
|
0, 0, width, height);
|
||||||
|
|
||||||
|
ret->xft = XftDrawCreate(x->d, ret->p,
|
||||||
|
DefaultVisual(x->d, DefaultScreen(x->d)),
|
||||||
|
DefaultColormap(x->d, DefaultScreen(x->d)));
|
||||||
|
if (ret->xft == NULL) ERR("XftDrawCreate failed\n");
|
||||||
|
|
||||||
/* enable backing store */
|
/* enable backing store */
|
||||||
{
|
{
|
||||||
XSetWindowAttributes att;
|
XSetWindowAttributes att;
|
||||||
@@ -261,11 +290,17 @@ void x_events(gui *_gui)
|
|||||||
w->common.allocate(g, w, 0, 0, xw->new_width, xw->new_height);
|
w->common.allocate(g, w, 0, 0, xw->new_width, xw->new_height);
|
||||||
xw->width = xw->new_width;
|
xw->width = xw->new_width;
|
||||||
xw->height = xw->new_height;
|
xw->height = xw->new_height;
|
||||||
|
XftDrawDestroy(xw->xft);
|
||||||
XFreePixmap(x->d, xw->p);
|
XFreePixmap(x->d, xw->p);
|
||||||
xw->p = XCreatePixmap(x->d, xw->w, xw->width, xw->height,
|
xw->p = XCreatePixmap(x->d, xw->w, xw->width, xw->height,
|
||||||
DefaultDepth(x->d, DefaultScreen(x->d)));
|
DefaultDepth(x->d, DefaultScreen(x->d)));
|
||||||
XFillRectangle(x->d, xw->p, x->colors[BACKGROUND_COLOR],
|
XFillRectangle(x->d, xw->p, x->colors[BACKGROUND_COLOR],
|
||||||
0, 0, xw->width, xw->height);
|
0, 0, xw->width, xw->height);
|
||||||
|
xw->xft = XftDrawCreate(x->d, xw->p,
|
||||||
|
DefaultVisual(x->d, DefaultScreen(x->d)),
|
||||||
|
DefaultColormap(x->d, DefaultScreen(x->d)));
|
||||||
|
if (xw->xft == NULL) ERR("XftDrawCreate failed\n");
|
||||||
|
|
||||||
//xw->repaint = 1;
|
//xw->repaint = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,24 +325,17 @@ void x_flush(x_connection *_x)
|
|||||||
XFlush(x->d);
|
XFlush(x->d);
|
||||||
}
|
}
|
||||||
|
|
||||||
void x_text_get_dimensions(x_connection *_c, const char *t,
|
void x_text_get_dimensions(x_connection *_c, int font, const char *t,
|
||||||
int *width, int *height, int *baseline)
|
int *width, int *height, int *baseline)
|
||||||
{
|
{
|
||||||
struct x_connection *c = _c;
|
struct x_connection *c = _c;
|
||||||
int dir;
|
XGlyphInfo ext;
|
||||||
int ascent;
|
|
||||||
int descent;
|
|
||||||
XCharStruct overall;
|
|
||||||
|
|
||||||
/* TODO: don't use XQueryTextExtents (X roundtrip) */
|
XftTextExtents8(c->d, c->fonts[font], (FcChar8 *)t, strlen(t), &ext);
|
||||||
XQueryTextExtents(c->d, XGContextFromGC(c->colors[1]), t, strlen(t),
|
|
||||||
&dir, &ascent, &descent, &overall);
|
|
||||||
|
|
||||||
//LOGD("dir %d ascent %d descent %d lbearing %d rbearing %d width %d ascent %d descent %d\n", dir, ascent, descent, overall.lbearing, overall.rbearing, overall.width, overall.ascent, overall.descent);
|
*width = ext.width;
|
||||||
|
*height = c->fonts[font]->height;
|
||||||
*width = overall.width;
|
*baseline = c->fonts[font]->ascent;
|
||||||
*height = ascent + descent;
|
|
||||||
*baseline = ascent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
@@ -338,25 +366,26 @@ void x_fill_rectangle(x_connection *_c, x_window *_w, int color,
|
|||||||
XFillRectangle(c->d, w->p, c->colors[color], x, y, width, height);
|
XFillRectangle(c->d, w->p, c->colors[color], x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
void x_draw_string(x_connection *_c, x_window *_w, int color,
|
void x_draw_string(x_connection *_c, x_window *_w, int font, int color,
|
||||||
int x, int y, const char *t)
|
int x, int y, const char *t)
|
||||||
{
|
{
|
||||||
struct x_connection *c = _c;
|
struct x_connection *c = _c;
|
||||||
struct x_window *w = _w;
|
struct x_window *w = _w;
|
||||||
int tlen = strlen(t);
|
int tlen = strlen(t);
|
||||||
XDrawString(c->d, w->p, c->colors[color], x, y, t, tlen);
|
XftDrawString8(w->xft, &c->xft_colors[color], c->fonts[font],
|
||||||
|
x, y, (const unsigned char *)t, tlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
void x_draw_clipped_string(x_connection *_c, x_window *_w, int color,
|
void x_draw_clipped_string(x_connection *_c, x_window *_w, int font,
|
||||||
int x, int y, const char *t,
|
int color, int x, int y, const char *t,
|
||||||
int clipx, int clipy, int clipwidth, int clipheight)
|
int clipx, int clipy, int clipwidth, int clipheight)
|
||||||
{
|
{
|
||||||
struct x_connection *c = _c;
|
struct x_window *w = _w;
|
||||||
|
|
||||||
XRectangle clip = { clipx, clipy, clipwidth, clipheight };
|
XRectangle clip = { clipx, clipy, clipwidth, clipheight };
|
||||||
XSetClipRectangles(c->d, c->colors[color], 0, 0, &clip, 1, Unsorted);
|
if (XftDrawSetClipRectangles(w->xft, 0, 0, &clip, 1) == False) abort();
|
||||||
x_draw_string(_c, _w, color, x, y, t);
|
x_draw_string(_c, _w, font, color, x, y, t);
|
||||||
XSetClipMask(c->d, c->colors[color], None);
|
if (XftDrawSetClip(w->xft, NULL) == False) abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void x_draw_image(x_connection *_c, x_window *_w, x_image *_img, int x, int y)
|
void x_draw_image(x_connection *_c, x_window *_w, x_image *_img, int x, int y)
|
||||||
|
|||||||
@@ -20,12 +20,13 @@ int x_connection_fd(x_connection *x);
|
|||||||
void x_flush(x_connection *x);
|
void x_flush(x_connection *x);
|
||||||
|
|
||||||
int x_new_color(x_connection *x, char *color);
|
int x_new_color(x_connection *x, char *color);
|
||||||
|
int x_new_font(x_connection *x, char *font);
|
||||||
|
|
||||||
/* for x_events, we pass the gui */
|
/* for x_events, we pass the gui */
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
void x_events(gui *gui);
|
void x_events(gui *gui);
|
||||||
|
|
||||||
void x_text_get_dimensions(x_connection *, const char *t,
|
void x_text_get_dimensions(x_connection *, int font, const char *t,
|
||||||
int *width, int *height, int *baseline);
|
int *width, int *height, int *baseline);
|
||||||
|
|
||||||
/* drawing functions */
|
/* drawing functions */
|
||||||
@@ -39,11 +40,11 @@ void x_draw_rectangle(x_connection *c, x_window *w, int color,
|
|||||||
void x_fill_rectangle(x_connection *c, x_window *w, int color,
|
void x_fill_rectangle(x_connection *c, x_window *w, int color,
|
||||||
int x, int y, int width, int height);
|
int x, int y, int width, int height);
|
||||||
|
|
||||||
void x_draw_string(x_connection *_c, x_window *_w, int color,
|
void x_draw_string(x_connection *_c, x_window *_w, int font, int color,
|
||||||
int x, int y, const char *t);
|
int x, int y, const char *t);
|
||||||
|
|
||||||
void x_draw_clipped_string(x_connection *_c, x_window *_w, int color,
|
void x_draw_clipped_string(x_connection *_c, x_window *_w, int font,
|
||||||
int x, int y, const char *t,
|
int color, int x, int y, const char *t,
|
||||||
int clipx, int clipy, int clipwidth, int clipheight);
|
int clipx, int clipy, int clipwidth, int clipheight);
|
||||||
|
|
||||||
void x_draw_image(x_connection *c, x_window *w, x_image *img, int x, int y);
|
void x_draw_image(x_connection *c, x_window *w, x_image *img, int x, int y);
|
||||||
|
|||||||
@@ -2,14 +2,18 @@
|
|||||||
#define _X_DEFS_H_
|
#define _X_DEFS_H_
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
#include <Xft.h>
|
||||||
|
|
||||||
struct x_connection {
|
struct x_connection {
|
||||||
Display *d;
|
Display *d;
|
||||||
GC *colors;
|
GC *colors;
|
||||||
|
XftColor *xft_colors;
|
||||||
int ncolors;
|
int ncolors;
|
||||||
XPoint *pts;
|
XPoint *pts;
|
||||||
int pts_size;
|
int pts_size;
|
||||||
int pts_maxsize;
|
int pts_maxsize;
|
||||||
|
XftFont **fonts;
|
||||||
|
int nfonts;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct x_window {
|
struct x_window {
|
||||||
@@ -17,6 +21,7 @@ struct x_window {
|
|||||||
Pixmap p;
|
Pixmap p;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
XftDraw *xft;
|
||||||
/* below: internal data used for X events handling */
|
/* below: internal data used for X events handling */
|
||||||
int redraw;
|
int redraw;
|
||||||
int repaint;
|
int repaint;
|
||||||
|
|||||||
@@ -79,8 +79,8 @@ static void paint(gui *_gui, widget *_this)
|
|||||||
this->common.x + this->vrule_width + x,
|
this->common.x + this->vrule_width + x,
|
||||||
this->common.y + this->common.height - this->label_height * 2 - 5);
|
this->common.y + this->common.height - this->label_height * 2 - 5);
|
||||||
sprintf(v, "%g", k * ticstep);
|
sprintf(v, "%g", k * ticstep);
|
||||||
x_text_get_dimensions(g->x, v, &vwidth, &dummy, &dummy);
|
x_text_get_dimensions(g->x, DEFAULT_FONT, v, &vwidth, &dummy, &dummy);
|
||||||
x_draw_string(g->x, g->xwin, FOREGROUND_COLOR,
|
x_draw_string(g->x, g->xwin, DEFAULT_FONT, FOREGROUND_COLOR,
|
||||||
this->common.x + this->vrule_width + x - vwidth/2,
|
this->common.x + this->vrule_width + x - vwidth/2,
|
||||||
this->common.y + this->common.height - this->label_height * 2 +
|
this->common.y + this->common.height - this->label_height * 2 +
|
||||||
this->label_baseline,
|
this->label_baseline,
|
||||||
@@ -116,20 +116,20 @@ static void paint(gui *_gui, widget *_this)
|
|||||||
(allocated_ymax - allocated_ymin) *
|
(allocated_ymax - allocated_ymin) *
|
||||||
(allocated_plot_height - 1);
|
(allocated_plot_height - 1);
|
||||||
sprintf(v, "%g", k * ticstep);
|
sprintf(v, "%g", k * ticstep);
|
||||||
x_text_get_dimensions(g->x, v, &vwidth, &dummy, &dummy);
|
x_text_get_dimensions(g->x, DEFAULT_FONT, v, &vwidth, &dummy, &dummy);
|
||||||
x_draw_line(g->x, g->xwin, FOREGROUND_COLOR,
|
x_draw_line(g->x, g->xwin, FOREGROUND_COLOR,
|
||||||
this->common.x + this->vrule_width,
|
this->common.x + this->vrule_width,
|
||||||
this->common.y + FLIP(y),
|
this->common.y + FLIP(y),
|
||||||
this->common.x + this->vrule_width + 5,
|
this->common.x + this->vrule_width + 5,
|
||||||
this->common.y + FLIP(y));
|
this->common.y + FLIP(y));
|
||||||
x_draw_string(g->x, g->xwin, FOREGROUND_COLOR,
|
x_draw_string(g->x, g->xwin, DEFAULT_FONT, FOREGROUND_COLOR,
|
||||||
this->common.x + this->vrule_width - vwidth - 2,
|
this->common.x + this->vrule_width - vwidth - 2,
|
||||||
this->common.y + FLIP(y) - this->label_height/2+this->label_baseline,
|
this->common.y + FLIP(y) - this->label_height/2+this->label_baseline,
|
||||||
v);
|
v);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* label at bottom, in the middle */
|
/* label at bottom, in the middle */
|
||||||
x_draw_string(g->x, g->xwin, FOREGROUND_COLOR,
|
x_draw_string(g->x, g->xwin, DEFAULT_FONT, FOREGROUND_COLOR,
|
||||||
this->common.x + (this->common.width - this->label_width) / 2,
|
this->common.x + (this->common.width - this->label_width) / 2,
|
||||||
this->common.y + this->common.height - this->label_height
|
this->common.y + this->common.height - this->label_height
|
||||||
+ this->label_baseline,
|
+ this->label_baseline,
|
||||||
@@ -177,8 +177,8 @@ widget *new_xy_plot(gui *_gui, int width, int height, char *label,
|
|||||||
w->label = strdup(label); if (w->label == NULL) OOM;
|
w->label = strdup(label); if (w->label == NULL) OOM;
|
||||||
/* TODO: be sure calling X there is valid wrt "global model" (we are
|
/* TODO: be sure calling X there is valid wrt "global model" (we are
|
||||||
* not in the "gui thread") */
|
* not in the "gui thread") */
|
||||||
x_text_get_dimensions(g->x, label, &w->label_width, &w->label_height,
|
x_text_get_dimensions(g->x, DEFAULT_FONT, label,
|
||||||
&w->label_baseline);
|
&w->label_width, &w->label_height, &w->label_baseline);
|
||||||
LOGD("XY PLOT label wh %d %d\n", w->label_width, w->label_height);
|
LOGD("XY PLOT label wh %d %d\n", w->label_width, w->label_height);
|
||||||
|
|
||||||
w->wanted_width = width;
|
w->wanted_width = width;
|
||||||
|
|||||||
Reference in New Issue
Block a user