Skip to content

Commit

Permalink
Merge pull request #1330 from bynect/change-lengths
Browse files Browse the repository at this point in the history
Refactor length parsing and make offset use the (N,N) syntax
  • Loading branch information
bynect authored Apr 20, 2024
2 parents b354f47 + 9de5769 commit a6e1d4e
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 90 deletions.
4 changes: 3 additions & 1 deletion docs/dunst.5.pod
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ notification being off screen.

Examples:
origin = top-right
offset = 10x300 # a margin of 10 pixels from the right and 300 pixels from the top
offset = (10, 300) # a margin of 10 pixels from the right and 300 pixels from the top

For backwards compatibility the syntax NxN is also accepted.

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

Expand Down
2 changes: 1 addition & 1 deletion dunstrc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
origin = top-right

# Offset from the origin
offset = 10x50
offset = (10, 50)

# Scale factor. It is auto-detected if value is 0.
scale = 0
Expand Down
14 changes: 7 additions & 7 deletions src/draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ static void layout_setup(struct colored_layout *cl, int width, int height, doubl
int icon_width = cl->icon ? get_icon_width(cl->icon, scale) + horizontal_padding : 0;
int text_width = width - 2 * settings.h_padding - (cl->n->icon_position == ICON_TOP ? 0 : icon_width);
int progress_bar_height = have_progress_bar(cl) ? settings.progress_bar_height + settings.padding : 0;
int max_text_height = MAX(0, settings.height - progress_bar_height - 2 * settings.padding);
int max_text_height = MAX(0, settings.height.max - progress_bar_height - 2 * settings.padding);
layout_setup_pango(cl->l, text_width, max_text_height, cl->n->word_wrap, cl->n->ellipsize, cl->n->alignment);
}

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

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

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

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

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

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

if ((2 * settings.padding + cl_h) < settings.height)
if ((2 * settings.padding + cl_h) < settings.height.max)
dim.y += cl_h + 2 * settings.padding;
else
dim.y += settings.height;
dim.y += settings.height.max;

if (settings.gap_size)
dim.y += settings.gap_size;
Expand Down
75 changes: 26 additions & 49 deletions src/option_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,13 @@ int string_parse_list(const void *data, const char *s, void *ret) {
switch (type) {
case MOUSE_LIST:
arr = string_to_array(s, ",");
success = string_parse_enum_list(&mouse_action_enum_data,
arr, ret);
success = string_parse_enum_list(&mouse_action_enum_data, arr, ret);
break;
case OFFSET_LIST:
arr = string_to_array(s, "x");
int len = string_array_length(arr);
if (len != 2) {
success = false;
LOG_W("Offset has two values, separated by an 'x'");
break;
}
int *int_arr = NULL;
Expand Down Expand Up @@ -301,72 +299,46 @@ int get_setting_id(const char *key, const char *section) {
return -1;
}

// TODO simplify this function
// NOTE: We do minimal checks in this function so the values should be sanitized somewhere else
int string_parse_length(void *ret_in, const char *s) {
struct length *ret = (struct length*) ret_in;
int val = 0;
char *s_stripped = string_strip_brackets(s);

// single int without brackets
if (!s_stripped) {
// single int without brackets
int val = 0;
bool success = safe_string_to_int(&val, s);
if (success && val > 0) {
// single int
ret->min = val;
ret->max = val;
return true;
}
if (val <= 0) {
LOG_W("A length should be a positive value");
if (!success) {
LOG_W("Specify either a single value or two comma-separated values between parentheses");
return false;
}
return false;
}

ret->min = val;
ret->max = val;
return true;
}

char **s_arr = string_to_array(s_stripped, ",");
int len = string_array_length(s_arr);
g_free(s_stripped);

if (len <= 1) {
LOG_W("Please specify a minimum and maximum value or a single value without brackets");
g_strfreev(s_arr);
g_free(s_stripped);
return false;
}
if (len > 2) {
int len = string_array_length(s_arr);
if (len != 2) {
g_strfreev(s_arr);
g_free(s_stripped);
LOG_W("Too many values in array. A length should be only one or two values");
LOG_W("Specify either a single value or two comma-separated values between parentheses");
return false;
}

int *int_arr = NULL;
bool success = string_parse_int_list(s_arr, &int_arr, true);
if (!success) {
g_strfreev(s_arr);
g_free(s_stripped);
return false;
}
g_strfreev(s_arr);

if (int_arr[0] == -1)
int_arr[0] = 0;
if (!success)
return false;

if (int_arr[1] == -1)
int_arr[1] = INT_MAX;

if (int_arr[0] < 0 || int_arr[1] < 0) {
LOG_W("A lengths should be positive");
success = false;
} else if (int_arr[0] > int_arr[1]) {
LOG_W("The minimum value should be less than the maximum value. (%i > %i)",
int_arr[0], int_arr[1]);
success = false;
} else {
ret->min = int_arr[0];
ret->max = int_arr[1];
}
ret->min = int_arr[0] == -1 ? INT_MIN : int_arr[0];
ret->max = int_arr[1] == -1 ? INT_MAX : int_arr[1];

g_free(int_arr);
g_strfreev(s_arr);
g_free(s_stripped);
return success;
}

Expand Down Expand Up @@ -428,6 +400,11 @@ bool set_from_string(void *target, struct setting setting, const char *value) {
LOG_D("list type %i", GPOINTER_TO_INT(setting.parser_data));
return string_parse_list(setting.parser_data, value, target);
case TYPE_LENGTH:
// Keep compatibility with old offset syntax
if (STR_EQ(setting.name, "offset") && string_parse_list(GINT_TO_POINTER(OFFSET_LIST), value, target)) {
LOG_I("Using legacy offset syntax NxN, you should switch to the new syntax (N, N)");
return true;
}
return string_parse_length(target, value);
case TYPE_COLOR:
return string_parse_color(value, target);
Expand Down
26 changes: 24 additions & 2 deletions src/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,16 +202,38 @@ void check_and_correct_settings(struct settings *s) {
DIE("setting progress_bar_max_width is smaller than progress_bar_min_width");
}
if (s->progress_bar_min_width > s->width.max) {
LOG_W("Progress bar min width is greater than the max width of the notification.");
LOG_W("Progress bar min width is greater than the max width of the notification");
}
int progress_bar_max_corner_radius = (s->progress_bar_height / 2);
if (s->progress_bar_corner_radius > progress_bar_max_corner_radius) {
settings.progress_bar_corner_radius = progress_bar_max_corner_radius;
LOG_W("Progress bar corner radius clamped to half of progress bar height (%i).",
LOG_W("Progress bar corner radius clamped to half of progress bar height (%i)",
progress_bar_max_corner_radius);
}
}

// check lengths
if (s->width.min == INT_MIN) {
s->width.min = 0;
}
if (s->width.min < 0 || s->width.max < 0) {
DIE("setting width does not support negative values");
}
if (s->width.min > s->width.max) {
DIE("setting width min (%i) is always greather than max (%i)", s->width.min, s->width.max);
}

if (s->height.min < 0 || s->height.max < 0) {
DIE("setting height does not support negative values");
}
if (s->height.min != s->height.max) {
LOG_W("Dynamic height is not yet supported");
}

if (s->offset.x == INT_MIN || s->offset.y == INT_MAX) {
DIE("setting offset needs both horizontal and vertical values");
}

// TODO Implement this with icon sizes as rules

// restrict the icon size to a reasonable limit if we have a fixed width.
Expand Down
4 changes: 2 additions & 2 deletions src/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,8 @@ struct settings {
enum zwlr_layer_shell_v1_layer layer;
enum origin_values origin;
struct length width;
int height;
struct position offset;
struct length height;
struct position offset; // NOTE: we rely on the fact that lenght and position are similar
int notification_limit;
int gap_size;
};
Expand Down
8 changes: 4 additions & 4 deletions src/settings_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -1529,7 +1529,7 @@ static const struct setting allowed_settings[] = {
.name = "height",
.section = "global",
.description = "The maximum height of a single notification, excluding the frame.",
.type = TYPE_INT,
.type = TYPE_LENGTH,
.default_value = "300",
.value = &settings.height,
.parser = NULL,
Expand All @@ -1539,11 +1539,11 @@ static const struct setting allowed_settings[] = {
.name = "offset",
.section = "global",
.description = "The offset of the notification from the origin.",
.type = TYPE_LIST,
.default_value = "10x50",
.type = TYPE_LENGTH,
.default_value = "(10, 50)",
.value = &settings.offset,
.parser = NULL,
.parser_data = GINT_TO_POINTER(OFFSET_LIST),
.parser_data = NULL,
},
{
.name = "notification_limit",
Expand Down
18 changes: 9 additions & 9 deletions test/draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,23 +70,23 @@ GSList *get_dummy_layouts(GSList *notifications)
return layouts;
}

int get_small_max_height(void)
struct length get_small_max_height(void)
{
// to keep test calculations simpler, set max height small to
// only test cases where height is not dynamically determined
// by notification content
// future tests targeting dynamic sizing logic could be added
// to address this limitation
int small_max_height = 10;
return small_max_height;
struct length height = { 0, 10 };
return height;
}

int get_expected_dimension_height(int layout_count)
{
// assumes settings.height == notification height, see get_small_max_height
int separator_height = (layout_count - 1) * settings.separator_height;
int total_gap_size = (layout_count - 1) * settings.gap_size;
int height = settings.height * layout_count;
int height = settings.height.max * layout_count;
int frame_width_total_height;
int expected_height;
if(settings.gap_size) {
Expand All @@ -102,7 +102,7 @@ int get_expected_dimension_height(int layout_count)
int get_expected_dimension_y_offset(int layout_count)
{
// assumes settings.height == notification height, see get_small_max_height
int expected_y = layout_count * settings.height;
int expected_y = layout_count * settings.height.max;
if(settings.gap_size) {
expected_y += (layout_count * (2 * settings.frame_width));
expected_y += (layout_count * settings.gap_size);
Expand Down Expand Up @@ -155,7 +155,7 @@ TEST test_layout_from_notification_no_icon(void)

TEST test_calculate_dimensions_height_no_gaps(void)
{
int original_height = settings.height;
struct length original_height = settings.height;
bool orginal_gap_size = settings.gap_size;
settings.height = get_small_max_height();
settings.gap_size = 10;
Expand Down Expand Up @@ -201,7 +201,7 @@ TEST test_calculate_dimensions_height_no_gaps(void)

TEST test_calculate_dimensions_height_gaps(void)
{
int original_height = settings.height;
struct length original_height = settings.height;
bool orginal_gap_size = settings.gap_size;
settings.height = get_small_max_height();
settings.gap_size = 10;
Expand Down Expand Up @@ -247,7 +247,7 @@ TEST test_calculate_dimensions_height_gaps(void)

TEST test_layout_render_no_gaps(void)
{
int original_height = settings.height;
struct length original_height = settings.height;
bool orginal_gap_size = settings.gap_size;
settings.height = get_small_max_height();
settings.gap_size = 0;
Expand Down Expand Up @@ -291,7 +291,7 @@ TEST test_layout_render_no_gaps(void)

TEST test_layout_render_gaps(void)
{
int original_height = settings.height;
struct length original_height = settings.height;
bool orginal_gap_size = settings.gap_size;
settings.height = get_small_max_height();
settings.gap_size = 10;
Expand Down
Loading

0 comments on commit a6e1d4e

Please sign in to comment.