diff --git a/src/draw.c b/src/draw.c index 3ee0668..f3e3a6a 100644 --- a/src/draw.c +++ b/src/draw.c @@ -141,10 +141,11 @@ static struct color layout_get_sepcolor(struct colored_layout *cl, static void layout_setup_pango(PangoLayout *layout, int width) { + int scale = output->get_scale(); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); - pango_layout_set_width(layout, width * PANGO_SCALE); + pango_layout_set_width(layout, width * scale * PANGO_SCALE); pango_layout_set_font_description(layout, pango_fdesc); - pango_layout_set_spacing(layout, settings.line_height * PANGO_SCALE); + pango_layout_set_spacing(layout, settings.line_height * scale * PANGO_SCALE); PangoAlignment align; switch (settings.align) { @@ -192,9 +193,20 @@ static bool have_progress_bar(const struct notification *n) return (n->progress >= 0 && settings.progress_bar == true); } +static void get_text_size(PangoLayout *l, int *w, int *h, int scale) { + pango_layout_get_pixel_size(l, w, h); + // scale the size down, because it may be rendered at higher DPI + + if (w) + *w /= scale; + if (h) + *h /= scale; +} + static struct dimensions calculate_dimensions(GSList *layouts) { struct dimensions dim = { 0 }; + int scale = output->get_scale(); const struct screen_info *scr = output->get_active_screen(); if (have_dynamic_width()) { @@ -221,10 +233,10 @@ static struct dimensions calculate_dimensions(GSList *layouts) for (GSList *iter = layouts; iter; iter = iter->next) { struct colored_layout *cl = iter->data; int w=0,h=0; - pango_layout_get_pixel_size(cl->l, &w, &h); + get_text_size(cl->l, &w, &h, scale); if (cl->icon) { - h = MAX(cairo_image_surface_get_height(cl->icon), h); - w += cairo_image_surface_get_width(cl->icon) + settings.h_padding; + h = MAX(get_icon_height(cl->icon, scale), h); + w += get_icon_width(cl->icon, scale) + settings.h_padding; } h = MAX(settings.notification_height, h + settings.padding * 2); dim.h += h; @@ -250,15 +262,15 @@ static struct dimensions calculate_dimensions(GSList *layouts) w -= 2 * settings.h_padding; w -= 2 * settings.frame_width; if (cl->icon) { - w -= cairo_image_surface_get_width(cl->icon) + get_text_icon_padding(); + w -= get_icon_width(cl->icon, scale) + get_text_icon_padding(); } layout_setup_pango(cl->l, w); /* re-read information */ - pango_layout_get_pixel_size(cl->l, &w, &h); + get_text_size(cl->l, &w, &h, scale); if (cl->icon) { - h = MAX(cairo_image_surface_get_height(cl->icon), h); - w += cairo_image_surface_get_width(cl->icon) + settings.h_padding; + h = MAX(get_icon_height(cl->icon, scale), h); + w += get_icon_width(cl->icon, scale) + settings.h_padding; } h = MAX(settings.notification_height, h + settings.padding * 2); dim.h += h; @@ -299,6 +311,7 @@ static struct colored_layout *layout_init_shared(cairo_t *c, const struct notifi { struct colored_layout *cl = g_malloc(sizeof(struct colored_layout)); cl->l = layout_create(c); + int scale = output->get_scale(); if (!settings.word_wrap) { PangoEllipsizeMode ellipsize; @@ -346,7 +359,7 @@ static struct colored_layout *layout_init_shared(cairo_t *c, const struct notifi width -= 2 * settings.h_padding; width -= 2 * settings.frame_width; if (cl->icon) { - width -= cairo_image_surface_get_width(cl->icon) + get_text_icon_padding(); + width -= get_icon_width(cl->icon, scale) + get_text_icon_padding(); } layout_setup_pango(cl->l, width); } @@ -367,6 +380,7 @@ static struct colored_layout *layout_from_notification(cairo_t *c, struct notifi { struct colored_layout *cl = layout_init_shared(c, n); + int scale = output->get_scale(); /* markup */ GError *err = NULL; @@ -388,8 +402,8 @@ static struct colored_layout *layout_from_notification(cairo_t *c, struct notifi } - 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); + get_text_size(cl->l, NULL, &(n->displayed_height), scale); + if (cl->icon) n->displayed_height = MAX(get_icon_height(cl->icon, scale), n->displayed_height); n->displayed_height = n->displayed_height + settings.padding * 2; @@ -435,14 +449,14 @@ static GSList *create_layouts(cairo_t *c) } -static int layout_get_height(struct colored_layout *cl) +static int layout_get_height(struct colored_layout *cl, int scale) { int h; int h_icon = 0; int h_progress_bar = 0; - pango_layout_get_pixel_size(cl->l, NULL, &h); + get_text_size(cl->l, NULL, &h, scale); if (cl->icon) - h_icon = cairo_image_surface_get_height(cl->icon); + h_icon = get_icon_height(cl->icon, scale); if (have_progress_bar(cl->n)){ h_progress_bar = settings.progress_bar_height + settings.padding; } @@ -482,8 +496,14 @@ static int frame_internal_radius (int r, int w, int h) * The top corners will get rounded by `corner_radius`, if `first` is set. * Respectably the same for `last` with the bottom corners. */ -void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, bool first, bool last) +void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, int scale, bool first, bool last) { + width *= scale; + height *= scale; + x *= scale; + y *= scale; + corner_radius *= scale; + const float degrees = M_PI / 180.0; cairo_new_sub_path(c); @@ -531,6 +551,13 @@ void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corn cairo_close_path(c); } +/** + * A small wrapper around cairo_rectange for drawing a scaled rectangle. + */ +void draw_rect(cairo_t *c, int x, int y, int width, int height, int scale) { + cairo_rectangle(c, x * scale, y * scale, width * scale, height * scale); +} + static cairo_surface_t *render_background(cairo_surface_t *srf, struct colored_layout *cl, struct colored_layout *cl_next, @@ -540,7 +567,8 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, int corner_radius, bool first, bool last, - int *ret_width) + int *ret_width, + int scale) { int x = 0; int radius_int = corner_radius; @@ -560,7 +588,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, else height += settings.separator_height; - draw_rounded_rect(c, x, y, width, height, corner_radius, first, last); + draw_rounded_rect(c, x, y, width, height, corner_radius, scale, first, last); /* adding frame */ x += settings.frame_width; @@ -578,11 +606,11 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, radius_int = frame_internal_radius(corner_radius, settings.frame_width, height); - draw_rounded_rect(c, x, y, width, height, radius_int, first, last); + draw_rounded_rect(c, x, y, width, height, radius_int, scale, first, last); cairo_set_source_rgba(c, cl->frame.r, cl->frame.g, cl->frame.b, cl->frame.a); cairo_fill(c); - draw_rounded_rect(c, x, y, width, height, radius_int, first, last); + draw_rounded_rect(c, x, y, width, height, radius_int, scale, first, last); cairo_set_source_rgba(c, cl->bg.r, cl->bg.g, cl->bg.b, cl->bg.a); cairo_fill(c); @@ -594,7 +622,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, struct color sep_color = layout_get_sepcolor(cl, cl_next); cairo_set_source_rgba(c, sep_color.r, sep_color.g, sep_color.b, sep_color.a); - cairo_rectangle(c, settings.frame_width, y + height, width, settings.separator_height); + draw_rect(c, settings.frame_width, y + height, width, settings.separator_height, scale); cairo_fill(c); } @@ -604,18 +632,18 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, if (ret_width) *ret_width = width; - return cairo_surface_create_for_rectangle(srf, x, y, width, height); + return cairo_surface_create_for_rectangle(srf, x * scale, y * scale, width * scale, height * scale); } -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, int scale) { - const int h = layout_get_height(cl); + const int h = layout_get_height(cl, scale); 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; - pango_layout_get_pixel_size(cl->l, NULL, &h_text); + get_text_size(cl->l, NULL, &h_text, scale); int text_x = settings.h_padding, text_y = settings.padding + h_without_progress_bar / 2 - h_text / 2; @@ -633,10 +661,10 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) // icon position if (settings.icon_position == ICON_LEFT) { - text_x = cairo_image_surface_get_width(cl->icon) + settings.h_padding + get_text_icon_padding(); + text_x = get_icon_width(cl->icon, scale) + settings.h_padding + get_text_icon_padding(); } // else ICON_RIGHT } - cairo_move_to(c, text_x, text_y); + cairo_move_to(c, text_x * scale, text_y * scale); cairo_set_source_rgba(c, cl->fg.r, cl->fg.g, cl->fg.b, cl->fg.a); pango_cairo_update_layout(c, cl->l); @@ -645,8 +673,8 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) // icon positioning if (cl->icon) { - unsigned int image_width = cairo_image_surface_get_width(cl->icon), - image_height = cairo_image_surface_get_height(cl->icon), + unsigned int image_width = get_icon_width(cl->icon, scale), + image_height = get_icon_height(cl->icon, scale), image_x = width - settings.h_padding - image_width, image_y = settings.padding + h_without_progress_bar/2 - image_height/2; @@ -664,8 +692,8 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) image_x = settings.h_padding; } // else ICON_RIGHT - cairo_set_source_surface(c, cl->icon, image_x, image_y); - cairo_rectangle(c, image_x, image_y, image_width, image_height); + cairo_set_source_surface(c, cl->icon, image_x * scale, image_y * scale); + draw_rect(c, image_x, image_y, image_width, image_height, scale); cairo_fill(c); } @@ -689,16 +717,17 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width) // 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); + draw_rect(c, x_bar_1, frame_y, progress_width_1, progress_height, scale); 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); + draw_rect(c, x_bar_2, frame_y, progress_width_2, progress_height, scale); 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); + // TODO draw_rect instead of cairo_rectangle resulted in blurry lines. Why? + cairo_rectangle(c, (frame_x + half_frame_width) * scale, (frame_y + half_frame_width) * scale, (progress_width - frame_width) * scale, progress_height * scale); + cairo_set_line_width(c, frame_width * scale); cairo_stroke(c); } } @@ -710,18 +739,19 @@ static struct dimensions layout_render(cairo_surface_t *srf, bool first, bool last) { - const int cl_h = layout_get_height(cl); + int scale = output->get_scale(); + const int cl_h = layout_get_height(cl, scale); int h_text = 0; - pango_layout_get_pixel_size(cl->l, NULL, &h_text); + get_text_size(cl->l, NULL, &h_text, scale); int bg_width = 0; int bg_height = MAX(settings.notification_height, (2 * settings.padding) + cl_h); - cairo_surface_t *content = render_background(srf, cl, cl_next, dim.y, dim.w, bg_height, dim.corner_radius, first, last, &bg_width); + cairo_surface_t *content = render_background(srf, cl, cl_next, dim.y, dim.w, bg_height, dim.corner_radius, first, last, &bg_width, scale); cairo_t *c = cairo_create(content); - render_content(c, cl, bg_width); + render_content(c, cl, bg_width, scale); /* adding frame */ if (first) @@ -773,8 +803,9 @@ void draw(void) GSList *layouts = create_layouts(output->win_get_context(win)); struct dimensions dim = calculate_dimensions(layouts); + int scale = output->get_scale(); - cairo_surface_t *image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dim.w, dim.h); + cairo_surface_t *image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dim.w * scale, dim.h * scale); bool first = true; for (GSList *iter = layouts; iter; iter = iter->next) { @@ -799,4 +830,14 @@ void draw_deinit(void) output->win_destroy(win); output->deinit(); } + +int draw_get_scale(void) +{ + if (output) { + return output->get_scale(); + } else { + LOG_W("Called draw_get_scale before output init"); + return 1; + } +} /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/draw.h b/src/draw.h index 43303a4..e968012 100644 --- a/src/draw.h +++ b/src/draw.h @@ -12,9 +12,13 @@ void draw_setup(void); void draw(void); -void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, bool first, bool last); +void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, int scale, bool first, bool last); + +// TODO get rid of this function by passing scale to everything that needs it. +int draw_get_scale(void); void draw_deinit(void); + #endif /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/dunst.c b/src/dunst.c index dad4c7c..d201fad 100644 --- a/src/dunst.c +++ b/src/dunst.c @@ -24,6 +24,7 @@ GMainLoop *mainloop = NULL; static struct dunst_status status; +static bool setup_done = false; /* see dunst.h */ void dunst_status(const enum dunst_status_field field, @@ -56,6 +57,14 @@ static gboolean run(void *data); void wake_up(void) { + // If wake_up is being called before the output has been setup we should + // return. + if (!setup_done) + { + LOG_D("Ignoring wake up"); + return; + } + LOG_D("Waking up"); run(NULL); } @@ -197,6 +206,7 @@ int dunst_main(int argc, char *argv[]) // we do not call wakeup now, wake_up does not work here yet } + setup_done = true; run(NULL); g_main_loop_run(mainloop); g_clear_pointer(&mainloop, g_main_loop_unref); diff --git a/src/icon.c b/src/icon.c index fdca559..2437550 100644 --- a/src/icon.c +++ b/src/icon.c @@ -86,6 +86,14 @@ static void pixbuf_data_to_cairo_data( } } +int get_icon_width(cairo_surface_t *icon, int scale) { + return cairo_image_surface_get_width(icon) / scale; +} + +int get_icon_height(cairo_surface_t *icon, int scale) { + return cairo_image_surface_get_height(icon) / scale; +} + cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf) { assert(pixbuf); @@ -144,22 +152,26 @@ static bool icon_size_clamp(int *w, int *h) { * * @param pixbuf (nullable) The pixbuf, which may be too big. * Takes ownership of the reference. + * @param dpi_scale An integer for the dpi scaling. That doesn't mean the icon + * is always scaled by dpi_scale. * @return the scaled version of the pixbuf. If scaling wasn't * necessary, it returns the same pixbuf. Transfers full * ownership of the reference. */ -static GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf) +static GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf, int dpi_scale) { ASSERT_OR_RET(pixbuf, NULL); int w = gdk_pixbuf_get_width(pixbuf); int h = gdk_pixbuf_get_height(pixbuf); + + // TODO immediately rescale icon upon scale changes if (icon_size_clamp(&w, &h)) { GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, - w, - h, + w * dpi_scale, + h * dpi_scale, GDK_INTERP_BILINEAR); g_object_unref(pixbuf); pixbuf = scaled; @@ -168,7 +180,7 @@ static GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf) return pixbuf; } -GdkPixbuf *get_pixbuf_from_file(const char *filename) +GdkPixbuf *get_pixbuf_from_file(const char *filename, int scale) { char *path = string_to_path(g_strdup(filename)); GError *error = NULL; @@ -179,10 +191,11 @@ GdkPixbuf *get_pixbuf_from_file(const char *filename) g_free(path); return NULL; } + // TODO immediately rescale icon upon scale changes icon_size_clamp(&w, &h); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_scale(path, - w, - h, + w * scale, + h * scale, TRUE, &error); @@ -250,7 +263,7 @@ char *get_path_from_icon_name(const char *iconname) return new_name; } -GdkPixbuf *get_pixbuf_from_icon(const char *iconname) +GdkPixbuf *get_pixbuf_from_icon(const char *iconname, int scale) { char *path = get_path_from_icon_name(iconname); if (!path) { @@ -259,7 +272,7 @@ GdkPixbuf *get_pixbuf_from_icon(const char *iconname) GdkPixbuf *pixbuf = NULL; - pixbuf = get_pixbuf_from_file(path); + pixbuf = get_pixbuf_from_file(path, scale); g_free(path); if (!pixbuf) @@ -268,18 +281,18 @@ GdkPixbuf *get_pixbuf_from_icon(const char *iconname) return pixbuf; } -GdkPixbuf *icon_get_for_name(const char *name, char **id) +GdkPixbuf *icon_get_for_name(const char *name, char **id, int scale) { ASSERT_OR_RET(name, NULL); ASSERT_OR_RET(id, NULL); - GdkPixbuf *pb = get_pixbuf_from_icon(name); + GdkPixbuf *pb = get_pixbuf_from_icon(name, scale); if (pb) *id = g_strdup(name); return pb; } -GdkPixbuf *icon_get_for_data(GVariant *data, char **id) +GdkPixbuf *icon_get_for_data(GVariant *data, char **id, int dpi_scale) { ASSERT_OR_RET(data, NULL); ASSERT_OR_RET(id, NULL); @@ -383,7 +396,7 @@ GdkPixbuf *icon_get_for_data(GVariant *data, char **id) g_free(data_chk); g_variant_unref(data_variant); - pixbuf = icon_pixbuf_scale(pixbuf); + pixbuf = icon_pixbuf_scale(pixbuf, dpi_scale); return pixbuf; } diff --git a/src/icon.h b/src/icon.h index 242880b..ef781fb 100644 --- a/src/icon.h +++ b/src/icon.h @@ -11,11 +11,26 @@ cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf); /** Retrieve an icon by its full filepath, scaled according to settings. * * @param filename A string representing a readable file path + * @param scale An integer representing the output dpi scaling. * * @return an instance of `GdkPixbuf` * @retval NULL: file does not exist, not readable, etc.. */ -GdkPixbuf *get_pixbuf_from_file(const char *filename); +GdkPixbuf *get_pixbuf_from_file(const char *filename, int scale); + + +/** + * Get the unscaled icon width. + * + * If scale is 2 for example, the icon will render in twice the size, but + * get_icon_width still returns the same size as when scale is 1. + */ +int get_icon_width(cairo_surface_t *icon, int scale); + +/** + * Get the unscaled icon height, see get_icon_width. + */ +int get_icon_height(cairo_surface_t *icon, int scale); /** Retrieve a path from an icon name. * @@ -33,11 +48,12 @@ char *get_path_from_icon_name(const char *iconname); * @param iconname A string describing a `file://` URL, an arbitary filename * or an icon name, which then gets searched for in the * settings.icon_path + * @param scale An integer representing the output dpi scaling. * * @return an instance of `GdkPixbuf` * @retval NULL: file does not exist, not readable, etc.. */ -GdkPixbuf *get_pixbuf_from_icon(const char *iconname); +GdkPixbuf *get_pixbuf_from_icon(const char *iconname, int scale); /** Read an icon from disk and convert it to a GdkPixbuf, scaled according to settings * @@ -49,10 +65,11 @@ GdkPixbuf *get_pixbuf_from_icon(const char *iconname); * get searched in the folders of the icon_path setting. * @param id (necessary) A unique identifier of the returned pixbuf. Only filled, * if the return value is non-NULL. + * @param scale An integer representing the output dpi scaling. * @return an instance of `GdkPixbuf`, representing the name's image * @retval NULL: Invalid path given */ -GdkPixbuf *icon_get_for_name(const char *name, char **id); +GdkPixbuf *icon_get_for_name(const char *name, char **id, int dpi_scale); /** Convert a GVariant like described in GdkPixbuf, scaled according to settings * @@ -63,10 +80,11 @@ GdkPixbuf *icon_get_for_name(const char *name, char **id); * like described in the notification spec. * @param id (necessary) A unique identifier of the returned pixbuf. * Only filled, if the return value is non-NULL. + * @param scale An integer representing the output dpi scaling. * @return an instance of `GdkPixbuf` derived from the GVariant * @retval NULL: GVariant parameter nulled, invalid or in wrong format */ -GdkPixbuf *icon_get_for_data(GVariant *data, char **id); +GdkPixbuf *icon_get_for_data(GVariant *data, char **id, int scale); #endif /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/notification.c b/src/notification.c index b16d671..015e4b6 100644 --- a/src/notification.c +++ b/src/notification.c @@ -23,6 +23,7 @@ #include "rules.h" #include "settings.h" #include "utils.h" +#include "draw.h" static void notification_extract_urls(struct notification *n); static void notification_format_message(struct notification *n); @@ -314,7 +315,7 @@ void notification_icon_replace_path(struct notification *n, const char *new_icon g_clear_object(&n->icon); g_clear_pointer(&n->icon_id, g_free); - n->icon = icon_get_for_name(new_icon, &n->icon_id); + n->icon = icon_get_for_name(new_icon, &n->icon_id, draw_get_scale()); } void notification_icon_replace_data(struct notification *n, GVariant *new_icon) @@ -325,7 +326,7 @@ void notification_icon_replace_data(struct notification *n, GVariant *new_icon) g_clear_object(&n->icon); g_clear_pointer(&n->icon_id, g_free); - n->icon = icon_get_for_data(new_icon, &n->icon_id); + n->icon = icon_get_for_data(new_icon, &n->icon_id, draw_get_scale()); } /* see notification.h */ diff --git a/src/wayland/wl.c b/src/wayland/wl.c index 6b61c7b..a623cf1 100644 --- a/src/wayland/wl.c +++ b/src/wayland/wl.c @@ -116,6 +116,8 @@ static void output_handle_scale(void *data, struct wl_output *wl_output, int32_t factor) { struct dunst_output *output = data; output->scale = factor; + + wake_up(); } static const struct wl_output_listener output_listener = { @@ -622,7 +624,7 @@ static void schedule_frame_and_commit(); // Draw and commit a new frame. static void send_frame() { - int scale = 1; + int scale = wl_get_scale(); struct dunst_output *output = get_configured_output(); int height = ctx.cur_dim.h; @@ -689,8 +691,6 @@ static void send_frame() { if (ctx.height != height || ctx.width != width) { struct dimensions dim = ctx.cur_dim; // Set window size - LOG_D("Window dimensions %ix%i", dim.w, dim.h); - LOG_D("Window position %ix%i", dim.x, dim.y); zwlr_layer_surface_v1_set_size(ctx.layer_surface, dim.w, dim.h); @@ -815,12 +815,15 @@ void wl_win_hide(window win) { void wl_display_surface(cairo_surface_t *srf, window winptr, const struct dimensions* dim) { /* struct window_wl *win = (struct window_wl*)winptr; */ - ctx.current_buffer = get_next_buffer(ctx.shm, ctx.buffers, dim->w, dim->h); + int scale = wl_get_scale(); + LOG_D("Buffer size (scaled) %ix%i", dim->w * scale, dim->h * scale); + ctx.current_buffer = get_next_buffer(ctx.shm, ctx.buffers, + dim->w * scale, dim->h * scale); cairo_t *c = ctx.current_buffer->cairo; cairo_save(c); cairo_set_source_surface(c, srf, 0, 0); - cairo_rectangle(c, 0, 0, dim->w, dim->h); + cairo_rectangle(c, 0, 0, dim->w * scale, dim->h * scale); cairo_fill(c); cairo_restore(c); @@ -848,6 +851,7 @@ const struct screen_info* wl_get_active_screen(void) { .id = 0, .mmh = 500 }; + scr.dpi = wl_get_scale() * 96; return &scr; } diff --git a/src/wayland/wl.h b/src/wayland/wl.h index f4b3af9..5b5a914 100644 --- a/src/wayland/wl.h +++ b/src/wayland/wl.h @@ -24,6 +24,9 @@ const struct screen_info* wl_get_active_screen(void); bool wl_is_idle(void); bool wl_have_fullscreen_window(void); +// Return the dpi scaling of the current output. Everything that's rendered +// should be multiplied by this value, but don't use it to multiply other +// values. All sizes should be in unscaled units. int wl_get_scale(void); #endif /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/x11/x.c b/src/x11/x.c index 971b57b..ab18c91 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -113,7 +113,7 @@ static void x_win_corners_shape(struct window_x11 *win, const int rad) draw_rounded_rect(cr, 0, 0, width, height, - rad, + rad, 1, true, true); cairo_fill(cr); diff --git a/test/icon.c b/test/icon.c index b9ebc7b..1afe1e0 100644 --- a/test/icon.c +++ b/test/icon.c @@ -12,6 +12,8 @@ extern const char *base; +int scale = 1; + TEST test_get_path_from_icon_null(void){ char *result = get_path_from_icon_name(NULL); ASSERT_EQ(result, NULL); @@ -86,7 +88,7 @@ TEST test_get_pixbuf_from_file_tilde(void) gchar *path = g_build_filename(base, iconpath, "valid", "icon1.svg", NULL); path = string_replace_at(path, 0, strlen(home), "~"); - GdkPixbuf *pixbuf = get_pixbuf_from_file(path); + GdkPixbuf *pixbuf = get_pixbuf_from_file(path, scale); g_clear_pointer(&path, g_free); ASSERT(pixbuf); @@ -101,7 +103,7 @@ TEST test_get_pixbuf_from_file_absolute(void) gchar *path = g_build_filename(base, iconpath, "valid", "icon1.svg", NULL); - GdkPixbuf *pixbuf = get_pixbuf_from_file(path); + GdkPixbuf *pixbuf = get_pixbuf_from_file(path, scale); g_clear_pointer(&path, g_free); ASSERT(pixbuf); @@ -113,7 +115,7 @@ TEST test_get_pixbuf_from_file_absolute(void) TEST test_get_pixbuf_from_icon_invalid(void) { - GdkPixbuf *pixbuf = get_pixbuf_from_icon("invalid"); + GdkPixbuf *pixbuf = get_pixbuf_from_icon("invalid", scale); ASSERT(pixbuf == NULL); g_clear_pointer(&pixbuf, g_object_unref); @@ -122,7 +124,7 @@ TEST test_get_pixbuf_from_icon_invalid(void) TEST test_get_pixbuf_from_icon_both(void) { - GdkPixbuf *pixbuf = get_pixbuf_from_icon("icon1"); + GdkPixbuf *pixbuf = get_pixbuf_from_icon("icon1", scale); // the first icon found is invalid, so the pixbuf is empty ASSERT(!pixbuf); g_clear_pointer(&pixbuf, g_object_unref); @@ -132,7 +134,7 @@ TEST test_get_pixbuf_from_icon_both(void) TEST test_get_pixbuf_from_icon_onlysvg(void) { - GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlysvg"); + GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlysvg", scale); ASSERT(pixbuf); ASSERTm("SVG pixbuf isn't loaded", IS_ICON_SVG(pixbuf)); g_clear_pointer(&pixbuf, g_object_unref); @@ -142,7 +144,7 @@ TEST test_get_pixbuf_from_icon_onlysvg(void) TEST test_get_pixbuf_from_icon_onlypng(void) { - GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlypng"); + GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlypng", scale); ASSERT(pixbuf); ASSERTm("PNG pixbuf isn't loaded", IS_ICON_PNG(pixbuf)); g_clear_pointer(&pixbuf, g_object_unref); @@ -153,7 +155,7 @@ TEST test_get_pixbuf_from_icon_onlypng(void) TEST test_get_pixbuf_from_icon_filename(void) { char *icon = g_strconcat(base, "/data/icons/valid.png", NULL); - GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon); + GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon, scale); ASSERT(pixbuf); ASSERTm("PNG pixbuf isn't loaded", IS_ICON_PNG(pixbuf)); g_clear_pointer(&pixbuf, g_object_unref); @@ -165,7 +167,7 @@ TEST test_get_pixbuf_from_icon_filename(void) TEST test_get_pixbuf_from_icon_fileuri(void) { char *icon = g_strconcat("file://", base, "/data/icons/valid.svg", NULL); - GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon); + GdkPixbuf *pixbuf = get_pixbuf_from_icon(icon, scale); ASSERT(pixbuf); ASSERTm("SVG pixbuf isn't loaded", IS_ICON_SVG(pixbuf)); g_clear_pointer(&pixbuf, g_object_unref); @@ -220,7 +222,7 @@ TEST test_icon_size_clamp_too_small_then_too_big(void) TEST test_get_pixbuf_from_icon_both_is_scaled(void) { - GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlypng"); + GdkPixbuf *pixbuf = get_pixbuf_from_icon("onlypng", scale); ASSERT(pixbuf); ASSERT_EQ(gdk_pixbuf_get_width(pixbuf), 16); ASSERT_EQ(gdk_pixbuf_get_height(pixbuf), 16);