@@ -88,11 +88,14 @@ static void set_font_options(cairo_t *cairo, struct mako_state *state) {
88
88
}
89
89
90
90
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 ,
92
93
struct mako_hotspot * hotspot , int progress ) {
93
94
int border_size = 2 * style -> border_size ;
94
95
int padding_height = style -> padding .top + style -> padding .bottom ;
95
96
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 ;
96
99
int radius = style -> border_radius ;
97
100
98
101
// 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,
113
116
114
117
set_font_options (cairo , state );
115
118
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
116
133
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 );
125
134
pango_layout_set_font_description (layout , desc );
126
135
pango_font_description_free (desc );
127
136
128
137
PangoAttrList * attrs = NULL ;
129
138
GError * error = NULL ;
130
139
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
+
131
184
if (pango_parse_markup (text , -1 , 0 , & attrs , & buf , NULL , & error )) {
132
185
pango_layout_set_text (layout , buf , -1 );
133
186
free (buf );
@@ -154,13 +207,16 @@ static int render_notification(cairo_t *cairo, struct mako_state *state,
154
207
}
155
208
int text_height = buffer_text_height / scale ;
156
209
157
- int notif_height = text_height + border_size + padding_height ;
210
+ int layout_height = text_height + padding_height + style -> border_size ;
158
211
if (icon != NULL && icon -> height > text_height ) {
159
- notif_height = icon -> height + border_size + padding_height ;
212
+ layout_height + = icon -> height - text_height ;
160
213
}
161
214
215
+ int notif_height = titlebar_height + layout_height ;
216
+
162
217
if (notif_height < radius * 2 ) {
163
218
notif_height = radius * 2 + border_size ;
219
+ layout_height = notif_height - titlebar_height ;
164
220
}
165
221
166
222
int notif_background_width = notif_width - style -> border_size ;
@@ -183,6 +239,34 @@ static int render_notification(cairo_t *cairo, struct mako_state *state,
183
239
// we have to create a new one for progress in the meantime.
184
240
cairo_path_t * border_path = cairo_copy_path (cairo );
185
241
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
+
186
270
// Render progress. We need to render this as a normal rectangle, but clip
187
271
// it to the rounded rectangle we drew for the background. We also inset it
188
272
// 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,
201
285
set_source_u32 (cairo , style -> colors .progress .value );
202
286
set_rounded_rectangle (cairo ,
203
287
offset_x + style -> border_size ,
204
- offset_y + style -> border_size ,
288
+ offset_y + titlebar_height ,
205
289
progress_width ,
206
- notif_height - style -> border_size ,
290
+ layout_height ,
207
291
scale , 0 );
208
292
cairo_fill (cairo );
209
293
cairo_restore (cairo );
@@ -226,17 +310,17 @@ static int render_notification(cairo_t *cairo, struct mako_state *state,
226
310
// Render icon
227
311
double xpos = offset_x + style -> border_size +
228
312
(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 ;
231
315
draw_icon (cairo , icon , xpos , ypos , scale );
232
316
}
233
317
234
318
// Render text
235
319
set_source_u32 (cairo , style -> colors .text );
236
320
move_to (cairo ,
237
321
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 ,
240
324
scale );
241
325
pango_cairo_update_layout (cairo , layout );
242
326
pango_cairo_show_layout (cairo , layout );
@@ -290,6 +374,16 @@ int render(struct mako_state *state, struct pool_buffer *buffer, int scale) {
290
374
continue ;
291
375
}
292
376
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
+
293
387
size_t text_len =
294
388
format_text (style -> format , NULL , format_notif_text , notif );
295
389
@@ -308,8 +402,9 @@ int render(struct mako_state *state, struct pool_buffer *buffer, int scale) {
308
402
309
403
struct mako_icon * icon = (style -> icons ) ? notif -> icon : NULL ;
310
404
int notif_height = render_notification (
311
- cairo , state , style , text , icon , total_height , scale ,
405
+ cairo , state , style , title , text , icon , total_height , scale ,
312
406
& notif -> hotspot , notif -> progress );
407
+ free (title );
313
408
free (text );
314
409
315
410
total_height += notif_height ;
@@ -346,6 +441,16 @@ int render(struct mako_state *state, struct pool_buffer *buffer, int scale) {
346
441
.count = count ,
347
442
};
348
443
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
+
349
454
size_t text_ln =
350
455
format_text (style .format , NULL , format_hidden_text , & data );
351
456
char * text = malloc (text_ln + 1 );
@@ -357,7 +462,8 @@ int render(struct mako_state *state, struct pool_buffer *buffer, int scale) {
357
462
format_text (style .format , text , format_hidden_text , & data );
358
463
359
464
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 );
361
467
free (text );
362
468
finish_style (& style );
363
469
0 commit comments