Skip to content

Commit a6e1d4e

Browse files
authored
Merge pull request #1330 from bynect/change-lengths
Refactor length parsing and make offset use the (N,N) syntax
2 parents b354f47 + 9de5769 commit a6e1d4e

File tree

9 files changed

+90
-90
lines changed

9 files changed

+90
-90
lines changed

docs/dunst.5.pod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,9 @@ notification being off screen.
141141

142142
Examples:
143143
origin = top-right
144-
offset = 10x300 # a margin of 10 pixels from the right and 300 pixels from the top
144+
offset = (10, 300) # a margin of 10 pixels from the right and 300 pixels from the top
145+
146+
For backwards compatibility the syntax NxN is also accepted.
145147

146148
=item B<scale> (default: 0, X11 only)
147149

dunstrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
origin = top-right
3434

3535
# Offset from the origin
36-
offset = 10x50
36+
offset = (10, 50)
3737

3838
# Scale factor. It is auto-detected if value is 0.
3939
scale = 0

src/draw.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ static void layout_setup(struct colored_layout *cl, int width, int height, doubl
202202
int icon_width = cl->icon ? get_icon_width(cl->icon, scale) + horizontal_padding : 0;
203203
int text_width = width - 2 * settings.h_padding - (cl->n->icon_position == ICON_TOP ? 0 : icon_width);
204204
int progress_bar_height = have_progress_bar(cl) ? settings.progress_bar_height + settings.padding : 0;
205-
int max_text_height = MAX(0, settings.height - progress_bar_height - 2 * settings.padding);
205+
int max_text_height = MAX(0, settings.height.max - progress_bar_height - 2 * settings.padding);
206206
layout_setup_pango(cl->l, text_width, max_text_height, cl->n->word_wrap, cl->n->ellipsize, cl->n->alignment);
207207
}
208208

@@ -219,7 +219,7 @@ static void free_colored_layout(void *data)
219219
static struct dimensions calculate_notification_dimensions(struct colored_layout *cl, double scale)
220220
{
221221
struct dimensions dim = { 0 };
222-
layout_setup(cl, settings.width.max, settings.height, scale);
222+
layout_setup(cl, settings.width.max, settings.height.max, scale);
223223

224224
int horizontal_padding = get_horizontal_text_icon_padding(cl->n);
225225
int icon_width = cl->icon? get_icon_width(cl->icon, scale) + horizontal_padding : 0;
@@ -245,7 +245,7 @@ static struct dimensions calculate_notification_dimensions(struct colored_layout
245245
dim.h += progress_bar_height;
246246
dim.w = dim.text_width + icon_width + 2 * settings.h_padding;
247247

248-
dim.h = MIN(settings.height, dim.h + settings.padding * 2);
248+
dim.h = MIN(settings.height.max, dim.h + settings.padding * 2);
249249
dim.w = MAX(settings.width.min, dim.w);
250250
if (have_progress_bar(cl))
251251
dim.w = MAX(settings.progress_bar_min_width, dim.w);
@@ -709,7 +709,7 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou
709709
{
710710
// Redo layout setup, while knowing the width. This is to make
711711
// alignment work correctly
712-
layout_setup(cl, width, settings.height, scale);
712+
layout_setup(cl, width, settings.height.max, scale);
713713

714714
const int h = layout_get_height(cl, scale);
715715
LOG_D("Layout height %i", h);
@@ -852,7 +852,7 @@ static struct dimensions layout_render(cairo_surface_t *srf,
852852
get_text_size(cl->l, NULL, &h_text, scale);
853853

854854
int bg_width = 0;
855-
int bg_height = MIN(settings.height, (2 * settings.padding) + cl_h);
855+
int bg_height = MIN(settings.height.max, (2 * settings.padding) + cl_h);
856856

857857
cairo_surface_t *content = render_background(srf, cl, cl_next, dim.y, dim.w, bg_height, dim.corner_radius, corners, &bg_width, scale);
858858
cairo_t *c = cairo_create(content);
@@ -866,10 +866,10 @@ static struct dimensions layout_render(cairo_surface_t *srf,
866866
if (corners & (C_BOT | _C_LAST))
867867
dim.y += settings.frame_width;
868868

869-
if ((2 * settings.padding + cl_h) < settings.height)
869+
if ((2 * settings.padding + cl_h) < settings.height.max)
870870
dim.y += cl_h + 2 * settings.padding;
871871
else
872-
dim.y += settings.height;
872+
dim.y += settings.height.max;
873873

874874
if (settings.gap_size)
875875
dim.y += settings.gap_size;

src/option_parser.c

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,13 @@ int string_parse_list(const void *data, const char *s, void *ret) {
131131
switch (type) {
132132
case MOUSE_LIST:
133133
arr = string_to_array(s, ",");
134-
success = string_parse_enum_list(&mouse_action_enum_data,
135-
arr, ret);
134+
success = string_parse_enum_list(&mouse_action_enum_data, arr, ret);
136135
break;
137136
case OFFSET_LIST:
138137
arr = string_to_array(s, "x");
139138
int len = string_array_length(arr);
140139
if (len != 2) {
141140
success = false;
142-
LOG_W("Offset has two values, separated by an 'x'");
143141
break;
144142
}
145143
int *int_arr = NULL;
@@ -301,72 +299,46 @@ int get_setting_id(const char *key, const char *section) {
301299
return -1;
302300
}
303301

304-
// TODO simplify this function
302+
// NOTE: We do minimal checks in this function so the values should be sanitized somewhere else
305303
int string_parse_length(void *ret_in, const char *s) {
306304
struct length *ret = (struct length*) ret_in;
307-
int val = 0;
308305
char *s_stripped = string_strip_brackets(s);
306+
307+
// single int without brackets
309308
if (!s_stripped) {
310-
// single int without brackets
309+
int val = 0;
311310
bool success = safe_string_to_int(&val, s);
312-
if (success && val > 0) {
313-
// single int
314-
ret->min = val;
315-
ret->max = val;
316-
return true;
317-
}
318-
if (val <= 0) {
319-
LOG_W("A length should be a positive value");
311+
if (!success) {
312+
LOG_W("Specify either a single value or two comma-separated values between parentheses");
313+
return false;
320314
}
321-
return false;
322-
}
323315

316+
ret->min = val;
317+
ret->max = val;
318+
return true;
319+
}
324320

325321
char **s_arr = string_to_array(s_stripped, ",");
326-
int len = string_array_length(s_arr);
322+
g_free(s_stripped);
327323

328-
if (len <= 1) {
329-
LOG_W("Please specify a minimum and maximum value or a single value without brackets");
330-
g_strfreev(s_arr);
331-
g_free(s_stripped);
332-
return false;
333-
}
334-
if (len > 2) {
324+
int len = string_array_length(s_arr);
325+
if (len != 2) {
335326
g_strfreev(s_arr);
336-
g_free(s_stripped);
337-
LOG_W("Too many values in array. A length should be only one or two values");
327+
LOG_W("Specify either a single value or two comma-separated values between parentheses");
338328
return false;
339329
}
340330

341331
int *int_arr = NULL;
342332
bool success = string_parse_int_list(s_arr, &int_arr, true);
343-
if (!success) {
344-
g_strfreev(s_arr);
345-
g_free(s_stripped);
346-
return false;
347-
}
333+
g_strfreev(s_arr);
348334

349-
if (int_arr[0] == -1)
350-
int_arr[0] = 0;
335+
if (!success)
336+
return false;
351337

352-
if (int_arr[1] == -1)
353-
int_arr[1] = INT_MAX;
354-
355-
if (int_arr[0] < 0 || int_arr[1] < 0) {
356-
LOG_W("A lengths should be positive");
357-
success = false;
358-
} else if (int_arr[0] > int_arr[1]) {
359-
LOG_W("The minimum value should be less than the maximum value. (%i > %i)",
360-
int_arr[0], int_arr[1]);
361-
success = false;
362-
} else {
363-
ret->min = int_arr[0];
364-
ret->max = int_arr[1];
365-
}
338+
ret->min = int_arr[0] == -1 ? INT_MIN : int_arr[0];
339+
ret->max = int_arr[1] == -1 ? INT_MAX : int_arr[1];
366340

367341
g_free(int_arr);
368-
g_strfreev(s_arr);
369-
g_free(s_stripped);
370342
return success;
371343
}
372344

@@ -428,6 +400,11 @@ bool set_from_string(void *target, struct setting setting, const char *value) {
428400
LOG_D("list type %i", GPOINTER_TO_INT(setting.parser_data));
429401
return string_parse_list(setting.parser_data, value, target);
430402
case TYPE_LENGTH:
403+
// Keep compatibility with old offset syntax
404+
if (STR_EQ(setting.name, "offset") && string_parse_list(GINT_TO_POINTER(OFFSET_LIST), value, target)) {
405+
LOG_I("Using legacy offset syntax NxN, you should switch to the new syntax (N, N)");
406+
return true;
407+
}
431408
return string_parse_length(target, value);
432409
case TYPE_COLOR:
433410
return string_parse_color(value, target);

src/settings.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,16 +202,38 @@ void check_and_correct_settings(struct settings *s) {
202202
DIE("setting progress_bar_max_width is smaller than progress_bar_min_width");
203203
}
204204
if (s->progress_bar_min_width > s->width.max) {
205-
LOG_W("Progress bar min width is greater than the max width of the notification.");
205+
LOG_W("Progress bar min width is greater than the max width of the notification");
206206
}
207207
int progress_bar_max_corner_radius = (s->progress_bar_height / 2);
208208
if (s->progress_bar_corner_radius > progress_bar_max_corner_radius) {
209209
settings.progress_bar_corner_radius = progress_bar_max_corner_radius;
210-
LOG_W("Progress bar corner radius clamped to half of progress bar height (%i).",
210+
LOG_W("Progress bar corner radius clamped to half of progress bar height (%i)",
211211
progress_bar_max_corner_radius);
212212
}
213213
}
214214

215+
// check lengths
216+
if (s->width.min == INT_MIN) {
217+
s->width.min = 0;
218+
}
219+
if (s->width.min < 0 || s->width.max < 0) {
220+
DIE("setting width does not support negative values");
221+
}
222+
if (s->width.min > s->width.max) {
223+
DIE("setting width min (%i) is always greather than max (%i)", s->width.min, s->width.max);
224+
}
225+
226+
if (s->height.min < 0 || s->height.max < 0) {
227+
DIE("setting height does not support negative values");
228+
}
229+
if (s->height.min != s->height.max) {
230+
LOG_W("Dynamic height is not yet supported");
231+
}
232+
233+
if (s->offset.x == INT_MIN || s->offset.y == INT_MAX) {
234+
DIE("setting offset needs both horizontal and vertical values");
235+
}
236+
215237
// TODO Implement this with icon sizes as rules
216238

217239
// restrict the icon size to a reasonable limit if we have a fixed width.

src/settings.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,8 @@ struct settings {
173173
enum zwlr_layer_shell_v1_layer layer;
174174
enum origin_values origin;
175175
struct length width;
176-
int height;
177-
struct position offset;
176+
struct length height;
177+
struct position offset; // NOTE: we rely on the fact that lenght and position are similar
178178
int notification_limit;
179179
int gap_size;
180180
};

src/settings_data.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1529,7 +1529,7 @@ static const struct setting allowed_settings[] = {
15291529
.name = "height",
15301530
.section = "global",
15311531
.description = "The maximum height of a single notification, excluding the frame.",
1532-
.type = TYPE_INT,
1532+
.type = TYPE_LENGTH,
15331533
.default_value = "300",
15341534
.value = &settings.height,
15351535
.parser = NULL,
@@ -1539,11 +1539,11 @@ static const struct setting allowed_settings[] = {
15391539
.name = "offset",
15401540
.section = "global",
15411541
.description = "The offset of the notification from the origin.",
1542-
.type = TYPE_LIST,
1543-
.default_value = "10x50",
1542+
.type = TYPE_LENGTH,
1543+
.default_value = "(10, 50)",
15441544
.value = &settings.offset,
15451545
.parser = NULL,
1546-
.parser_data = GINT_TO_POINTER(OFFSET_LIST),
1546+
.parser_data = NULL,
15471547
},
15481548
{
15491549
.name = "notification_limit",

test/draw.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,23 +70,23 @@ GSList *get_dummy_layouts(GSList *notifications)
7070
return layouts;
7171
}
7272

73-
int get_small_max_height(void)
73+
struct length get_small_max_height(void)
7474
{
7575
// to keep test calculations simpler, set max height small to
7676
// only test cases where height is not dynamically determined
7777
// by notification content
7878
// future tests targeting dynamic sizing logic could be added
7979
// to address this limitation
80-
int small_max_height = 10;
81-
return small_max_height;
80+
struct length height = { 0, 10 };
81+
return height;
8282
}
8383

8484
int get_expected_dimension_height(int layout_count)
8585
{
8686
// assumes settings.height == notification height, see get_small_max_height
8787
int separator_height = (layout_count - 1) * settings.separator_height;
8888
int total_gap_size = (layout_count - 1) * settings.gap_size;
89-
int height = settings.height * layout_count;
89+
int height = settings.height.max * layout_count;
9090
int frame_width_total_height;
9191
int expected_height;
9292
if(settings.gap_size) {
@@ -102,7 +102,7 @@ int get_expected_dimension_height(int layout_count)
102102
int get_expected_dimension_y_offset(int layout_count)
103103
{
104104
// assumes settings.height == notification height, see get_small_max_height
105-
int expected_y = layout_count * settings.height;
105+
int expected_y = layout_count * settings.height.max;
106106
if(settings.gap_size) {
107107
expected_y += (layout_count * (2 * settings.frame_width));
108108
expected_y += (layout_count * settings.gap_size);
@@ -155,7 +155,7 @@ TEST test_layout_from_notification_no_icon(void)
155155

156156
TEST test_calculate_dimensions_height_no_gaps(void)
157157
{
158-
int original_height = settings.height;
158+
struct length original_height = settings.height;
159159
bool orginal_gap_size = settings.gap_size;
160160
settings.height = get_small_max_height();
161161
settings.gap_size = 10;
@@ -201,7 +201,7 @@ TEST test_calculate_dimensions_height_no_gaps(void)
201201

202202
TEST test_calculate_dimensions_height_gaps(void)
203203
{
204-
int original_height = settings.height;
204+
struct length original_height = settings.height;
205205
bool orginal_gap_size = settings.gap_size;
206206
settings.height = get_small_max_height();
207207
settings.gap_size = 10;
@@ -247,7 +247,7 @@ TEST test_calculate_dimensions_height_gaps(void)
247247

248248
TEST test_layout_render_no_gaps(void)
249249
{
250-
int original_height = settings.height;
250+
struct length original_height = settings.height;
251251
bool orginal_gap_size = settings.gap_size;
252252
settings.height = get_small_max_height();
253253
settings.gap_size = 0;
@@ -291,7 +291,7 @@ TEST test_layout_render_no_gaps(void)
291291

292292
TEST test_layout_render_gaps(void)
293293
{
294-
int original_height = settings.height;
294+
struct length original_height = settings.height;
295295
bool orginal_gap_size = settings.gap_size;
296296
settings.height = get_small_max_height();
297297
settings.gap_size = 10;

0 commit comments

Comments
 (0)