diff --git a/Makefile b/Makefile index 90d97fa5f..e92657eb5 100644 --- a/Makefile +++ b/Makefile @@ -89,6 +89,7 @@ test: test/test clean-coverage-run test-valgrind: test/test ${VALGRIND} \ --suppressions=.valgrind.suppressions \ + --track-origins=yes \ --leak-check=full \ --show-leak-kinds=definite \ --errors-for-leak-kinds=definite \ diff --git a/src/draw.c b/src/draw.c index 671d992bb..fc025c433 100644 --- a/src/draw.c +++ b/src/draw.c @@ -35,6 +35,7 @@ const struct output *output; window win; PangoFontDescription *pango_fdesc; +PangoContext *pango_ctx; // NOTE: Saves some characters #define COLOR(cl, field) (cl)->n->colors.field @@ -82,6 +83,8 @@ void draw_setup(void) pango_fdesc = pango_font_description_from_string(settings.font); LOG_D("Loaded closest matching font: '%s'", pango_font_description_get_family(pango_fdesc)); + pango_ctx = pango_cairo_create_context(out->win_get_context(win)); + if (settings.enable_recursive_icon_lookup) load_icon_themes(); } @@ -160,14 +163,8 @@ static bool have_progress_bar(const struct colored_layout *cl) !cl->is_xmore); } -static void get_text_size(PangoLayout *l, int *w, int *h, double scale) { +static void get_text_size(PangoLayout *l, int *w, int *h) { pango_layout_get_pixel_size(l, w, h); - // scale the size down, because it may be rendered at higher DPI - - if (w) - *w = ceil(*w / scale); - if (h) - *h = ceil(*h / scale); } // Set up pango for a given layout. @@ -177,29 +174,26 @@ static void layout_setup_pango(PangoLayout *layout, int width, int height, bool word_wrap, PangoEllipsizeMode ellipsize_mode, PangoAlignment alignment) { - double scale = output->get_scale(); pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); - pango_layout_set_width(layout, round(width * scale * PANGO_SCALE)); + pango_layout_set_width(layout, round(width * PANGO_SCALE)); // When no height is set, word wrap is turned off if (word_wrap) - pango_layout_set_height(layout, round(height * scale * PANGO_SCALE)); + pango_layout_set_height(layout, round(height * PANGO_SCALE)); pango_layout_set_font_description(layout, pango_fdesc); - pango_layout_set_spacing(layout, round(settings.line_height * scale * PANGO_SCALE)); - + pango_layout_set_spacing(layout, round(settings.line_height * PANGO_SCALE)); pango_layout_set_ellipsize(layout, ellipsize_mode); - pango_layout_set_alignment(layout, alignment); } // Set up the layout of a single notification // @param width Width of the layout // @param height Height of the layout -static void layout_setup(struct colored_layout *cl, int width, int height, double scale) +static void layout_setup(struct colored_layout *cl, int width, int height) { int horizontal_padding = get_horizontal_text_icon_padding(cl->n); - int icon_width = cl->icon ? get_icon_width(cl->icon, scale) + horizontal_padding : 0; + int icon_width = cl->icon ? get_icon_width(cl->icon) + 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); @@ -216,14 +210,14 @@ static void free_colored_layout(void *data) } // calculates the minimum dimensions of the notification excluding the frame -static struct dimensions calculate_notification_dimensions(struct colored_layout *cl, double scale) +static struct dimensions calculate_notification_dimensions(struct colored_layout *cl) { struct dimensions dim = { 0 }; - layout_setup(cl, settings.width.max, settings.height, scale); + layout_setup(cl, settings.width.max, settings.height); int horizontal_padding = get_horizontal_text_icon_padding(cl->n); - int icon_width = cl->icon? get_icon_width(cl->icon, scale) + horizontal_padding : 0; - int icon_height = cl->icon? get_icon_height(cl->icon, scale) : 0; + int icon_width = cl->icon? get_icon_width(cl->icon) + horizontal_padding : 0; + int icon_height = cl->icon? get_icon_height(cl->icon) : 0; int progress_bar_height = have_progress_bar(cl) ? settings.progress_bar_height + settings.padding : 0; int vertical_padding; @@ -232,7 +226,7 @@ static struct dimensions calculate_notification_dimensions(struct colored_layout dim.text_width = 0; dim.text_height = 0; } else { - get_text_size(cl->l, &dim.text_width, &dim.text_height, scale); + get_text_size(cl->l, &dim.text_width, &dim.text_height); vertical_padding = get_vertical_text_icon_padding(cl->n); } @@ -260,13 +254,12 @@ static struct dimensions calculate_dimensions(GSList *layouts) { int layout_count = g_slist_length(layouts); struct dimensions dim = { 0 }; - double scale = output->get_scale(); dim.corner_radius = settings.corner_radius; for (GSList *iter = layouts; iter; iter = iter->next) { struct colored_layout *cl = iter->data; - struct dimensions n_dim = calculate_notification_dimensions(cl, scale); + struct dimensions n_dim = calculate_notification_dimensions(cl); dim.h += n_dim.h; LOG_D("Notification dimensions %ix%i", n_dim.w, n_dim.h); dim.w = MAX(dim.w, n_dim.w + settings.frame_width); @@ -295,24 +288,10 @@ static struct dimensions calculate_dimensions(GSList *layouts) return dim; } -static PangoLayout *layout_create(cairo_t *c) -{ - const struct screen_info *screen = output->get_active_screen(); - - PangoContext *context = pango_cairo_create_context(c); - pango_cairo_context_set_resolution(context, screen->dpi); - - PangoLayout *layout = pango_layout_new(context); - - g_object_unref(context); - - return layout; -} - static struct colored_layout *layout_init_shared(cairo_t *c, struct notification *n) { struct colored_layout *cl = g_malloc(sizeof(struct colored_layout)); - cl->l = layout_create(c); + cl->l = pango_layout_new(pango_ctx); cl->is_xmore = false; cl->n = n; @@ -404,7 +383,7 @@ static GSList *create_layouts(cairo_t *c) } -static int layout_get_height(struct colored_layout *cl, double scale) +static int layout_get_height(struct colored_layout *cl) { int h_text = 0; int h_icon = 0; @@ -414,12 +393,12 @@ static int layout_get_height(struct colored_layout *cl, double scale) if (cl->n->hide_text) { vertical_padding = 0; } else { - get_text_size(cl->l, NULL, &h_text, scale); + get_text_size(cl->l, NULL, &h_text); vertical_padding = get_vertical_text_icon_padding(cl->n); } if (cl->icon) - h_icon = get_icon_height(cl->icon, scale); + h_icon = get_icon_height(cl->icon); if (have_progress_bar(cl)) { h_progress_bar = settings.progress_bar_height + settings.padding; @@ -462,35 +441,29 @@ static int frame_internal_radius (int r, int w, int h) /** * A small wrapper around cairo_rectange for drawing a scaled rectangle. */ -static inline void draw_rect(cairo_t *c, double x, double y, double width, double height, double scale) +static inline void draw_rect(cairo_t *c, int x, int y, int width, int height) { - cairo_rectangle(c, round(x * scale), round(y * scale), round(width * scale), round(height * scale)); + cairo_rectangle(c, x, y, width, height); } /** - * Create a path on the given cairo context to draw the background of a notification. + * Create a path on the given cairo pango_ctx to draw the background of a notification. * The top corners will get rounded by `corner_radius`, if `first` is set. * Respectably the same for `last` with the bottom corners. * * TODO: Pass additional frame width information to fix blurry lines due to fractional scaling * X and Y can then be calculated as: x = round(x*scale) + half_frame_width */ -void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int corner_radius, double scale, enum corner_pos corners) +void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, enum corner_pos corners) { // Fast path for simple rects if (corners == C_NONE || corner_radius <= 0) { - draw_rect(c, x, y, width, height, scale); + draw_rect(c, x, y, width, height); return; } - width = round(width * scale); - height = round(height * scale); - x *= scale; - y *= scale; - corner_radius = round(corner_radius * scale); - // Nothing valid to draw - if (width <= 0 || height <= 0 || scale <= 0) + if (width <= 0 || height <= 0) return; const double degrees = M_PI / 180.0; @@ -635,8 +608,7 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, int height, int corner_radius, enum corner_pos corners, - int *ret_width, - double scale) + int *ret_width) { int x = 0; int radius_int = corner_radius; @@ -656,7 +628,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, scale, corners); + draw_rounded_rect(c, x, y, width, height, corner_radius, corners); /* adding frame */ x += settings.frame_width; @@ -674,11 +646,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, scale, corners); + draw_rounded_rect(c, x, y, width, height, radius_int, corners); cairo_set_source_rgba(c, COLOR(cl, frame.r), COLOR(cl, frame.g), COLOR(cl, frame.b), COLOR(cl, frame.a)); cairo_fill(c); - draw_rounded_rect(c, x, y, width, height, radius_int, scale, corners); + draw_rounded_rect(c, x, y, width, height, radius_int, corners); cairo_set_source_rgba(c, COLOR(cl, bg.r), COLOR(cl, bg.g), COLOR(cl, bg.b), COLOR(cl, bg.a)); cairo_fill(c); @@ -690,7 +662,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); - draw_rect(c, settings.frame_width, y + height, width, settings.separator_height, scale); + draw_rect(c, settings.frame_width, y + height, width, settings.separator_height); cairo_fill(c); } @@ -700,18 +672,16 @@ static cairo_surface_t *render_background(cairo_surface_t *srf, if (ret_width) *ret_width = width; - return cairo_surface_create_for_rectangle(srf, - round(x * scale), round(y * scale), - round(width * scale), round(height * scale)); + return cairo_surface_create_for_rectangle(srf, x, y, width, height); } -static void render_content(cairo_t *c, struct colored_layout *cl, int width, double scale) +static void render_content(cairo_t *c, struct colored_layout *cl, int width) { // 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); - const int h = layout_get_height(cl, scale); + const int h = layout_get_height(cl); LOG_D("Layout height %i", h); int h_without_progress_bar = h; if (have_progress_bar(cl)) { @@ -720,7 +690,7 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou if (!cl->n->hide_text) { int h_text = 0; - get_text_size(cl->l, NULL, &h_text, scale); + get_text_size(cl->l, NULL, &h_text); int text_x = settings.h_padding, text_y = settings.padding + h_without_progress_bar / 2 - h_text / 2; @@ -738,12 +708,12 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou // icon position if (cl->n->icon_position == ICON_LEFT) { - text_x = get_icon_width(cl->icon, scale) + settings.h_padding + get_horizontal_text_icon_padding(cl->n); + text_x = get_icon_width(cl->icon) + settings.h_padding + get_horizontal_text_icon_padding(cl->n); } else if (cl->n->icon_position == ICON_TOP) { - text_y = get_icon_height(cl->icon, scale) + settings.padding + get_vertical_text_icon_padding(cl->n); + text_y = get_icon_height(cl->icon) + settings.padding + get_vertical_text_icon_padding(cl->n); } // else ICON_RIGHT } - cairo_move_to(c, round(text_x * scale), round(text_y * scale)); + cairo_move_to(c, text_x, text_y); cairo_set_source_rgba(c, COLOR(cl, fg.r), COLOR(cl, fg.g), COLOR(cl, fg.b), COLOR(cl, fg.a)); pango_cairo_update_layout(c, cl->l); @@ -752,8 +722,8 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou // icon positioning if (cl->icon) { - unsigned int image_width = get_icon_width(cl->icon, scale), - image_height = get_icon_height(cl->icon, scale), + unsigned int image_width = get_icon_width(cl->icon), + image_height = get_icon_height(cl->icon), image_x = width - settings.h_padding - image_width, image_y = settings.padding + h_without_progress_bar/2 - image_height/2; @@ -774,8 +744,8 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou image_x = width/2 - image_width/2; } // else ICON_RIGHT - cairo_set_source_surface(c, cl->icon, round(image_x * scale), round(image_y * scale)); - draw_rounded_rect(c, image_x, image_y, image_width, image_height, settings.icon_corner_radius, scale, settings.icon_corners); + cairo_set_source_surface(c, cl->icon, image_x, image_y); + draw_rounded_rect(c, image_x, image_y, image_width, image_height, settings.icon_corner_radius, settings.icon_corners); cairo_fill(c); } @@ -816,25 +786,25 @@ static void render_content(cairo_t *c, struct colored_layout *cl, int width, dou // back layer (background) cairo_set_source_rgba(c, COLOR(cl, bg.r), COLOR(cl, bg.g), COLOR(cl, bg.b), COLOR(cl, bg.a)); draw_rounded_rect(c, x_bar_2, frame_y, progress_width_2, progress_height, - settings.progress_bar_corner_radius, scale, settings.progress_bar_corners); + settings.progress_bar_corner_radius, settings.progress_bar_corners); cairo_fill(c); // top layer (fill) cairo_set_source_rgba(c, COLOR(cl, highlight.r), COLOR(cl, highlight.g), COLOR(cl, highlight.b), COLOR(cl, highlight.a)); draw_rounded_rect(c, x_bar_1, frame_y, progress_width_1, progress_height, - settings.progress_bar_corner_radius, scale, settings.progress_bar_corners); + settings.progress_bar_corner_radius, settings.progress_bar_corners); cairo_fill(c); // border cairo_set_source_rgba(c, COLOR(cl, frame.r), COLOR(cl, frame.g), COLOR(cl, frame.b), COLOR(cl, frame.a)); - cairo_set_line_width(c, frame_width * scale); + cairo_set_line_width(c, frame_width); draw_rounded_rect(c, frame_x + half_frame_width + 1, frame_y, progress_width - frame_width - 2, progress_height, settings.progress_bar_corner_radius, - scale, settings.progress_bar_corners); + settings.progress_bar_corners); cairo_stroke(c); } } @@ -845,19 +815,18 @@ static struct dimensions layout_render(cairo_surface_t *srf, struct dimensions dim, enum corner_pos corners) { - double scale = output->get_scale(); - const int cl_h = layout_get_height(cl, scale); + const int cl_h = layout_get_height(cl); int h_text = 0; - get_text_size(cl->l, NULL, &h_text, scale); + get_text_size(cl->l, NULL, &h_text); int bg_width = 0; int bg_height = MIN(settings.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, corners, &bg_width, scale); + cairo_surface_t *content = render_background(srf, cl, cl_next, dim.y, dim.w, bg_height, dim.corner_radius, corners, &bg_width); cairo_t *c = cairo_create(content); - render_content(c, cl, bg_width, scale); + render_content(c, cl, bg_width); /* adding frame */ if (corners & (C_TOP | _C_FIRST)) @@ -895,12 +864,12 @@ void calc_window_pos(const struct screen_info *scr, int width, int height, int * case ORIGIN_TOP_LEFT: case ORIGIN_LEFT_CENTER: case ORIGIN_BOTTOM_LEFT: - *ret_x = scr->x + round(settings.offset.x * draw_get_scale()); + *ret_x = scr->x + settings.offset.x; break; case ORIGIN_TOP_RIGHT: case ORIGIN_RIGHT_CENTER: case ORIGIN_BOTTOM_RIGHT: - *ret_x = scr->x + (scr->w - width) - round(settings.offset.x * draw_get_scale()); + *ret_x = scr->x + (scr->w - width) - settings.offset.x; break; case ORIGIN_TOP_CENTER: case ORIGIN_CENTER: @@ -915,12 +884,12 @@ void calc_window_pos(const struct screen_info *scr, int width, int height, int * case ORIGIN_TOP_LEFT: case ORIGIN_TOP_CENTER: case ORIGIN_TOP_RIGHT: - *ret_y = scr->y + round(settings.offset.y * draw_get_scale()); + *ret_y = scr->y + settings.offset.y; break; case ORIGIN_BOTTOM_LEFT: case ORIGIN_BOTTOM_CENTER: case ORIGIN_BOTTOM_RIGHT: - *ret_y = scr->y + (scr->h - height) - round(settings.offset.y * draw_get_scale()); + *ret_y = scr->y + (scr->h - height) - settings.offset.y; break; case ORIGIN_LEFT_CENTER: case ORIGIN_CENTER: @@ -936,8 +905,9 @@ void draw(void) assert(queues_length_displayed() > 0); cairo_t *c = output->win_get_context(win); + cairo_surface_t *srf = output->win_get_surface(win); - if (c == NULL) { + if (c == NULL || srf == NULL) { return; } @@ -945,11 +915,15 @@ void draw(void) struct dimensions dim = calculate_dimensions(layouts); LOG_D("Window dimensions %ix%i", dim.w, dim.h); - double scale = output->get_scale(); - cairo_surface_t *image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - round(dim.w * scale), - round(dim.h * scale)); + cairo_surface_t *image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dim.w, dim.h); + + // Scaling + double scale = output->get_scale(); + cairo_surface_set_device_scale(srf, scale, scale); + // NOTE: is this better or worse than screen->dpi? + pango_cairo_context_set_resolution(pango_ctx, scale * 96); + pango_cairo_update_context(c, pango_ctx); enum corner_pos corners = (settings.corners & C_TOP) | _C_FIRST; for (GSList *iter = layouts; iter; iter = iter->next) { @@ -966,6 +940,9 @@ void draw(void) corners &= ~(C_TOP | _C_FIRST); } + // NOTE: Currently display_surface scales the dimension on its own. Otherwise these + // logical dimensions (of the backbuffer surface) should have been scaled to + // the real pixel size output->display_surface(image_surface, win, &dim); cairo_surface_destroy(image_surface); @@ -974,19 +951,13 @@ void draw(void) void draw_deinit(void) { + g_object_unref(pango_ctx); + pango_font_description_free(pango_fdesc); + output->win_destroy(win); output->deinit(); if (settings.enable_recursive_icon_lookup) free_all_themes(); } -double 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 c2e04207f..e3a42c449 100644 --- a/src/draw.h +++ b/src/draw.h @@ -57,10 +57,7 @@ void draw_setup(void); void draw(void); -void draw_rounded_rect(cairo_t *c, float x, float y, int width, int height, int corner_radius, double scale, enum corner_pos corners); - -// TODO get rid of this function by passing scale to everything that needs it. -double draw_get_scale(void); +void draw_rounded_rect(cairo_t *c, int x, int y, int width, int height, int corner_radius, enum corner_pos corners); void draw_deinit(void); diff --git a/src/icon.c b/src/icon.c index 7807004d5..7f179364d 100644 --- a/src/icon.c +++ b/src/icon.c @@ -83,12 +83,12 @@ static void pixbuf_data_to_cairo_data( } } -int get_icon_width(cairo_surface_t *icon, double scale) { - return round(cairo_image_surface_get_width(icon) / scale); +int get_icon_width(cairo_surface_t *icon) { + return cairo_image_surface_get_width(icon); } -int get_icon_height(cairo_surface_t *icon, double scale) { - return round(cairo_image_surface_get_height(icon) / scale); +int get_icon_height(cairo_surface_t *icon) { + return cairo_image_surface_get_height(icon); } cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf) @@ -154,14 +154,13 @@ static bool icon_size_clamp(int *w, int *h, int min_size, int max_size) { * * @param pixbuf (nullable) The pixbuf, which may be too big. * Takes ownership of the reference. - * @param dpi_scale A double for the dpi scaling. * @param min_size The minimum allowed icon size. * @param max_size The maximum allowed icon size. * @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_to_size(GdkPixbuf *pixbuf, double dpi_scale, int min_size, int max_size) +static GdkPixbuf *icon_pixbuf_scale_to_size(GdkPixbuf *pixbuf, int min_size, int max_size) { ASSERT_OR_RET(pixbuf, NULL); @@ -169,10 +168,7 @@ static GdkPixbuf *icon_pixbuf_scale_to_size(GdkPixbuf *pixbuf, double dpi_scale, int h = gdk_pixbuf_get_height(pixbuf); // TODO immediately rescale icon upon scale changes - if(icon_size_clamp(&w, &h, min_size, max_size)) { - w = round(w * dpi_scale); - h = round(h * dpi_scale); - } + icon_size_clamp(&w, &h, min_size, max_size); GdkPixbuf *scaled = gdk_pixbuf_scale_simple( pixbuf, w, @@ -183,7 +179,7 @@ static GdkPixbuf *icon_pixbuf_scale_to_size(GdkPixbuf *pixbuf, double dpi_scale, return pixbuf; } -GdkPixbuf *get_pixbuf_from_file(const char *filename, int min_size, int max_size, double scale) +GdkPixbuf *get_pixbuf_from_file(const char *filename, int min_size, int max_size) { GError *error = NULL; gint w, h; @@ -196,8 +192,8 @@ GdkPixbuf *get_pixbuf_from_file(const char *filename, int min_size, int max_size // TODO immediately rescale icon upon scale changes icon_size_clamp(&w, &h, min_size, max_size); pixbuf = gdk_pixbuf_new_from_file_at_scale(filename, - round(w * scale), - round(h * scale), + w, + h, TRUE, &error); @@ -270,7 +266,7 @@ char *get_path_from_icon_name(const char *iconname, int size) return new_name; } -GdkPixbuf *icon_get_for_data(GVariant *data, char **id, double dpi_scale, int min_size, int max_size) +GdkPixbuf *icon_get_for_data(GVariant *data, char **id, int min_size, int max_size) { ASSERT_OR_RET(data, NULL); ASSERT_OR_RET(id, NULL); @@ -380,7 +376,7 @@ GdkPixbuf *icon_get_for_data(GVariant *data, char **id, double dpi_scale, int mi g_free(data_chk); g_variant_unref(data_variant); - pixbuf = icon_pixbuf_scale_to_size(pixbuf, dpi_scale, min_size, max_size); + pixbuf = icon_pixbuf_scale_to_size(pixbuf, min_size, max_size); return pixbuf; } diff --git a/src/icon.h b/src/icon.h index 13d04b07c..a411ab185 100644 --- a/src/icon.h +++ b/src/icon.h @@ -13,12 +13,11 @@ cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf); * @param filename A string representing a readable file path * @param min_size An iteger representing the desired minimum unscaled icon size. * @param max_size An iteger representing the desired maximum unscaled icon size. - * @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, int min_size, int max_size, double scale); +GdkPixbuf *get_pixbuf_from_file(const char *filename, int min_size, int max_size); /** @@ -27,12 +26,12 @@ GdkPixbuf *get_pixbuf_from_file(const char *filename, int min_size, int max_size * 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, double scale); +int get_icon_width(cairo_surface_t *icon); /** * Get the unscaled icon height, see get_icon_width. */ -int get_icon_height(cairo_surface_t *icon, double scale); +int get_icon_height(cairo_surface_t *icon); /** Retrieve a path from an icon name. * @@ -56,13 +55,12 @@ char *get_path_from_icon_name(const char *iconname, int size); * 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 dpi_scale An integer representing the output dpi scaling. * @param min_size An integer representing the desired minimum unscaled icon size. * @param max_size An integer representing the desired maximum unscaled icon size. * @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, double dpi_scale, int min_size, int max_size); +GdkPixbuf *icon_get_for_data(GVariant *data, char **id, int min_size, int max_size); #endif /* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */ diff --git a/src/notification.c b/src/notification.c index 94411c232..5ba321aad 100644 --- a/src/notification.c +++ b/src/notification.c @@ -356,9 +356,7 @@ void notification_icon_replace_path(struct notification *n, const char *new_icon g_free(n->icon_path); n->icon_path = get_path_from_icon_name(new_icon, n->min_icon_size); if (n->icon_path) { - GdkPixbuf *pixbuf = get_pixbuf_from_file(n->icon_path, - n->min_icon_size, n->max_icon_size, - draw_get_scale()); + GdkPixbuf *pixbuf = get_pixbuf_from_file(n->icon_path, n->min_icon_size, n->max_icon_size); if (pixbuf) { n->icon = gdk_pixbuf_to_cairo_surface(pixbuf); g_object_unref(pixbuf); @@ -377,8 +375,7 @@ void notification_icon_replace_data(struct notification *n, GVariant *new_icon) n->icon = NULL; g_clear_pointer(&n->icon_id, g_free); - GdkPixbuf *icon = icon_get_for_data(new_icon, &n->icon_id, - draw_get_scale(), n->min_icon_size, n->max_icon_size); + GdkPixbuf *icon = icon_get_for_data(new_icon, &n->icon_id, n->min_icon_size, n->max_icon_size); n->icon = gdk_pixbuf_to_cairo_surface(icon); if (icon) g_object_unref(icon); diff --git a/src/output.c b/src/output.c index 32dd2fe4b..f180553c4 100644 --- a/src/output.c +++ b/src/output.c @@ -28,6 +28,7 @@ const struct output output_x11 = { x_display_surface, x_win_get_context, + x_win_get_surface, get_active_screen, @@ -51,6 +52,7 @@ const struct output output_wl = { wl_display_surface, wl_win_get_context, + wl_win_get_surface, wl_get_active_screen, diff --git a/src/output.h b/src/output.h index aaf214841..ea39c29c2 100644 --- a/src/output.h +++ b/src/output.h @@ -29,6 +29,7 @@ struct screen_info { int dpi; }; +// NOTE: Refactor the output struct struct output { bool (*init)(void); void (*deinit)(void); @@ -42,6 +43,7 @@ struct output { void (*display_surface)(cairo_surface_t *srf, window win, const struct dimensions*); cairo_t* (*win_get_context)(window); + cairo_surface_t* (*win_get_surface)(window); const struct screen_info* (*get_active_screen)(void); diff --git a/src/wayland/wl.c b/src/wayland/wl.c index e97e35662..36a0bc56f 100644 --- a/src/wayland/wl.c +++ b/src/wayland/wl.c @@ -583,10 +583,10 @@ 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; */ - 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); + double scale = wl_get_scale(); + int w = round(dim->w * scale), h = round(dim->h * scale); + LOG_D("Buffer size (scaled) %ix%i", w, h); + ctx.current_buffer = get_next_buffer(ctx.shm, ctx.buffers, w, h); if(ctx.current_buffer == NULL) { return; @@ -595,7 +595,7 @@ void wl_display_surface(cairo_surface_t *srf, window winptr, const struct dimens 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 * scale, dim->h * scale); + cairo_rectangle(c, 0, 0, w, h); cairo_fill(c); cairo_restore(c); @@ -618,6 +618,18 @@ cairo_t* wl_win_get_context(window winptr) { return win->c_ctx; } +cairo_surface_t* wl_win_get_surface(window winptr) { + struct window_wl *win = (struct window_wl*)winptr; + ctx.current_buffer = get_next_buffer(ctx.shm, ctx.buffers, 500, 500); + + if(ctx.current_buffer == NULL) { + return NULL; + } + + win->c_surface = ctx.current_buffer->surface; + return win->c_surface; +} + const struct screen_info* wl_get_active_screen(void) { static struct screen_info scr = { .w = 3840, @@ -685,6 +697,9 @@ bool wl_have_fullscreen_window(void) { } double wl_get_scale(void) { + if (settings.scale > 0) + return settings.scale; + int scale = 0; struct dunst_output *output = get_configured_output(); if (output) { diff --git a/src/wayland/wl.h b/src/wayland/wl.h index 34814917b..11a03b0fe 100644 --- a/src/wayland/wl.h +++ b/src/wayland/wl.h @@ -18,6 +18,7 @@ void wl_win_hide(window); void wl_display_surface(cairo_surface_t *srf, window win, const struct dimensions*); cairo_t* wl_win_get_context(window); +cairo_surface_t* wl_win_get_surface(window); const struct screen_info* wl_get_active_screen(void); diff --git a/src/wayland/wl_seat.c b/src/wayland/wl_seat.c index ffc1e48be..37134e446 100644 --- a/src/wayland/wl_seat.c +++ b/src/wayland/wl_seat.c @@ -18,6 +18,7 @@ #include "../log.h" #include "../settings.h" #include "wl_ctx.h" +#include "wl.h" static void touch_handle_motion(void *data, struct wl_touch *wl_touch, uint32_t time, int32_t id, @@ -50,8 +51,10 @@ static void touch_handle_up(void *data, struct wl_touch *wl_touch, if (id >= MAX_TOUCHPOINTS) { return; } + + double scale = wl_get_scale(); input_handle_click(BTN_TOUCH, false, - seat->touch.pts[id].x, seat->touch.pts[id].y); + seat->touch.pts[id].x/scale, seat->touch.pts[id].y/scale); } @@ -100,7 +103,8 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uint32_t button_state) { struct dunst_seat *seat = data; - input_handle_click(button, button_state, seat->pointer.x, seat->pointer.y); + double scale = wl_get_scale(); + input_handle_click(button, button_state, seat->pointer.x/scale, seat->pointer.y/scale); } static void pointer_handle_leave(void *data, struct wl_pointer *wl_pointer, diff --git a/src/x11/x.c b/src/x11/x.c index 440751914..d9f40397b 100644 --- a/src/x11/x.c +++ b/src/x11/x.c @@ -118,10 +118,7 @@ static void x_win_corners_shape(struct window_x11 *win, const int rad) cairo_paint(cr); cairo_set_source_rgba(cr, 1, 1, 1, 1); - draw_rounded_rect(cr, 0, 0, - width, height, - rad, 1, - settings.corners); + draw_rounded_rect(cr, 0, 0, width, height, rad, settings.corners); cairo_fill(cr); cairo_show_page(cr); @@ -197,6 +194,11 @@ cairo_t* x_win_get_context(window winptr) return ((struct window_x11*)win)->c_ctx; } +cairo_surface_t* x_win_get_surface(window win) +{ + return ((struct window_x11*)win)->root_surface; +} + static void setopacity(Window win, unsigned long opacity) { Atom _NET_WM_WINDOW_OPACITY = diff --git a/src/x11/x.h b/src/x11/x.h index e7dee7d70..3a6cf3178 100644 --- a/src/x11/x.h +++ b/src/x11/x.h @@ -32,6 +32,7 @@ void x_win_hide(window); void x_display_surface(cairo_surface_t *srf, window, const struct dimensions *dim); cairo_t* x_win_get_context(window); +cairo_surface_t* x_win_get_surface(window); /* X misc */ bool x_is_idle(void); diff --git a/test/draw.c b/test/draw.c index 2b2b5d389..3c7322218 100644 --- a/test/draw.c +++ b/test/draw.c @@ -14,7 +14,7 @@ cairo_t *c; double get_dummy_scale(void) { return 1; } const struct screen_info* noop_screen(void) { - static struct screen_info i; + static struct screen_info i = {0}; return &i; } @@ -31,6 +31,7 @@ const struct output dummy_output = { wl_display_surface, wl_win_get_context, + wl_win_get_surface, noop_screen, @@ -48,6 +49,7 @@ const struct output dummy_output = { x_display_surface, x_win_get_context, + x_win_get_surface, noop_screen, @@ -265,15 +267,18 @@ TEST test_layout_render_no_gaps(void) dim = calculate_dimensions(layouts); image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); - enum corner_pos corners = C_TOP | _C_FIRST; + enum corner_pos corners = (settings.corners & C_TOP) | _C_FIRST; for (GSList *iter = layouts; iter; iter = iter->next) { + struct colored_layout *cl_this = iter->data; struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; - if (!cl_next) - corners |= C_BOT | _C_LAST; - dim = layout_render(image_surface, cl_this, cl_next, dim, corners); + if (settings.gap_size) + corners = settings.corners; + else if (!cl_next) + corners |= (settings.corners & C_BOT) | _C_LAST; + dim = layout_render(image_surface, cl_this, cl_next, dim, corners); corners &= ~(C_TOP | _C_FIRST); } @@ -309,11 +314,19 @@ TEST test_layout_render_gaps(void) dim = calculate_dimensions(layouts); image_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + enum corner_pos corners = (settings.corners & C_TOP) | _C_FIRST; for (GSList *iter = layouts; iter; iter = iter->next) { + struct colored_layout *cl_this = iter->data; struct colored_layout *cl_next = iter->next ? iter->next->data : NULL; - dim = layout_render(image_surface, cl_this, cl_next, dim, C_ALL); + if (settings.gap_size) + corners = settings.corners; + else if (!cl_next) + corners |= (settings.corners & C_BOT) | _C_LAST; + + dim = layout_render(image_surface, cl_this, cl_next, dim, corners); + corners &= ~(C_TOP | _C_FIRST); } expected_y = get_expected_dimension_y_offset(layout_count); @@ -334,6 +347,10 @@ SUITE(suite_draw) cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); c = cairo_create(s); + // XXX: This variable should not be accessed like this + extern PangoContext *pango_ctx; + pango_ctx = pango_cairo_create_context(c); + SHUFFLE_TESTS(time(NULL), { RUN_TEST(test_layout_from_notification); RUN_TEST(test_layout_from_notification_icon_off); @@ -343,4 +360,8 @@ SUITE(suite_draw) RUN_TEST(test_layout_render_no_gaps); RUN_TEST(test_layout_render_gaps); }); + + g_object_unref(pango_ctx); + cairo_destroy(c); + cairo_surface_destroy(s); } diff --git a/test/notification.c b/test/notification.c index 392580c79..2daedfd17 100644 --- a/test/notification.c +++ b/test/notification.c @@ -168,8 +168,8 @@ TEST test_notification_icon_scaling_toosmall(void) struct notification *n = notification_load_icon_with_scaling(20, 100); ASSERT(n->icon); - ASSERT_EQ(get_icon_width(n->icon, 1), 20); - ASSERT_EQ(get_icon_height(n->icon, 1), 20); + ASSERT_EQ(get_icon_width(n->icon), 20); + ASSERT_EQ(get_icon_height(n->icon), 20); notification_unref(n); @@ -182,8 +182,8 @@ TEST test_notification_icon_scaling_toolarge(void) struct notification *n = notification_load_icon_with_scaling(5, 10); ASSERT(n->icon); - ASSERT_EQ(get_icon_width(n->icon, 1), 10); - ASSERT_EQ(get_icon_height(n->icon, 1), 10); + ASSERT_EQ(get_icon_width(n->icon), 10); + ASSERT_EQ(get_icon_height(n->icon), 10); notification_unref(n); @@ -195,8 +195,8 @@ TEST test_notification_icon_scaling_notconfigured(void) struct notification *n = notification_load_icon_with_scaling(0, 0); ASSERT(n->icon); - ASSERT_EQ(get_icon_width(n->icon, 1), 16); - ASSERT_EQ(get_icon_height(n->icon, 1), 16); + ASSERT_EQ(get_icon_width(n->icon), 16); + ASSERT_EQ(get_icon_height(n->icon), 16); notification_unref(n); @@ -208,8 +208,8 @@ TEST test_notification_icon_scaling_notneeded(void) struct notification *n = notification_load_icon_with_scaling(10, 20); ASSERT(n->icon); - ASSERT_EQ(get_icon_width(n->icon, 1), 16); - ASSERT_EQ(get_icon_height(n->icon, 1), 16); + ASSERT_EQ(get_icon_width(n->icon), 16); + ASSERT_EQ(get_icon_height(n->icon), 16); notification_unref(n);