cleanup draw_win
This commit is contained in:
parent
362e45857c
commit
2f5d8d7afb
316
dunst.c
316
dunst.c
@ -1,6 +1,7 @@
|
|||||||
/* copyright 2012 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
/* copyright 2012 Sascha Kruse and contributors (see LICENSE for licensing information) */
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
#include <assert.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -361,50 +362,67 @@ void update_lists()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int next_split(char *source, int max_width)
|
/* TODO get draw_txt_buf as argument */
|
||||||
|
int do_word_wrap(char *source, int max_width)
|
||||||
{
|
{
|
||||||
int last_word = 0;
|
char *last_space = NULL;
|
||||||
for (int i = 0; i < strlen(source); i++) {
|
char *cur = source;
|
||||||
if (isspace(source[i])) {
|
int lines = 1;
|
||||||
if (textnw(dc, source, i) > max_width) {
|
|
||||||
return last_word;
|
if (max_width < 1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
while (*cur != '\0') {
|
||||||
|
if (isspace(*cur)) {
|
||||||
|
if (textnw(dc, source, cur - source) > max_width) {
|
||||||
|
*last_space = '\0';
|
||||||
|
lines++;
|
||||||
|
cur = last_space + 1;
|
||||||
|
source = cur;
|
||||||
|
continue;
|
||||||
} else {
|
} else {
|
||||||
last_word = i;
|
last_space = cur;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cur++;
|
||||||
}
|
}
|
||||||
return -1;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fill_notification_buffer(notification * n, notification_buffer * buf)
|
void update_draw_txt_buf(notification * n, int max_width)
|
||||||
{
|
{
|
||||||
memset(buf->txt, '\0', BUFSIZ);
|
if (!n->draw_txt_buf.txt) {
|
||||||
buf->n = n;
|
int dup_len = strlen(" () ") + digit_count(INT_MAX);
|
||||||
|
int msg_len = strlen(n->msg) + 2; /* 2 == surrounding spaces */
|
||||||
|
int age_len = strlen(" ( h 60m 60s old ) ")
|
||||||
|
+ digit_count(INT_MAX); /* could be INT_MAX hours */
|
||||||
|
int line_length = dup_len + msg_len + age_len;
|
||||||
|
|
||||||
char *end = buf->txt;
|
line_length += sizeof(" ( more ) ") + digit_count(INT_MAX);
|
||||||
int size = BUFSIZ;
|
|
||||||
|
|
||||||
/* print duplication count */
|
n->draw_txt_buf.txt = calloc(line_length, sizeof(char));
|
||||||
if (n->dup_count > 0) {
|
n->draw_txt_buf.bufsize = line_length;
|
||||||
size -= snprintf(end, size, "(%d)", n->dup_count);
|
|
||||||
}
|
}
|
||||||
if (size <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
end = buf->txt + strlen(buf->txt);
|
char *buf = n->draw_txt_buf.txt;
|
||||||
|
int bufsize = n->draw_txt_buf.bufsize;
|
||||||
|
char *next = buf;
|
||||||
|
|
||||||
/* print message */
|
memset(buf, '\0', bufsize);
|
||||||
size -= snprintf(end, size, " %s", n->msg);
|
|
||||||
if (size <= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
end = buf->txt + strlen(buf->txt);
|
/* print dup_count */
|
||||||
|
if (n->dup_count > 0) {
|
||||||
|
snprintf(next, bufsize - strlen(buf), "(%d) ", n->dup_count);
|
||||||
|
next = buf + strlen(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* print msg */
|
||||||
|
strncat(buf, n->msg, bufsize - strlen(buf));
|
||||||
|
next = buf + strlen(buf);
|
||||||
|
|
||||||
/* print age */
|
/* print age */
|
||||||
time_t t_delta;
|
|
||||||
int hours, minutes, seconds;
|
int hours, minutes, seconds;
|
||||||
|
time_t t_delta = now - n->timestamp;
|
||||||
t_delta = now - n->timestamp;
|
|
||||||
|
|
||||||
if (show_age_threshold >= 0 && t_delta >= show_age_threshold) {
|
if (show_age_threshold >= 0 && t_delta >= show_age_threshold) {
|
||||||
hours = t_delta / 3600;
|
hours = t_delta / 3600;
|
||||||
@ -412,85 +430,60 @@ void fill_notification_buffer(notification * n, notification_buffer * buf)
|
|||||||
seconds = t_delta % 60;
|
seconds = t_delta % 60;
|
||||||
|
|
||||||
if (hours > 0) {
|
if (hours > 0) {
|
||||||
size -=
|
snprintf(next, bufsize - strlen(buf),
|
||||||
snprintf(end, size, " (%dh %dm %ds old)",
|
" (%dh %dm %ds old)", hours, minutes, seconds);
|
||||||
hours, minutes, seconds);
|
|
||||||
} else if (minutes > 0) {
|
} else if (minutes > 0) {
|
||||||
size -= snprintf(end, size, " (%dm %ds old)",
|
snprintf(next, bufsize - strlen(buf), " (%dm %ds old)",
|
||||||
minutes, seconds);
|
minutes, seconds);
|
||||||
} else {
|
} else {
|
||||||
size -= snprintf(end, size, " (%ds old)", seconds);
|
snprintf(next, bufsize - strlen(buf), " (%ds old)",
|
||||||
|
seconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (size <= 0)
|
|
||||||
return;
|
n->draw_txt_buf.line_count =
|
||||||
|
do_word_wrap(n->draw_txt_buf.txt, max_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *draw_txt_get_line(draw_txt * dt, int line)
|
||||||
|
{
|
||||||
|
if (line > dt->line_count) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
switch (align) {
|
||||||
|
case left:
|
||||||
|
return 0;
|
||||||
|
case center:
|
||||||
|
return (line_width - text_width) / 2;
|
||||||
|
case right:
|
||||||
|
return line_width - text_width;
|
||||||
|
default:
|
||||||
|
/* this can't happen */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_win(void)
|
void draw_win(void)
|
||||||
{
|
{
|
||||||
int width, x, y, height;
|
int width, x, y, height;
|
||||||
int dc_height = 0;
|
|
||||||
unsigned int len = l_length(displayed_notifications);
|
|
||||||
notification_buffer *n_buf;
|
|
||||||
dc->x = 0;
|
|
||||||
dc->y = 0;
|
|
||||||
dc->h = 0;
|
|
||||||
|
|
||||||
update_screen_info();
|
update_screen_info();
|
||||||
|
|
||||||
/* calculate height */
|
|
||||||
if (geometry.h == 0) {
|
|
||||||
height = len;
|
|
||||||
} else {
|
|
||||||
height = MIN(geometry.h, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (indicate_hidden && geometry.h != 1
|
|
||||||
&& !l_is_empty(notification_queue)) {
|
|
||||||
height++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* initialize and fill buffers */
|
|
||||||
n_buf = calloc(height, sizeof(notification_buffer));
|
|
||||||
|
|
||||||
l_node *iter;
|
|
||||||
int i;
|
|
||||||
for (i = 0, iter = displayed_notifications->head; i < height; i++) {
|
|
||||||
if (iter) {
|
|
||||||
notification *n = (notification *) iter->data;
|
|
||||||
fill_notification_buffer(n, &n_buf[i]);
|
|
||||||
iter = iter->next;
|
|
||||||
} else {
|
|
||||||
n_buf[i].n = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add "(x more)" */
|
|
||||||
if (indicate_hidden && geometry.h != 1
|
|
||||||
&& !l_is_empty(notification_queue)) {
|
|
||||||
snprintf(n_buf[height - 1].txt, BUFSIZ, "(%d more)",
|
|
||||||
l_length(notification_queue));
|
|
||||||
/* give this buffer the most important notification in order
|
|
||||||
* to set the colors to it
|
|
||||||
*/
|
|
||||||
n_buf[height - 1].n = most_important(notification_queue)->data;
|
|
||||||
|
|
||||||
} else if (indicate_hidden && !l_is_empty(notification_queue)) {
|
|
||||||
/* append "(x more)" message to notification text */
|
|
||||||
char *begin;
|
|
||||||
for (begin = n_buf[0].txt; *begin != '\0'; begin++) ;
|
|
||||||
snprintf(begin, BUFSIZ - strlen(n_buf[0].txt),
|
|
||||||
" (%d more)", l_length(notification_queue));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate width */
|
/* calculate width */
|
||||||
if (geometry.mask & WidthValue && geometry.w == 0) {
|
if (geometry.mask & WidthValue && geometry.w == 0) {
|
||||||
/* dynamic width */
|
/* dynamic width */
|
||||||
width = 0;
|
width = 0;
|
||||||
for (i = 0; i < height; i++) {
|
|
||||||
width = MAX(width, textw(dc, n_buf[i].txt));
|
|
||||||
}
|
|
||||||
} else if (geometry.mask & WidthValue) {
|
} else if (geometry.mask & WidthValue) {
|
||||||
/* fixed width */
|
/* fixed width */
|
||||||
width = geometry.w;
|
width = geometry.w;
|
||||||
@ -499,84 +492,102 @@ void draw_win(void)
|
|||||||
width = scr.dim.w;
|
width = scr.dim.w;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calculate dc_height */
|
/* update draw_txt_bufs and line_cnt */
|
||||||
if (word_wrap) {
|
int line_cnt = 0;
|
||||||
for (int i = 0; i < height; i++) {
|
for (l_node * iter = displayed_notifications->head; iter;
|
||||||
if (strlen(n_buf[i].txt) > 0) {
|
iter = iter->next) {
|
||||||
char *txt = n_buf[i].txt;
|
notification *n = (notification *) iter->data;
|
||||||
int done = False;
|
update_draw_txt_buf(n, width);
|
||||||
while (!done) {
|
line_cnt += n->draw_txt_buf.line_count;
|
||||||
int txtlen = next_split(txt, width);
|
|
||||||
if (txtlen < 0) {
|
|
||||||
done = True;
|
|
||||||
}
|
}
|
||||||
dc_height++;
|
|
||||||
txt += txtlen;
|
/* if we have a dynamic width, calculate the actual width */
|
||||||
|
if (width == 0) {
|
||||||
|
for (l_node * iter = displayed_notifications->head; iter;
|
||||||
|
iter = iter->next) {
|
||||||
|
notification *n = (notification *) iter->data;
|
||||||
|
for (int i = 0; i < n->draw_txt_buf.line_count; i++) {
|
||||||
|
char *line =
|
||||||
|
draw_txt_get_line(&n->draw_txt_buf, i);
|
||||||
|
assert(line != NULL);
|
||||||
|
width = MAX(width, textw(dc, line));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* calculate height */
|
||||||
|
if (geometry.h == 0) {
|
||||||
|
height = line_cnt * font_h;
|
||||||
} else {
|
} else {
|
||||||
dc_height = height;
|
height = MIN(geometry.h, line_cnt) * font_h;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* */
|
/* add "(x more)" */
|
||||||
if (width <= 0) {
|
draw_txt x_more;
|
||||||
printf("Warning: width == 0\n");
|
x_more.txt = NULL;
|
||||||
goto draw_win_cleanup;
|
|
||||||
|
char *print_to;
|
||||||
|
int more = l_length(notification_queue);
|
||||||
|
if (indicate_hidden && more > 0) {
|
||||||
|
|
||||||
|
int x_more_len = strlen(" ( more) ") + digit_count(more);
|
||||||
|
|
||||||
|
if (geometry.h != 1) {
|
||||||
|
/* add additional line */
|
||||||
|
x_more.txt = calloc(x_more_len, sizeof(char));
|
||||||
|
height += font_h;
|
||||||
|
line_cnt++;
|
||||||
|
|
||||||
|
print_to = x_more.txt;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* append "(x more)" message to notification text */
|
||||||
|
notification *n =
|
||||||
|
(notification *) displayed_notifications->head;
|
||||||
|
print_to =
|
||||||
|
draw_txt_get_line(&n->draw_txt_buf,
|
||||||
|
n->draw_txt_buf.line_count);
|
||||||
|
for (; *print_to != '\0'; print_to++) ;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dc_height <= 0) {
|
snprintf(print_to, x_more_len, "(%d more)", more);
|
||||||
printf("Warning: dc_height == 0\n");
|
|
||||||
goto draw_win_cleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (font_h <= 0) {
|
assert(font_h > 0);
|
||||||
printf("Warning: font_h == 0\n");
|
assert(width > 0);
|
||||||
goto draw_win_cleanup;
|
assert(height > 0);
|
||||||
}
|
assert(line_cnt > 0);
|
||||||
resizedc(dc, width, dc_height * font_h);
|
|
||||||
|
resizedc(dc, width, height);
|
||||||
|
|
||||||
/* draw buffers */
|
/* draw buffers */
|
||||||
for (int i = 0; i < height; i++) {
|
dc->y = 0;
|
||||||
if (strlen(n_buf[i].txt) > 0) {
|
ColorSet *last_color;
|
||||||
notification *n;
|
assert(displayed_notifications->head != NULL);
|
||||||
n = n_buf[i].n;
|
for (l_node * iter = displayed_notifications->head; iter;
|
||||||
|
iter = iter->next) {
|
||||||
|
|
||||||
int done = False;
|
notification *n = (notification *) iter->data;
|
||||||
char *txt = n_buf[i].txt;
|
last_color = n->colors;
|
||||||
while (!done) {
|
|
||||||
int txtlen;
|
|
||||||
if (!word_wrap) {
|
|
||||||
txtlen = strlen(txt);
|
|
||||||
done = True;
|
|
||||||
} else {
|
|
||||||
txtlen = next_split(txt, width);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (txtlen < 0) {
|
for (int i = 0; i < n->draw_txt_buf.line_count; i++) {
|
||||||
done = True;
|
|
||||||
txtlen = strlen(txt);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
char *line = draw_txt_get_line(&n->draw_txt_buf, i + 1);
|
||||||
dc->x = 0;
|
dc->x = 0;
|
||||||
drawrect(dc, 0, 0, width, font_h, True,
|
drawrect(dc, 0, 0, width, font_h, True, n->colors->BG);
|
||||||
n->colors->BG);
|
|
||||||
|
|
||||||
/* calculate offset */
|
dc->x = calculate_x_offset(width, textw(dc, line));
|
||||||
if (align == right) {
|
drawtext(dc, line, n->colors);
|
||||||
dc->x = width - textnw(dc, txt, txtlen);
|
|
||||||
} else if (align == center) {
|
|
||||||
dc->x =
|
|
||||||
(width -
|
|
||||||
textnw(dc, txt, txtlen)) / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
drawtextn(dc, txt, txtlen, n->colors);
|
|
||||||
dc->y += font_h;
|
dc->y += font_h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
txt = txt + txtlen;
|
/* draw x_more */
|
||||||
}
|
if (x_more.txt) {
|
||||||
}
|
dc->x = 0;
|
||||||
|
drawrect(dc, 0, 0, width, font_h, True, last_color->BG);
|
||||||
|
dc->x = calculate_x_offset(width, textw(dc, x_more.txt));
|
||||||
|
drawtext(dc, x_more.txt, last_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* calculate window position */
|
/* calculate window position */
|
||||||
@ -587,19 +598,17 @@ void draw_win(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (geometry.mask & YNegative) {
|
if (geometry.mask & YNegative) {
|
||||||
y = scr.dim.y + (scr.dim.h + geometry.y) - dc_height * font_h;
|
y = scr.dim.y + (scr.dim.h + geometry.y) - height;
|
||||||
} else {
|
} else {
|
||||||
y = scr.dim.y + geometry.y;
|
y = scr.dim.y + geometry.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* move and map window */
|
/* move and map window */
|
||||||
XResizeWindow(dc->dpy, win, width, dc_height * font_h);
|
XResizeWindow(dc->dpy, win, width, height);
|
||||||
XMoveWindow(dc->dpy, win, x, y);
|
XMoveWindow(dc->dpy, win, x, y);
|
||||||
mapdc(dc, win, width, dc_height * font_h);
|
mapdc(dc, win, width, height);
|
||||||
|
|
||||||
draw_win_cleanup:
|
free(x_more.txt);
|
||||||
/* cleanup */
|
|
||||||
free(n_buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char
|
char
|
||||||
@ -796,6 +805,7 @@ int init_notification(notification * n, int id)
|
|||||||
n->msg = strtrim(n->msg);
|
n->msg = strtrim(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) {
|
||||||
|
8
dunst.h
8
dunst.h
@ -32,12 +32,19 @@ typedef struct _rule_t {
|
|||||||
|
|
||||||
} rule_t;
|
} rule_t;
|
||||||
|
|
||||||
|
typedef struct _draw_txt {
|
||||||
|
char *txt;
|
||||||
|
int line_count;
|
||||||
|
int bufsize;
|
||||||
|
} 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;
|
||||||
@ -67,6 +74,7 @@ typedef struct _keyboard_shortcut {
|
|||||||
int is_valid;
|
int is_valid;
|
||||||
} keyboard_shortcut;
|
} keyboard_shortcut;
|
||||||
|
|
||||||
|
|
||||||
extern int verbosity;
|
extern int verbosity;
|
||||||
|
|
||||||
/* return id of notification */
|
/* return id of notification */
|
||||||
|
20
utils.c
20
utils.c
@ -62,6 +62,26 @@ void dunst_printf(int level, const char *fmt, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int digit_count(int i)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
if ( i == 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < 0) {
|
||||||
|
len++;
|
||||||
|
i *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i > 0) {
|
||||||
|
len++;
|
||||||
|
i /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
void die(char *text, int exit_value)
|
void die(char *text, int exit_value)
|
||||||
{
|
{
|
||||||
fputs(text, stderr);
|
fputs(text, stderr);
|
||||||
|
2
utils.h
2
utils.h
@ -13,6 +13,8 @@ void die(char * msg, int exit_value);
|
|||||||
/* print depending on verbosity */
|
/* print depending on verbosity */
|
||||||
void dunst_printf(int level, const char *fmt, ...);
|
void dunst_printf(int level, const char *fmt, ...);
|
||||||
|
|
||||||
|
int digit_count(int i);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* vim: set ts=8 sw=8 tw=0: */
|
/* vim: set ts=8 sw=8 tw=0: */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user