Merge pull request #854 from fwSmit/wayland-hidpi

wayland hidpi support
This commit is contained in:
Nikos Tsipinakis 2021-05-26 20:31:50 +02:00 committed by GitHub
commit b77f76f02e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 222 additions and 89 deletions

View File

@ -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: */

View File

@ -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: */

View File

@ -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);

View File

@ -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);
@ -389,7 +402,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;
}

View File

@ -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: */

View File

@ -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);
@ -313,7 +314,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)
@ -324,7 +325,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 */

View File

@ -29,7 +29,9 @@ const struct output output_x11 = {
get_active_screen,
x_is_idle,
have_fullscreen_window
have_fullscreen_window,
x_get_scale,
};
#ifdef ENABLE_WAYLAND
@ -49,7 +51,9 @@ const struct output output_wl = {
wl_get_active_screen,
wl_is_idle,
wl_have_fullscreen_window
wl_have_fullscreen_window,
wl_get_scale,
};
#endif

View File

@ -44,6 +44,8 @@ struct output {
bool (*is_idle)(void);
bool (*have_fullscreen_window)(void);
int (*get_scale)(void);
};
/**

View File

@ -107,7 +107,7 @@ static void output_handle_geometry(void *data, struct wl_output *wl_output,
int32_t x, int32_t y, int32_t phy_width, int32_t phy_height,
int32_t subpixel, const char *make, const char *model,
int32_t transform) {
//TODO
//TODO do something with the subpixel data
struct dunst_output *output = data;
output->subpixel = subpixel;
}
@ -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 = {
@ -135,7 +137,6 @@ static void create_output( struct wl_output *wl_output, uint32_t global_name) {
LOG_I("New output found - id %i", number);
output->global_name = global_name;
output->wl_output = wl_output;
// TODO: Fix this
output->scale = 1;
output->fullscreen = false;
wl_list_insert(&ctx.outputs, &output->link);
@ -227,7 +228,6 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
ctx.pointer.wl_pointer = wl_seat_get_pointer(wl_seat);
wl_pointer_add_listener(ctx.pointer.wl_pointer,
&pointer_listener, ctx.seat);
LOG_I("Adding pointer");
}
if (ctx.touch.wl_touch != NULL) {
wl_touch_release(ctx.touch.wl_touch);
@ -343,20 +343,29 @@ static void add_seat_to_idle_handler(struct wl_seat *seat) {
// Warning, can return NULL
static struct dunst_output *get_configured_output() {
switch (settings.f_mode){
case FOLLOW_NONE: ; // this semicolon is neccesary
int n = 0;
int target_monitor = settings.monitor;
struct dunst_output *output;
wl_list_for_each(output, &ctx.outputs, link) {
struct dunst_output *first_output = NULL, *configured_output = NULL,
*tmp_output = NULL;
wl_list_for_each(tmp_output, &ctx.outputs, link) {
if (n == 0)
first_output = tmp_output;
if (n == target_monitor)
return output;
configured_output = tmp_output;
n++;
}
// There's only 1 output, so return that
if (n == 1)
return first_output;
switch (settings.f_mode){
case FOLLOW_NONE: ; // this semicolon is neccesary
if (!configured_output) {
LOG_W("Monitor %i doesn't exist, using focused monitor", settings.monitor);
return NULL;
}
return configured_output;
case FOLLOW_MOUSE:
// fallthrough
case FOLLOW_KEYBOARD:
@ -626,7 +635,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;
@ -692,8 +701,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);
@ -818,12 +825,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);
@ -851,6 +861,7 @@ const struct screen_info* wl_get_active_screen(void) {
.id = 0,
.mmh = 500
};
scr.dpi = wl_get_scale() * 96;
return &scr;
}
@ -886,4 +897,21 @@ bool wl_have_fullscreen_window(void) {
LOG_D("Fullscreen queried: %i", have_fullscreen);
return have_fullscreen;
}
int wl_get_scale(void) {
int scale = 0;
struct dunst_output *output = get_configured_output();
if (output) {
scale = output->scale;
} else {
// return the largest scale
struct dunst_output *output;
wl_list_for_each(output, &ctx.outputs, link) {
scale = MAX(output->scale, scale);
}
}
if (scale <= 0)
scale = 1;
return scale;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -23,5 +23,10 @@ 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: */

View File

@ -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);
@ -942,4 +942,8 @@ static void x_shortcut_init(struct keyboard_shortcut *ks)
g_free(str_begin);
}
int x_get_scale(void) {
return 1;
}
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -51,5 +51,6 @@ void x_free(void);
struct geometry x_parse_geometry(const char *geom_str);
int x_get_scale(void);
#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

View File

@ -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);