Merge pull request #775 from fwSmit/progress-bar

Add progress bar
This commit is contained in:
Nikos Tsipinakis 2020-11-10 11:55:02 +02:00 committed by GitHub
commit 3d3ba4b9c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 245 additions and 10 deletions

View File

@ -6,10 +6,13 @@ struct settings defaults = {
.markup = MARKUP_NO, .markup = MARKUP_NO,
.colors_norm.bg = "#1793D1", .colors_norm.bg = "#1793D1",
.colors_norm.fg = "#DDDDDD", .colors_norm.fg = "#DDDDDD",
.colors_norm.highlight = "#1745d1",
.colors_crit.bg = "#ffaaaa", .colors_crit.bg = "#ffaaaa",
.colors_crit.fg = "#000000", .colors_crit.fg = "#000000",
.colors_crit.highlight = "#ff6666",
.colors_low.bg = "#aaaaff", .colors_low.bg = "#aaaaff",
.colors_low.fg = "#000000", .colors_low.fg = "#000000",
.colors_low.highlight = "#7f7fff",
.format = "%s %b", /* default format */ .format = "%s %b", /* default format */
.timeouts = { S2US(10), S2US(10), S2US(0) }, /* low, normal, critical */ .timeouts = { S2US(10), S2US(10), S2US(0) }, /* low, normal, critical */
@ -110,6 +113,15 @@ struct settings defaults = {
.mouse_right_click = (enum mouse_action []){MOUSE_CLOSE_ALL, -1}, .mouse_right_click = (enum mouse_action []){MOUSE_CLOSE_ALL, -1},
.progress_bar_height = 10,
.progress_bar_min_width = 150,
.progress_bar_max_width = 300,
.progress_bar_frame_width = 1,
.progress_bar = true,
}; };
struct rule default_rules[] = { struct rule default_rules[] = {

View File

@ -142,6 +142,32 @@ the notification on the left border of the screen while a horizontal offset of
=back =back
=item B<progress_bar> (values: [true/false], default: true)
When an integer value is passed to dunst as a hint (see B<NOTIFY-SEND>), a
progress bar will be drawn at the bottom of the notification. This
behavior can be turned off by setting this setting to false.
=item B<progress_bar_height> (default: 10)
The height of the progress bar in pixel. This includes the frame. Make sure
this value is bigger than twice the frame width.
=item B<progress_bar_min_width> (default: 150)
The minimum width of the progress bar in pixels. The notification is rescaled
to fit the bar.
=item B<progress_bar_max_width> (default: 300)
The maximum width of the progress bar in pixels. The notification is resized
to fit the progress bar.
=item B<progress_bar_frame_width> (default: 1)
The frame width of the progress bar in pixels. This value should be smaller
than half of the progress bar height.
=item B<indicate_hidden> (values: [true/false], default: true) =item B<indicate_hidden> (values: [true/false], default: true)
If this is set to true, a notification indicating how many notifications are If this is set to true, a notification indicating how many notifications are
@ -561,8 +587,8 @@ Specifies the keyboard shortcut that opens the context menu.
The urgency sections work in a similar way to rules and can be used to specify The urgency sections work in a similar way to rules and can be used to specify
attributes for the different urgency levels of notifications (low, normal, attributes for the different urgency levels of notifications (low, normal,
critical). Currently only the background, foreground, timeout, frame_color and critical). Currently only the background, foreground, hightlight, timeout,
icon attributes can be modified. frame_color and icon attributes can be modified.
The urgency sections are urgency_low, urgency_normal, urgency_critical for low, The urgency sections are urgency_low, urgency_normal, urgency_critical for low,
normal and critical urgency respectively. normal and critical urgency respectively.
@ -595,6 +621,12 @@ Defines the background color for low, normal and critical notifications respecti
See COLORS for the value format. See COLORS for the value format.
=item B<-lh/nh/ch color>
Defines the highlight color for low, normal and critical notifications respectively.
See COLORS for the value format.
=item B<-lfr/nfr/cfr color> =item B<-lfr/nfr/cfr color>
Defines the frame color for low, normal and critical notifications respectively. Defines the frame color for low, normal and critical notifications respectively.
@ -725,7 +757,12 @@ The background color of the notification. See COLORS for possible values.
=item C<foreground> =item C<foreground>
The background color of the notification. See COLORS for possible values. The foreground color of the notification. See COLORS for possible values.
=item C<highlight>
The highlight color of the notification. This color is used for coloring the
progress bar. See COLORS for possible values.
=item C<format> =item C<format>

17
dunstrc
View File

@ -31,6 +31,23 @@
# screen width minus the width defined in within the geometry option. # screen width minus the width defined in within the geometry option.
geometry = "300x5-30+20" geometry = "300x5-30+20"
# Turn on the progess bar
progress_bar = true
# Set the progress bar height. This includes the frame, so make sure
# it's at least twice as big as the frame width.
progress_bar_height = 10
# Set the frame width of the progress bar
progress_bar_frame_width = 1
# Set the minimum width for the progress bar
progress_bar_min_width = 150
# Set the maximum width for the progress bar
progress_bar_max_width = 300
# Show how many messages are currently hidden (because of geometry). # Show how many messages are currently hidden (because of geometry).
indicate_hidden = yes indicate_hidden = yes

View File

@ -23,6 +23,7 @@ struct colored_layout {
PangoLayout *l; PangoLayout *l;
struct color fg; struct color fg;
struct color bg; struct color bg;
struct color highlight;
struct color frame; struct color frame;
char *text; char *text;
PangoAttrList *attr; PangoAttrList *attr;
@ -166,6 +167,11 @@ static bool have_dynamic_width(void)
return (settings.geometry.width_set && settings.geometry.w == 0); return (settings.geometry.width_set && settings.geometry.w == 0);
} }
static bool have_progress_bar(const struct notification *n)
{
return (n->progress >= 0 && settings.progress_bar == true);
}
static struct dimensions calculate_dimensions(GSList *layouts) static struct dimensions calculate_dimensions(GSList *layouts)
{ {
struct dimensions dim = { 0 }; struct dimensions dim = { 0 };
@ -237,6 +243,11 @@ static struct dimensions calculate_dimensions(GSList *layouts)
text_width = MAX(w, text_width); text_width = MAX(w, text_width);
} }
if (have_progress_bar(cl->n)){
dim.h += settings.progress_bar_height + settings.padding;
dim.w = MAX(dim.w, settings.progress_bar_min_width);
}
dim.corner_radius = MIN(dim.corner_radius, h/2); dim.corner_radius = MIN(dim.corner_radius, h/2);
} }
@ -299,6 +310,7 @@ static struct colored_layout *layout_init_shared(cairo_t *c, const struct notifi
cl->fg = string_to_color(n->colors.fg); cl->fg = string_to_color(n->colors.fg);
cl->bg = string_to_color(n->colors.bg); cl->bg = string_to_color(n->colors.bg);
cl->highlight = string_to_color(n->colors.highlight);
cl->frame = string_to_color(n->colors.frame); cl->frame = string_to_color(n->colors.frame);
cl->n = n; cl->n = n;
@ -354,7 +366,13 @@ static struct colored_layout *layout_from_notification(cairo_t *c, struct notifi
pango_layout_get_pixel_size(cl->l, NULL, &(n->displayed_height)); pango_layout_get_pixel_size(cl->l, NULL, &(n->displayed_height));
if (cl->icon) n->displayed_height = MAX(cairo_image_surface_get_height(cl->icon), n->displayed_height); if (cl->icon) n->displayed_height = MAX(cairo_image_surface_get_height(cl->icon), n->displayed_height);
n->displayed_height = MAX(settings.notification_height, n->displayed_height + settings.padding * 2);
n->displayed_height = n->displayed_height + settings.padding * 2;
// progress bar
if (have_progress_bar(n)) n->displayed_height += settings.progress_bar_height + settings.padding;
n->displayed_height = MAX(settings.notification_height, n->displayed_height);
n->first_render = false; n->first_render = false;
return cl; return cl;
@ -397,11 +415,16 @@ static int layout_get_height(struct colored_layout *cl)
{ {
int h; int h;
int h_icon = 0; int h_icon = 0;
int h_progress_bar = 0;
pango_layout_get_pixel_size(cl->l, NULL, &h); pango_layout_get_pixel_size(cl->l, NULL, &h);
if (cl->icon) if (cl->icon)
h_icon = cairo_image_surface_get_height(cl->icon); h_icon = cairo_image_surface_get_height(cl->icon);
if (have_progress_bar(cl->n)){
h_progress_bar = settings.progress_bar_height + settings.padding;
}
return MAX(h, h_icon); int res = MAX(h, h_icon) + h_progress_bar;
return res;
} }
/* Attempt to make internal radius more organic. /* Attempt to make internal radius more organic.
@ -563,11 +586,15 @@ static cairo_surface_t *render_background(cairo_surface_t *srf,
static void render_content(cairo_t *c, struct colored_layout *cl, int width) static void render_content(cairo_t *c, struct colored_layout *cl, int width)
{ {
const int h = layout_get_height(cl); const int h = layout_get_height(cl);
int h_without_progress_bar = h;
if (have_progress_bar(cl->n)){
h_without_progress_bar -= settings.progress_bar_height + settings.padding;
}
int h_text; int h_text;
pango_layout_get_pixel_size(cl->l, NULL, &h_text); pango_layout_get_pixel_size(cl->l, NULL, &h_text);
int text_x = settings.h_padding, int text_x = settings.h_padding,
text_y = settings.padding + h / 2 - h_text / 2; text_y = settings.padding + h_without_progress_bar / 2 - h_text / 2;
// text positioning // text positioning
if (cl->icon) { if (cl->icon) {
@ -575,7 +602,7 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width)
if (settings.vertical_alignment == VERTICAL_TOP) { if (settings.vertical_alignment == VERTICAL_TOP) {
text_y = settings.padding; text_y = settings.padding;
} else if (settings.vertical_alignment == VERTICAL_BOTTOM) { } else if (settings.vertical_alignment == VERTICAL_BOTTOM) {
text_y = h + settings.padding - h_text; text_y = h_without_progress_bar + settings.padding - h_text;
if (text_y < 0) if (text_y < 0)
text_y = settings.padding; text_y = settings.padding;
} // else VERTICAL_CENTER } // else VERTICAL_CENTER
@ -597,14 +624,14 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width)
unsigned int image_width = cairo_image_surface_get_width(cl->icon), unsigned int image_width = cairo_image_surface_get_width(cl->icon),
image_height = cairo_image_surface_get_height(cl->icon), image_height = cairo_image_surface_get_height(cl->icon),
image_x = width - settings.h_padding - image_width, image_x = width - settings.h_padding - image_width,
image_y = settings.padding + h/2 - image_height/2; image_y = settings.padding + h_without_progress_bar/2 - image_height/2;
// vertical alignment // vertical alignment
if (settings.vertical_alignment == VERTICAL_TOP) { if (settings.vertical_alignment == VERTICAL_TOP) {
image_y = settings.padding; image_y = settings.padding;
} else if (settings.vertical_alignment == VERTICAL_BOTTOM) { } else if (settings.vertical_alignment == VERTICAL_BOTTOM) {
image_y = h + settings.padding - image_height; image_y = h_without_progress_bar + settings.padding - image_height;
if (image_y < settings.padding || image_y > h) if (image_y < settings.padding || image_y > h_without_progress_bar)
image_y = settings.padding; image_y = settings.padding;
} // else VERTICAL_CENTER } // else VERTICAL_CENTER
@ -618,6 +645,38 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width)
cairo_fill(c); cairo_fill(c);
} }
// progress bar positioning
if (have_progress_bar(cl->n)){
int progress = MIN(cl->n->progress, 100);
unsigned int frame_width = settings.progress_bar_frame_width,
progress_width = MIN(width - 2 * settings.h_padding, settings.progress_bar_max_width),
progress_height = settings.progress_bar_height - frame_width,
frame_x = settings.h_padding,
frame_y = settings.padding + h - settings.progress_bar_height,
progress_width_without_frame = progress_width - 2 * frame_width,
progress_width_1 = progress_width_without_frame * progress / 100,
progress_width_2 = progress_width_without_frame - progress_width_1,
x_bar_1 = frame_x + frame_width,
x_bar_2 = x_bar_1 + progress_width_1;
double half_frame_width = frame_width / 2.0;
// draw progress bar
// Note: the bar could be drawn a bit smaller, because the frame is drawn on top
// left side
cairo_set_source_rgba(c, cl->highlight.r, cl->highlight.g, cl->highlight.b, cl->highlight.a);
cairo_rectangle(c, x_bar_1, frame_y, progress_width_1, progress_height);
cairo_fill(c);
// right side
cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a);
cairo_rectangle(c, x_bar_2, frame_y, progress_width_2, progress_height);
cairo_fill(c);
// border
cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a);
cairo_rectangle(c, frame_x + half_frame_width, frame_y + half_frame_width, progress_width - frame_width, progress_height);
cairo_set_line_width(c, frame_width);
cairo_stroke(c);
}
} }
static struct dimensions layout_render(cairo_surface_t *srf, static struct dimensions layout_render(cairo_surface_t *srf,

View File

@ -64,6 +64,7 @@ void notification_print(const struct notification *n)
printf("\tformatted: '%s'\n", n->msg); printf("\tformatted: '%s'\n", n->msg);
printf("\tfg: %s\n", n->colors.fg); printf("\tfg: %s\n", n->colors.fg);
printf("\tbg: %s\n", n->colors.bg); printf("\tbg: %s\n", n->colors.bg);
printf("\thighlight: %s\n", n->colors.highlight);
printf("\tframe: %s\n", n->colors.frame); printf("\tframe: %s\n", n->colors.frame);
printf("\tfullscreen: %s\n", enum_to_string_fullscreen(n->fullscreen)); printf("\tfullscreen: %s\n", enum_to_string_fullscreen(n->fullscreen));
printf("\tprogress: %d\n", n->progress); printf("\tprogress: %d\n", n->progress);
@ -236,6 +237,7 @@ void notification_unref(struct notification *n)
g_free(n->urls); g_free(n->urls);
g_free(n->colors.fg); g_free(n->colors.fg);
g_free(n->colors.bg); g_free(n->colors.bg);
g_free(n->colors.highlight);
g_free(n->colors.frame); g_free(n->colors.frame);
g_free(n->stack_tag); g_free(n->stack_tag);
g_free(n->desktop_entry); g_free(n->desktop_entry);
@ -393,6 +395,8 @@ void notification_init(struct notification *n)
n->colors.fg = g_strdup(defcolors.fg); n->colors.fg = g_strdup(defcolors.fg);
if (!n->colors.bg) if (!n->colors.bg)
n->colors.bg = g_strdup(defcolors.bg); n->colors.bg = g_strdup(defcolors.bg);
if (!n->colors.highlight)
n->colors.highlight = g_strdup(defcolors.highlight);
if (!n->colors.frame) if (!n->colors.frame)
n->colors.frame = g_strdup(defcolors.frame); n->colors.frame = g_strdup(defcolors.frame);

View File

@ -33,6 +33,7 @@ struct notification_colors {
char *frame; char *frame;
char *bg; char *bg;
char *fg; char *fg;
char *highlight;
}; };
struct notification { struct notification {

View File

@ -38,6 +38,10 @@ void rule_apply(struct rule *r, struct notification *n)
g_free(n->colors.bg); g_free(n->colors.bg);
n->colors.bg = g_strdup(r->bg); n->colors.bg = g_strdup(r->bg);
} }
if (r->highlight) {
g_free(n->colors.highlight);
n->colors.highlight = g_strdup(r->highlight);
}
if (r->fc) { if (r->fc) {
g_free(n->colors.frame); g_free(n->colors.frame);
n->colors.frame = g_strdup(r->fc); n->colors.frame = g_strdup(r->fc);

View File

@ -31,6 +31,7 @@ struct rule {
char *new_icon; char *new_icon;
char *fg; char *fg;
char *bg; char *bg;
char *highlight;
char *fc; char *fc;
const char *format; const char *format;
const char *script; const char *script;

View File

@ -355,6 +355,49 @@ void load_settings(char *cmdline_config_path)
"Window corner radius" "Window corner radius"
); );
settings.progress_bar_height = option_get_int(
"global",
"progress_bar_height", "-progress_bar_height", defaults.progress_bar_height,
"Height of the progress bar"
);
settings.progress_bar_min_width = option_get_int(
"global",
"progress_bar_min_width", "-progress_bar_min_width", defaults.progress_bar_min_width,
"Minimum width of the progress bar"
);
settings.progress_bar_max_width = option_get_int(
"global",
"progress_bar_max_width", "-progress_bar_max_width", defaults.progress_bar_max_width,
"Maximum width of the progress bar"
);
settings.progress_bar_frame_width = option_get_int(
"global",
"progress_bar_frame_width", "-progress_bar_frame_width", defaults.progress_bar_frame_width,
"Frame width of the progress bar"
);
settings.progress_bar = option_get_bool(
"global",
"progress_bar", "-progress_bar", true,
"Show the progress bar"
);
// check sanity of the progress bar options
{
if (settings.progress_bar_height < (2 * settings.progress_bar_frame_width)){
LOG_E("setting progress_bar_frame_width is bigger than half of progress_bar_height");
}
if (settings.progress_bar_max_width < (2 * settings.progress_bar_frame_width)){
LOG_E("setting progress_bar_frame_width is bigger than half of progress_bar_max_width");
}
if (settings.progress_bar_max_width < settings.progress_bar_min_width){
LOG_E("setting progress_bar_max_width is smaller than progress_bar_min_width");
}
}
{ {
char *c = option_get_string( char *c = option_get_string(
"global", "global",
@ -584,6 +627,12 @@ void load_settings(char *cmdline_config_path)
"Foreground color for notifications with low urgency" "Foreground color for notifications with low urgency"
); );
settings.colors_low.highlight = option_get_string(
"urgency_low",
"highlight", "-lh", defaults.colors_low.highlight,
"Highlight color for notifications with low urgency"
);
settings.colors_low.frame = option_get_string( settings.colors_low.frame = option_get_string(
"urgency_low", "urgency_low",
"frame_color", "-lfr", settings.frame_color ? settings.frame_color : defaults.colors_low.frame, "frame_color", "-lfr", settings.frame_color ? settings.frame_color : defaults.colors_low.frame,
@ -614,6 +663,12 @@ void load_settings(char *cmdline_config_path)
"Foreground color for notifications with normal urgency" "Foreground color for notifications with normal urgency"
); );
settings.colors_norm.highlight = option_get_string(
"urgency_normal",
"highlight", "-nh", defaults.colors_norm.highlight,
"Highlight color for notifications with normal urgency"
);
settings.colors_norm.frame = option_get_string( settings.colors_norm.frame = option_get_string(
"urgency_normal", "urgency_normal",
"frame_color", "-nfr", settings.frame_color ? settings.frame_color : defaults.colors_norm.frame, "frame_color", "-nfr", settings.frame_color ? settings.frame_color : defaults.colors_norm.frame,
@ -644,6 +699,12 @@ void load_settings(char *cmdline_config_path)
"Foreground color for notifications with ciritical urgency" "Foreground color for notifications with ciritical urgency"
); );
settings.colors_crit.highlight = option_get_string(
"urgency_critical",
"highlight", "-ch", defaults.colors_crit.highlight,
"Highlight color for notifications with ciritical urgency"
);
settings.colors_crit.frame = option_get_string( settings.colors_crit.frame = option_get_string(
"urgency_critical", "urgency_critical",
"frame_color", "-cfr", settings.frame_color ? settings.frame_color : defaults.colors_crit.frame, "frame_color", "-cfr", settings.frame_color ? settings.frame_color : defaults.colors_crit.frame,
@ -756,6 +817,7 @@ void load_settings(char *cmdline_config_path)
r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_urgency); r->msg_urgency = ini_get_urgency(cur_section, "msg_urgency", r->msg_urgency);
r->fg = ini_get_string(cur_section, "foreground", r->fg); r->fg = ini_get_string(cur_section, "foreground", r->fg);
r->bg = ini_get_string(cur_section, "background", r->bg); r->bg = ini_get_string(cur_section, "background", r->bg);
r->bg = ini_get_string(cur_section, "highlight", r->highlight);
r->fc = ini_get_string(cur_section, "frame_color", r->fc); r->fc = ini_get_string(cur_section, "frame_color", r->fc);
r->format = ini_get_string(cur_section, "format", r->format); r->format = ini_get_string(cur_section, "format", r->format);
r->new_icon = ini_get_string(cur_section, "new_icon", r->new_icon); r->new_icon = ini_get_string(cur_section, "new_icon", r->new_icon);

View File

@ -92,6 +92,11 @@ struct settings {
enum mouse_action *mouse_left_click; enum mouse_action *mouse_left_click;
enum mouse_action *mouse_middle_click; enum mouse_action *mouse_middle_click;
enum mouse_action *mouse_right_click; enum mouse_action *mouse_right_click;
int progress_bar_height;
int progress_bar_min_width;
int progress_bar_max_width;
int progress_bar_frame_width;
bool progress_bar;
}; };
extern struct settings settings; extern struct settings settings;

View File

@ -0,0 +1,10 @@
[global]
font = Monospace 8
allow_markup = yes
format = "<b>%s</b>\n%b"
geometry = "0x5-30+20"
icon_position = left
progress_bar_min_width = 100
progress_bar_max_width = 200
progress_bar_frame_width = 5
progress_bar_height = 30

View File

@ -177,12 +177,35 @@ function geometry {
keypress keypress
} }
function progress_bar {
killall dunst
../../dunst -config dunstrc.default &
../../dunstify -h int:value:0 -a "dunst tester" -u c "Progress bar 0%: "
../../dunstify -h int:value:33 -a "dunst tester" -u c "Progress bar 33%: "
../../dunstify -h int:value:66 -a "dunst tester" -u c "Progress bar 66%: "
../../dunstify -h int:value:100 -a "dunst tester" -u c "Progress bar 100%: "
keypress
killall dunst
../../dunst -config dunstrc.default &
../../dunstify -h int:value:33 -a "dunst tester" -u l "Low priority: "
../../dunstify -h int:value:33 -a "dunst tester" -u n "Normal priority: "
../../dunstify -h int:value:33 -a "dunst tester" -u c "Critical priority: "
keypress
killall dunst
../../dunst -config dunstrc.progress_bar &
../../dunstify -h int:value:33 -a "dunst tester" -u n "The progress bar should not be the entire width"
../../dunstify -h int:value:33 -a "dunst tester" -u n "You might also notice height and frame size are changed"
../../dunstify -h int:value:33 -a "dunst tester" -u c "Short"
keypress
}
if [ -n "$1" ]; then if [ -n "$1" ]; then
while [ -n "$1" ]; do while [ -n "$1" ]; do
$1 $1
shift shift
done done
else else
progress_bar
geometry geometry
corners corners
show_age show_age