Refactor text rendering

This commit is contained in:
o9000 2017-06-05 15:20:16 +02:00
parent b50f5ecf3e
commit 59c3761455
5 changed files with 292 additions and 159 deletions

View file

@ -77,6 +77,9 @@ void default_clock()
time1_font_desc = NULL;
time2_has_font = FALSE;
time2_font_desc = NULL;
buf_time[0] = 0;
buf_date[0] = 0;
buf_tooltip[0] = 0;
}
void cleanup_clock()
@ -111,31 +114,6 @@ void cleanup_clock()
clock_timeout = NULL;
}
void update_clocks_sec(void *arg)
{
gettimeofday(&time_clock, 0);
if (time1_format) {
for (int i = 0; i < num_panels; i++)
panels[i].clock.area.resize_needed = 1;
}
schedule_panel_redraw();
}
void update_clocks_min(void *arg)
{
// remember old_sec because after suspend/hibernate the clock should be updated directly, and not
// on next minute change
time_t old_sec = time_clock.tv_sec;
gettimeofday(&time_clock, 0);
if (time_clock.tv_sec % 60 == 0 || time_clock.tv_sec - old_sec > 60) {
if (time1_format) {
for (int i = 0; i < num_panels; i++)
panels[i].clock.area.resize_needed = 1;
}
schedule_panel_redraw();
}
}
struct tm *clock_gettime_for_tz(const char *timezone)
{
if (timezone) {
@ -152,6 +130,35 @@ struct tm *clock_gettime_for_tz(const char *timezone)
}
}
void update_clocks()
{
if (time1_format)
strftime(buf_time, sizeof(buf_time), time1_format, clock_gettime_for_tz(time1_timezone));
if (time2_format)
strftime(buf_date, sizeof(buf_date), time2_format, clock_gettime_for_tz(time2_timezone));
if (time1_format || time2_format) {
for (int i = 0; i < num_panels; i++)
panels[i].clock.area.resize_needed = 1;
}
schedule_panel_redraw();
}
void update_clocks_sec(void *arg)
{
gettimeofday(&time_clock, 0);
update_clocks();
}
void update_clocks_min(void *arg)
{
// remember old_sec because after suspend/hibernate the clock should be updated directly, and not
// on next minute change
gettimeofday(&time_clock, 0);
time_t old_sec = time_clock.tv_sec;
if (time_clock.tv_sec % 60 == 0 || time_clock.tv_sec - old_sec > 60)
update_clocks();
}
gboolean time_format_needs_sec_ticks(char *time_format)
{
if (!time_format)
@ -205,6 +212,7 @@ void init_clock_panel(void *p)
clock->area._get_tooltip_text = clock_get_tooltip;
strftime(buf_tooltip, sizeof(buf_tooltip), time_tooltip_format, clock_gettime_for_tz(time_tooltip_timezone));
}
update_clocks_sec(NULL);
}
void clock_init_fonts()
@ -251,138 +259,53 @@ void clock_compute_text_geometry(Clock *clock,
int *date_height,
int *date_width)
{
Panel *panel = (Panel *)clock->area.panel;
int available_w, available_h;
if (panel_horizontal) {
available_w = panel->area.width;
available_h = clock->area.height - 2 * clock->area.paddingy - left_right_border_width(&clock->area);
} else {
available_w = clock->area.width - 2 * clock->area.paddingxlr - left_right_border_width(&clock->area);
available_h = panel->area.height;
}
*date_height = *date_width = 0;
strftime(buf_time, sizeof(buf_time), time1_format, clock_gettime_for_tz(time1_timezone));
get_text_size2(time1_font_desc,
time_height_ink,
time_height,
time_width,
available_h,
available_w,
buf_time,
strlen(buf_time),
PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE,
FALSE);
if (time2_format) {
strftime(buf_date, sizeof(buf_date), time2_format, clock_gettime_for_tz(time2_timezone));
get_text_size2(time2_font_desc,
date_height_ink,
date_height,
date_width,
available_h,
available_w,
buf_date,
strlen(buf_date),
PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE,
FALSE);
}
area_compute_text_geometry(&clock->area,
buf_time,
time2_format ? buf_date : NULL,
time1_font_desc,
time2_font_desc,
time_height_ink,
time_height,
time_width,
date_height_ink,
date_height,
date_width);
}
int clock_compute_desired_size(void *obj)
{
Clock *clock = (Clock *)obj;
int time_height_ink, time_height, time_width, date_height_ink, date_height, date_width;
clock_compute_text_geometry(clock,
&time_height_ink,
&time_height,
&time_width,
&date_height_ink,
&date_height,
&date_width);
if (panel_horizontal) {
int new_size = MAX(time_width, date_width) + 2 * clock->area.paddingxlr + left_right_border_width(&clock->area);
return new_size;
} else {
int new_size = time_height + date_height + 2 * clock->area.paddingxlr + top_bottom_border_width(&clock->area);
return new_size;
}
return text_area_compute_desired_size(&clock->area,
buf_time,
time2_format ? buf_date : NULL,
time1_font_desc,
time2_font_desc);
}
gboolean resize_clock(void *obj)
{
Clock *clock = (Clock *)obj;
gboolean result = FALSE;
schedule_redraw(&clock->area);
int time_height_ink, time_height, time_width, date_height_ink, date_height, date_width;
clock_compute_text_geometry(clock,
&time_height_ink,
&time_height,
&time_width,
&date_height_ink,
&date_height,
&date_width);
int new_size = clock_compute_desired_size(clock);
if (panel_horizontal) {
if (new_size > clock->area.width || new_size < (clock->area.width - 6)) {
// we try to limit the number of resizes
clock->area.width = new_size + 1;
clock->time1_posy = (clock->area.height - time_height) / 2;
if (time2_format) {
clock->time1_posy -= (date_height) / 2;
clock->time2_posy = clock->time1_posy + time_height;
}
result = TRUE;
}
} else {
if (new_size != clock->area.height) {
// we try to limit the number of resizes
clock->area.height = new_size;
clock->time1_posy = (clock->area.height - time_height) / 2;
if (time2_format) {
clock->time1_posy -= (date_height) / 2;
clock->time2_posy = clock->time1_posy + time_height;
}
result = TRUE;
}
}
return result;
return resize_text_area(&clock->area,
buf_time,
time2_format ? buf_date : NULL,
time1_font_desc,
time2_font_desc,
&clock->time1_posy,
&clock->time2_posy);
}
void draw_clock(void *obj, cairo_t *c)
{
Clock *clock = obj;
PangoLayout *layout = pango_cairo_create_layout(c);
pango_layout_set_font_description(layout, time1_font_desc);
pango_layout_set_width(layout, clock->area.width * PANGO_SCALE);
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
pango_layout_set_text(layout, buf_time, strlen(buf_time));
cairo_set_source_rgba(c, clock->font.rgb[0], clock->font.rgb[1], clock->font.rgb[2], clock->font.alpha);
pango_cairo_update_layout(c, layout);
draw_text(layout, c, 0, clock->time1_posy, &clock->font, ((Panel *)clock->area.panel)->font_shadow);
if (time2_format) {
pango_layout_set_font_description(layout, time2_font_desc);
pango_layout_set_indent(layout, 0);
pango_layout_set_text(layout, buf_date, strlen(buf_date));
pango_layout_set_width(layout, clock->area.width * PANGO_SCALE);
pango_cairo_update_layout(c, layout);
draw_text(layout, c, 0, clock->time2_posy, &clock->font, ((Panel *)clock->area.panel)->font_shadow);
}
g_object_unref(layout);
Clock *clock = (Clock *)obj;
draw_text_area(&clock->area,
c,
buf_time,
time2_format ? buf_date : NULL,
time1_font_desc,
time2_font_desc,
clock->time1_posy,
clock->time2_posy,
&clock->font);
}
void clock_dump_geometry(void *obj, int indent)

View file

@ -883,6 +883,180 @@ void area_dump_geometry(Area *area, int indent)
}
}
void area_compute_text_geometry(Area *area,
const char *line1,
const char *line2,
PangoFontDescription *line1_font_desc,
PangoFontDescription *line2_font_desc,
int *line1_height_ink,
int *line1_height,
int *line1_width,
int *line2_height_ink,
int *line2_height,
int *line2_width)
{
Panel *panel = (Panel *)area->panel;
int available_w, available_h;
if (panel_horizontal) {
available_w = panel->area.width;
available_h = area->height - 2 * area->paddingy - left_right_border_width(area);
} else {
available_w = area->width - 2 * area->paddingxlr - left_right_border_width(area);
available_h = panel->area.height;
}
if (line1 && line1[0])
get_text_size2(line1_font_desc,
line1_height_ink,
line1_height,
line1_width,
available_h,
available_w,
line1,
strlen(line1),
PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE,
FALSE);
else
*line1_width = *line1_height_ink = *line1_height = 0;
if (line2 && line2[0])
get_text_size2(line2_font_desc,
line2_height_ink,
line2_height,
line2_width,
available_h,
available_w,
line2,
strlen(line2),
PANGO_WRAP_WORD_CHAR,
PANGO_ELLIPSIZE_NONE,
FALSE);
else
*line2_width = *line2_height_ink = *line2_height = 0;
}
int text_area_compute_desired_size(Area *area,
const char *line1,
const char *line2,
PangoFontDescription *line1_font_desc,
PangoFontDescription *line2_font_desc)
{
int line1_height_ink, line1_height, line1_width, line2_height_ink, line2_height, line2_width;
area_compute_text_geometry(area,
line1,
line2,
line1_font_desc,
line2_font_desc,
&line1_height_ink,
&line1_height,
&line1_width,
&line2_height_ink,
&line2_height,
&line2_width);
if (panel_horizontal) {
int new_size = MAX(line1_width, line2_width) + 2 * area->paddingxlr + left_right_border_width(area);
return new_size;
} else {
int new_size = line1_height + line2_height + 2 * area->paddingxlr + top_bottom_border_width(area);
return new_size;
}
}
gboolean resize_text_area(Area *area,
const char *line1,
const char *line2,
PangoFontDescription *line1_font_desc,
PangoFontDescription *line2_font_desc,
int *line1_posy,
int *line2_posy)
{
gboolean result = FALSE;
schedule_redraw(area);
int line1_height_ink, line1_height, line1_width;
int line2_height_ink, line2_height, line2_width;
area_compute_text_geometry(area,
line1,
line2,
line1_font_desc,
line2_font_desc,
&line1_height_ink,
&line1_height,
&line1_width,
&line2_height_ink,
&line2_height,
&line2_width);
int new_size = text_area_compute_desired_size(area,
line1,
line2,
line1_font_desc,
line2_font_desc);
if (panel_horizontal) {
if (new_size > area->width || new_size < (area->width - 6)) {
// we try to limit the number of resizes
area->width = new_size + 1;
*line1_posy = (area->height - line1_height) / 2;
if (line2) {
*line1_posy -= (line2_height) / 2;
*line2_posy = *line1_posy + line1_height;
}
result = TRUE;
}
} else {
if (new_size != area->height) {
// we try to limit the number of resizes
area->height = new_size;
*line1_posy = (area->height - line1_height) / 2;
if (line2) {
*line1_posy -= (line2_height) / 2;
*line2_posy = *line1_posy + line1_height;
}
result = TRUE;
}
}
return result;
}
void draw_text_area(Area *area,
cairo_t *c,
const char *line1,
const char *line2,
PangoFontDescription *line1_font_desc,
PangoFontDescription *line2_font_desc,
int line1_posy,
int line2_posy,
Color *color)
{
PangoLayout *layout = pango_cairo_create_layout(c);
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
pango_layout_set_width(layout, area->width * PANGO_SCALE);
cairo_set_source_rgba(c, color->rgb[0], color->rgb[1], color->rgb[2], color->alpha);
if (line1 && line1[0]) {
pango_layout_set_font_description(layout, line1_font_desc);
pango_layout_set_text(layout, line1, strlen(line1));
pango_cairo_update_layout(c, layout);
draw_text(layout, c, 0, line1_posy, color, ((Panel *)area->panel)->font_shadow);
}
if (line2 && line2[0]) {
pango_layout_set_font_description(layout, line2_font_desc);
pango_layout_set_indent(layout, 0);
pango_layout_set_text(layout, line2, strlen(line2));
pango_cairo_update_layout(c, layout);
draw_text(layout, c, 0, line2_posy, color, ((Panel *)area->panel)->font_shadow);
}
g_object_unref(layout);
}
Area *compute_element_area(Area *area, Element element)
{
if (element == ELEMENT_SELF)

View file

@ -263,6 +263,39 @@ int relayout_with_constraint(Area *a, int maximum_size);
int compute_desired_size(Area *a);
int container_compute_desired_size(Area *a);
void area_compute_text_geometry(Area *area,
const char *line1,
const char *line2,
PangoFontDescription *line1_font_desc,
PangoFontDescription *line2_font_desc,
int *line1_height_ink,
int *line1_height,
int *line1_width,
int *line2_height_ink,
int *line2_height,
int *line2_width);
int text_area_compute_desired_size(Area *area,
const char *line1,
const char *line2,
PangoFontDescription *line1_font_desc,
PangoFontDescription *line2_font_desc);
gboolean resize_text_area(Area *area,
const char *line1,
const char *line2,
PangoFontDescription *line1_font_desc,
PangoFontDescription *line2_font_desc,
int *line1_posy,
int *line2_posy);
void draw_text_area(Area *area,
cairo_t *c,
const char *line1,
const char *line2,
PangoFontDescription *line1_font_desc,
PangoFontDescription *line2_font_desc,
int line1_posy,
int line2_posy,
Color *color);
int left_border_width(Area *a);
int right_border_width(Area *a);
int left_right_border_width(Area *a);

View file

@ -736,35 +736,38 @@ void clear_pixmap(Pixmap p, int x, int y, int w, int h)
XRenderFreePicture(server.display, pict);
}
void get_text_size2(PangoFontDescription *font,
void get_text_size2(const PangoFontDescription *font,
int *height_ink,
int *height,
int *width,
int panel_height,
int panel_width,
char *text,
int len,
int available_height,
int available_width,
const char *text,
int text_len,
PangoWrapMode wrap,
PangoEllipsizeMode ellipsis,
gboolean markup)
{
PangoRectangle rect_ink, rect;
Pixmap pmap = XCreatePixmap(server.display, server.root_win, panel_height, panel_width, server.depth);
available_width = MAX(0, available_width);
available_height = MAX(0, available_height);
Pixmap pmap = XCreatePixmap(server.display, server.root_win, available_height, available_width, server.depth);
cairo_surface_t *cs = cairo_xlib_surface_create(server.display, pmap, server.visual, panel_height, panel_width);
cairo_surface_t *cs = cairo_xlib_surface_create(server.display, pmap, server.visual, available_height, available_width);
cairo_t *c = cairo_create(cs);
PangoLayout *layout = pango_cairo_create_layout(c);
pango_layout_set_width(layout, panel_width * PANGO_SCALE);
pango_layout_set_height(layout, panel_height * PANGO_SCALE);
pango_layout_set_width(layout, available_width * PANGO_SCALE);
pango_layout_set_height(layout, available_height * PANGO_SCALE);
pango_layout_set_wrap(layout, wrap);
pango_layout_set_ellipsize(layout, ellipsis);
pango_layout_set_font_description(layout, font);
text_len = MAX(0, text_len);
if (!markup)
pango_layout_set_text(layout, text, len);
pango_layout_set_text(layout, text, text_len);
else
pango_layout_set_markup(layout, text, len);
pango_layout_set_markup(layout, text, text_len);
pango_layout_get_pixel_extents(layout, &rect_ink, &rect);
*height_ink = rect_ink.height;

View file

@ -95,14 +95,14 @@ void create_heuristic_mask(DATA32 *data, int w, int h);
// Renders the current Imlib image to a drawable. Wrapper around imlib_render_image_on_drawable.
void render_image(Drawable d, int x, int y);
void get_text_size2(PangoFontDescription *font,
void get_text_size2(const PangoFontDescription *font,
int *height_ink,
int *height,
int *width,
int panel_height,
int panel_with,
char *text,
int len,
int available_height,
int available_with,
const char *text,
int text_len,
PangoWrapMode wrap,
PangoEllipsizeMode ellipsis,
gboolean markup);