refactor draw_win

This commit is contained in:
Sascha Kruse 2012-12-11 00:08:34 +01:00
parent 69c55f25e5
commit e16b1764f8
2 changed files with 128 additions and 123 deletions

231
dunst.c
View File

@ -72,6 +72,8 @@ static bool print_notifications = false;
static dimension_t window_dim; static dimension_t window_dim;
static bool pause_display = false; static bool pause_display = false;
static r_line_cache line_cache;
bool dunst_grab_errored = false; bool dunst_grab_errored = false;
int next_notification_id = 1; int next_notification_id = 1;
@ -103,6 +105,10 @@ void hide_win(void);
void move_all_to_history(void); void move_all_to_history(void);
void print_version(void); void print_version(void);
void r_line_cache_init(r_line_cache *c);
void r_line_cache_append(r_line_cache *c, const char *s, ColorSet *col);
void r_line_cache_reset(r_line_cache *c);
/* show warning notification */ /* show warning notification */
void warn(const char *text, int urg); void warn(const char *text, int urg);
@ -383,6 +389,40 @@ void update_lists()
} }
} }
void r_line_cache_init(r_line_cache *c)
{
c->count = 0;
c->size = 0;
c->lines = NULL;
}
void r_line_cache_append(r_line_cache *c, const char *s, ColorSet *col)
{
if (!c || !s)
return;
/* resize cache if it's too small */
if (c->count >= c->size) {
c->size++;
c->lines = realloc(c->lines, c->size * sizeof(r_line));
}
c->count++;
c->lines[c->count-1].colors = col;
c->lines[c->count-1].str = strdup(s);
}
void r_line_cache_reset(r_line_cache *c)
{
for (int i = 0; i < c->count; i++) {
if (c->lines[i].str)
free(c->lines[i].str);
c->lines[i].str = NULL;
c->lines[i].colors = NULL;
}
c->count = 0;
}
/* TODO get draw_txt_buf as argument */ /* TODO get draw_txt_buf as argument */
int do_word_wrap(char *source, int max_width) int do_word_wrap(char *source, int max_width)
{ {
@ -430,16 +470,13 @@ int do_word_wrap(char *source, int max_width)
} }
} }
void update_draw_txt_buf(notification * n, int max_width) void add_notification_to_line_cache(notification *n, int max_width)
{ {
rstrip(n->msg); rstrip(n->msg);
char *msg = n->msg; char *msg = n->msg;
while (isspace(*msg)) while (isspace(*msg))
msg++; msg++;
if (n->draw_txt_buf.txt)
free(n->draw_txt_buf.txt);
char *buf; char *buf;
/* print dup_count */ /* print dup_count */
@ -481,22 +518,18 @@ void update_draw_txt_buf(notification * n, int max_width)
buf = new_buf; buf = new_buf;
} }
n->draw_txt_buf.line_count = do_word_wrap(buf, max_width);
n->draw_txt_buf.txt = buf;
}
char *draw_txt_get_line(draw_txt * dt, int line) int linecnt = do_word_wrap(buf, max_width);
{ n->line_count = linecnt;
if (line > dt->line_count) { char *cur = buf;
return NULL; for (int i = 0; i < linecnt; i++) {
r_line_cache_append(&line_cache, cur, n->colors);
while (*cur != '\0')
cur++;
cur++;
} }
free(buf);
char *begin = dt->txt;
for (int i = 1; i < line; i++) {
begin += strlen(begin) + 1;
}
return begin;
} }
int calculate_x_offset(int line_width, int text_width) int calculate_x_offset(int line_width, int text_width)
@ -570,148 +603,114 @@ unsigned long calculate_foreground_color(unsigned long source_color)
return color.pixel; return color.pixel;
} }
void draw_win(void) int calculate_width(void)
{ {
int width, x, y, height;
line_height = MAX(line_height, font_h);
update_screen_info();
/* calculate width */
if (geometry.mask & WidthValue && geometry.w == 0) { if (geometry.mask & WidthValue && geometry.w == 0) {
/* dynamic width */ /* dynamic width */
width = 0; return 0;
} else if (geometry.mask & WidthValue) { } else if (geometry.mask & WidthValue) {
/* fixed width */ /* fixed width */
if (geometry.negative_width) { if (geometry.negative_width) {
width = scr.dim.w - geometry.w; return scr.dim.w - geometry.w;
} else { } else {
width = geometry.w; return geometry.w;
} }
} else { } else {
/* across the screen */ /* across the screen */
width = scr.dim.w; return scr.dim.w;
} }
}
/* update draw_txt_bufs and line_cnt */
int line_cnt = 0; void draw_win(void)
{
r_line_cache_reset(&line_cache);
update_screen_info();
int width = calculate_width();
line_height = MAX(line_height, font_h);
/* create cache with all lines */
for (l_node * iter = displayed_notifications->head; iter; for (l_node * iter = displayed_notifications->head; iter;
iter = iter->next) { iter = iter->next) {
notification *n = (notification *) iter->data; notification *n = (notification *) iter->data;
update_draw_txt_buf(n, width); add_notification_to_line_cache(n, width);
line_cnt += n->draw_txt_buf.line_count;
} }
/* calculate height */ assert(line_cache.count > 0);
if (geometry.h == 0) {
height = line_cnt * line_height;
} else {
height = MAX(geometry.h, (line_cnt * line_height));
}
height += (l_length(displayed_notifications) - 1) * separator_height;
/* add "(x more)" */
draw_txt x_more;
x_more.txt = NULL;
char *print_to;
int more = l_length(notification_queue);
if (indicate_hidden && more > 0) {
int x_more_len = strlen(" ( more) ") + digit_count(more);
/* add (x more) */
int queue_cnt = l_length(notification_queue);
if (indicate_hidden && queue_cnt > 0) {
if (geometry.h != 1) { if (geometry.h != 1) {
/* add additional line */ char *tmp;
x_more.txt = calloc(x_more_len, sizeof(char)); asprintf(&tmp, "(%d more)", queue_cnt);
height += line_height; ColorSet *last_colors =
line_cnt++; line_cache.lines[line_cache.count-1].colors;
r_line_cache_append(&line_cache, strdup(tmp), last_colors);
print_to = x_more.txt; free(tmp);
} else { } else {
/* append "(x more)" message to notification text */ char *old = line_cache.lines[0].str;
notification *n = char *new;
(notification *) displayed_notifications->head-> asprintf(&new, "%s (%d more)", old, queue_cnt);
data; free(old);
print_to = line_cache.lines[0].str = new;
draw_txt_get_line(&n->draw_txt_buf,
n->draw_txt_buf.line_count);
for (; *print_to != '\0'; print_to++) ;
} }
snprintf(print_to, x_more_len, "(%d more)", more);
} }
/* if we have a dynamic width, calculate the actual width */ /* if we have a dynamic width, calculate the actual width */
if (width == 0) { if (width == 0) {
for (l_node * iter = displayed_notifications->head; iter; for (int i = 0; i < line_cache.count; i++) {
iter = iter->next) { char *line = line_cache.lines[i].str;
notification *n = (notification *) iter->data; width = MAX(width, textw(dc, line));
for (int i = 0; i < n->draw_txt_buf.line_count; i++) {
char *line =
draw_txt_get_line(&n->draw_txt_buf, i + 1);
assert(line != NULL);
width = MAX(width, textw(dc, line));
}
} }
} }
assert(line_height > 0); /* resize dc to correct width */
assert(font_h > 0);
assert(width > 0); int height = (line_cache.count * line_height)
assert(height > 0); + ((line_cache.count - 1) * separator_height);
assert(line_cnt > 0);
resizedc(dc, width, height); resizedc(dc, width, height);
/* draw buffers */
dc->y = 0; dc->y = 0;
ColorSet *last_color;
assert(displayed_notifications->head != NULL);
for (l_node * iter = displayed_notifications->head; iter;
iter = iter->next) {
notification *n = (notification *) iter->data; for (int i = 0; i < line_cache.count; i++) {
last_color = n->colors; dc->x = 0;
for (int i = 0; i < n->draw_txt_buf.line_count; i++) { r_line line = line_cache.lines[i];
char *line = draw_txt_get_line(&n->draw_txt_buf, i + 1);
dc->x = 0;
drawrect(dc, 0, 0, width, line_height, true,
n->colors->BG);
dc->x = calculate_x_offset(width, textw(dc, line)); /* draw background */
dc->y += (line_height - font_h) / 2; drawrect(dc, 0, 0, width, line_height, true, line.colors->BG);
drawtextn(dc, line, strlen(line), n->colors);
dc->y += line_height - ((line_height - font_h) / 2); /* draw text */
} dc->x = calculate_x_offset(width, textw(dc, line.str));
dc->y += (line_height - font_h) / 2;
drawtextn(dc, line.str, strlen(line.str), line.colors);
dc->y += line_height - ((line_height - font_h) / 2);
/* draw separator */ /* draw separator */
if (separator_height > 0) { if (separator_height > 0 && i < line_cache.count - 1) {
dc->x = 0; dc->x = 0;
double color; double color;
if (sep_color == AUTO) if (sep_color == AUTO)
color = color = calculate_foreground_color(line.colors->BG);
calculate_foreground_color(n->colors->BG);
else else
color = n->colors->FG; color = line.colors->FG;
drawrect(dc, 0, 0, width, separator_height, true, color);
drawrect(dc, 0, 0, width, separator_height, true,
color);
dc->y += separator_height; dc->y += separator_height;
} }
} }
/* draw x_more */
if (x_more.txt) {
dc->x = 0;
drawrect(dc, 0, 0, width, line_height, true, last_color->BG);
dc->x = calculate_x_offset(width, textw(dc, x_more.txt));
drawtext(dc, x_more.txt, last_color);
}
int x,y;
/* calculate window position */ /* calculate window position */
if (geometry.mask & XNegative) { if (geometry.mask & XNegative) {
x = (scr.dim.x + (scr.dim.w - width)) + geometry.x; x = (scr.dim.x + (scr.dim.w - width)) + geometry.x;
@ -739,8 +738,6 @@ void draw_win(void)
} }
mapdc(dc, win, width, height); mapdc(dc, win, width, height);
free(x_more.txt);
} }
char char
@ -808,7 +805,7 @@ void handle_mouse_click(XEvent ev)
assert(iter); assert(iter);
for (; iter; iter = iter->next) { for (; iter; iter = iter->next) {
n = (notification *) iter->data; n = (notification *) iter->data;
int height = font_h * n->draw_txt_buf.line_count; int height = font_h * n->line_count;
if (ev.xbutton.y > y && ev.xbutton.y < y + height) if (ev.xbutton.y > y && ev.xbutton.y < y + height)
break; break;
else else
@ -958,7 +955,6 @@ int init_notification(notification * n, int id)
n->msg = fix_markup(n->msg); n->msg = fix_markup(n->msg);
n->dup_count = 0; n->dup_count = 0;
n->draw_txt_buf.txt = NULL;
/* check if n is a duplicate */ /* check if n is a duplicate */
for (l_node * iter = notification_queue->head; iter; iter = iter->next) { for (l_node * iter = notification_queue->head; iter; iter = iter->next) {
@ -1702,6 +1698,7 @@ int main(int argc, char *argv[])
notification_history = l_init(); notification_history = l_init();
displayed_notifications = l_init(); displayed_notifications = l_init();
rules = l_init(); rules = l_init();
r_line_cache_init(&line_cache);
for (int i = 0; i < LENGTH(default_rules); i++) { for (int i = 0; i < LENGTH(default_rules); i++) {
l_push(rules, &default_rules[i]); l_push(rules, &default_rules[i]);

20
dunst.h
View File

@ -32,18 +32,12 @@ typedef struct _screen_info {
dimension_t dim; dimension_t dim;
} screen_info; } screen_info;
typedef struct _draw_txt {
char *txt;
int line_count;
} draw_txt;
typedef struct _notification { typedef struct _notification {
char *appname; char *appname;
char *summary; char *summary;
char *body; char *body;
char *icon; char *icon;
char *msg; char *msg;
draw_txt draw_txt_buf;
const char *format; const char *format;
char *dbus_client; char *dbus_client;
time_t start; time_t start;
@ -56,6 +50,7 @@ typedef struct _notification {
ColorSet *colors; ColorSet *colors;
char *color_strings[2]; char *color_strings[2];
int progress; /* percentage + 1, 0 to hide */ int progress; /* percentage + 1, 0 to hide */
int line_count;
} notification; } notification;
typedef struct _notification_buffer { typedef struct _notification_buffer {
@ -88,6 +83,19 @@ typedef struct _keyboard_shortcut {
bool is_valid; bool is_valid;
} keyboard_shortcut; } keyboard_shortcut;
typedef struct _r_line {
ColorSet *colors;
char *str;
} r_line;
typedef struct r_line_cache {
int count;
int size;
r_line *lines;
} r_line_cache;
extern int verbosity; extern int verbosity;
/* return id of notification */ /* return id of notification */