Skip to content

Commit a139f67

Browse files
committed
Render titlebar
This adds a titlebar to individual notifications. It will only render if titlebar-format is set in the config, and if there is text to render in it. Otherwise, the notification will render the same as it used to before this.
1 parent 0d52255 commit a139f67

File tree

1 file changed

+125
-19
lines changed

1 file changed

+125
-19
lines changed

render.c

+125-19
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,14 @@ static void set_font_options(cairo_t *cairo, struct mako_state *state) {
8888
}
8989

9090
static int render_notification(cairo_t *cairo, struct mako_state *state,
91-
struct mako_style *style, const char *text, struct mako_icon *icon, int offset_y, int scale,
91+
struct mako_style *style, const char *title, const char *text,
92+
struct mako_icon *icon, int offset_y, int scale,
9293
struct mako_hotspot *hotspot, int progress) {
9394
int border_size = 2 * style->border_size;
9495
int padding_height = style->padding.top + style->padding.bottom;
9596
int padding_width = style->padding.left + style->padding.right;
97+
int title_padding_height = style->title_padding.top + style->title_padding.bottom;
98+
int title_padding_width = style->title_padding.left + style->title_padding.right;
9699
int radius = style->border_radius;
97100

98101
// If the compositor has forced us to shrink down, do so.
@@ -113,21 +116,71 @@ static int render_notification(cairo_t *cairo, struct mako_state *state,
113116

114117
set_font_options(cairo, state);
115118

119+
PangoFontDescription *desc = pango_font_description_from_string(style->font);
120+
PangoLayout *title_layout = NULL;
121+
122+
if (strcmp(style->title_format, "") != 0) {
123+
title_layout = pango_cairo_create_layout(cairo);
124+
set_layout_size(title_layout,
125+
notif_width - border_size - title_padding_width,
126+
0, scale);
127+
128+
pango_layout_set_ellipsize(title_layout, PANGO_ELLIPSIZE_END);
129+
pango_layout_set_font_description(title_layout, desc);
130+
}
131+
132+
// Create layout early and set the font so we can free it
116133
PangoLayout *layout = pango_cairo_create_layout(cairo);
117-
set_layout_size(layout,
118-
notif_width - border_size - padding_width - text_x,
119-
style->height - border_size - padding_height,
120-
scale);
121-
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
122-
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
123-
PangoFontDescription *desc =
124-
pango_font_description_from_string(style->font);
125134
pango_layout_set_font_description(layout, desc);
126135
pango_font_description_free(desc);
127136

128137
PangoAttrList *attrs = NULL;
129138
GError *error = NULL;
130139
char *buf = NULL;
140+
141+
int title_height = 0;
142+
int titlebar_height = style->border_size;
143+
144+
if (strcmp(style->title_format, "") != 0) {
145+
if (pango_parse_markup(title, -1, 0, &attrs, &buf, NULL, &error)) {
146+
pango_layout_set_text(title_layout, buf, -1);
147+
free(buf);
148+
} else {
149+
fprintf(stderr, "cannot parse pango markup: %s\n", error->message);
150+
g_error_free(error);
151+
// fallback to plain text
152+
pango_layout_set_text(title_layout, title, -1);
153+
}
154+
155+
if (attrs == NULL) {
156+
attrs = pango_attr_list_new();
157+
}
158+
pango_attr_list_insert(attrs, pango_attr_scale_new(scale));
159+
pango_layout_set_attributes(title_layout, attrs);
160+
pango_attr_list_unref(attrs);
161+
162+
int buffer_title_height = 0;
163+
164+
// If there's no text to be rendered, the titlebar won't be rendered at all
165+
if (pango_layout_get_character_count(title_layout) > 0) {
166+
pango_layout_get_pixel_size(title_layout, NULL, &buffer_title_height);
167+
title_height = buffer_title_height / scale;
168+
titlebar_height = title_height + title_padding_height;
169+
}
170+
}
171+
172+
attrs = NULL;
173+
error = NULL;
174+
buf = NULL;
175+
176+
set_layout_size(layout,
177+
notif_width - border_size - padding_width - text_x,
178+
style->height - border_size - padding_height - title_height,
179+
scale);
180+
181+
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
182+
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
183+
131184
if (pango_parse_markup(text, -1, 0, &attrs, &buf, NULL, &error)) {
132185
pango_layout_set_text(layout, buf, -1);
133186
free(buf);
@@ -154,13 +207,16 @@ static int render_notification(cairo_t *cairo, struct mako_state *state,
154207
}
155208
int text_height = buffer_text_height / scale;
156209

157-
int notif_height = text_height + border_size + padding_height;
210+
int layout_height = text_height + padding_height + style->border_size;
158211
if (icon != NULL && icon->height > text_height) {
159-
notif_height = icon->height + border_size + padding_height;
212+
layout_height += icon->height - text_height;
160213
}
161214

215+
int notif_height = titlebar_height + layout_height;
216+
162217
if (notif_height < radius * 2) {
163218
notif_height = radius * 2 + border_size;
219+
layout_height = notif_height - titlebar_height;
164220
}
165221

166222
int notif_background_width = notif_width - style->border_size;
@@ -183,6 +239,34 @@ static int render_notification(cairo_t *cairo, struct mako_state *state,
183239
// we have to create a new one for progress in the meantime.
184240
cairo_path_t *border_path = cairo_copy_path(cairo);
185241

242+
// Render the titlebar
243+
if (title_height > 0) {
244+
cairo_save(cairo);
245+
cairo_clip(cairo);
246+
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
247+
set_source_u32(cairo, style->colors.border);
248+
set_rounded_rectangle(cairo,
249+
offset_x,
250+
offset_y,
251+
notif_background_width,
252+
titlebar_height,
253+
scale, radius);
254+
cairo_fill(cairo);
255+
cairo_restore(cairo);
256+
257+
// Some of the operations above reset the path, without this progress won't render
258+
cairo_append_path(cairo, border_path);
259+
260+
// Render title
261+
set_source_u32(cairo, style->colors.title);
262+
move_to(cairo,
263+
offset_x + style->title_padding.left + style->border_size,
264+
offset_y + style->title_padding.top,
265+
scale);
266+
pango_cairo_update_layout(cairo, title_layout);
267+
pango_cairo_show_layout(cairo, title_layout);
268+
}
269+
186270
// Render progress. We need to render this as a normal rectangle, but clip
187271
// it to the rounded rectangle we drew for the background. We also inset it
188272
// a bit further so that 0 and 100 percent are aligned to the inside edge
@@ -201,9 +285,9 @@ static int render_notification(cairo_t *cairo, struct mako_state *state,
201285
set_source_u32(cairo, style->colors.progress.value);
202286
set_rounded_rectangle(cairo,
203287
offset_x + style->border_size,
204-
offset_y + style->border_size,
288+
offset_y + titlebar_height,
205289
progress_width,
206-
notif_height - style->border_size,
290+
layout_height,
207291
scale, 0);
208292
cairo_fill(cairo);
209293
cairo_restore(cairo);
@@ -226,17 +310,17 @@ static int render_notification(cairo_t *cairo, struct mako_state *state,
226310
// Render icon
227311
double xpos = offset_x + style->border_size +
228312
(text_x - icon->width) / 2;
229-
double ypos = offset_y + style->border_size +
230-
(notif_height - icon->height - border_size) / 2;
313+
double ypos = offset_y + titlebar_height +
314+
(layout_height - icon->height - style->border_size) / 2;
231315
draw_icon(cairo, icon, xpos, ypos, scale);
232316
}
233317

234318
// Render text
235319
set_source_u32(cairo, style->colors.text);
236320
move_to(cairo,
237321
offset_x + style->border_size + text_x,
238-
offset_y + style->border_size +
239-
(double)(notif_height - border_size - text_height) / 2,
322+
offset_y + titlebar_height +
323+
(double)(layout_height - text_height - style->border_size) / 2,
240324
scale);
241325
pango_cairo_update_layout(cairo, layout);
242326
pango_cairo_show_layout(cairo, layout);
@@ -290,6 +374,16 @@ int render(struct mako_state *state, struct pool_buffer *buffer, int scale) {
290374
continue;
291375
}
292376

377+
size_t title_len =
378+
format_text(style->title_format, NULL, format_notif_text, notif);
379+
380+
char *title = malloc(title_len + 1);
381+
if (title == NULL) {
382+
fprintf(stderr, "Unable to allocate memory to render notification\n");
383+
break;
384+
}
385+
format_text(style->title_format, title, format_notif_text, notif);
386+
293387
size_t text_len =
294388
format_text(style->format, NULL, format_notif_text, notif);
295389

@@ -308,8 +402,9 @@ int render(struct mako_state *state, struct pool_buffer *buffer, int scale) {
308402

309403
struct mako_icon *icon = (style->icons) ? notif->icon : NULL;
310404
int notif_height = render_notification(
311-
cairo, state, style, text, icon, total_height, scale,
405+
cairo, state, style, title, text, icon, total_height, scale,
312406
&notif->hotspot, notif->progress);
407+
free(title);
313408
free(text);
314409

315410
total_height += notif_height;
@@ -346,6 +441,16 @@ int render(struct mako_state *state, struct pool_buffer *buffer, int scale) {
346441
.count = count,
347442
};
348443

444+
size_t title_ln =
445+
format_text(style.title_format, NULL, format_hidden_text, &data);
446+
char *title = malloc(title_ln + 1);
447+
if (title == NULL) {
448+
fprintf(stderr, "allocation failed");
449+
return 0;
450+
}
451+
452+
format_text(style.title_format, title, format_hidden_text, &data);
453+
349454
size_t text_ln =
350455
format_text(style.format, NULL, format_hidden_text, &data);
351456
char *text = malloc(text_ln + 1);
@@ -357,7 +462,8 @@ int render(struct mako_state *state, struct pool_buffer *buffer, int scale) {
357462
format_text(style.format, text, format_hidden_text, &data);
358463

359464
int hidden_height = render_notification(
360-
cairo, state, &style, text, NULL, total_height, scale, NULL, 0);
465+
cairo, state, &style, title, text, NULL, total_height, scale, NULL, 0);
466+
free(title);
361467
free(text);
362468
finish_style(&style);
363469

0 commit comments

Comments
 (0)