diff --git a/src/ui/frames.c b/src/ui/frames.c index 74135d9bd..362d7b6fb 100644 --- a/src/ui/frames.c +++ b/src/ui/frames.c @@ -1389,6 +1389,7 @@ meta_ui_frame_get_mask (MetaUIFrame *frame, MetaFrameBorders borders; MetaFrameFlags flags; MetaRectangle frame_rect; + int scale = meta_theme_get_window_scaling_factor (); meta_window_get_frame_rect (frame->meta_window, &frame_rect); @@ -1396,9 +1397,13 @@ meta_ui_frame_get_mask (MetaUIFrame *frame, meta_style_info_set_flags (frame->style_info, flags); meta_ui_frame_get_borders (frame, &borders); + + /* See comment in meta_frame_layout_draw_with_style() for details on HiDPI handling */ + cairo_scale (cr, scale, scale); gtk_render_background (frame->style_info->styles[META_STYLE_ELEMENT_FRAME], cr, - borders.invisible.left, borders.invisible.top, - frame_rect.width, frame_rect.height); + borders.invisible.left / scale, + borders.invisible.top / scale, + frame_rect.width / scale, frame_rect.height / scale); } /* XXX -- this is disgusting. Find a better approach here. diff --git a/src/ui/theme-private.h b/src/ui/theme-private.h index 4a5eddbaf..cdf23a038 100644 --- a/src/ui/theme-private.h +++ b/src/ui/theme-private.h @@ -276,5 +276,6 @@ void meta_theme_calc_geometry (MetaTheme *theme, int meta_pango_font_desc_get_text_height (const PangoFontDescription *font_desc, PangoContext *context); +int meta_theme_get_window_scaling_factor (void); #endif /* META_THEME_PRIVATE_H */ diff --git a/src/ui/theme.c b/src/ui/theme.c index 243d369c2..f73b42857 100644 --- a/src/ui/theme.c +++ b/src/ui/theme.c @@ -30,6 +30,8 @@ #define DEBUG_FILL_STRUCT(s) memset ((s), 0xef, sizeof (*(s))) +static void scale_border (GtkBorder *border, double factor); + static MetaFrameLayout * meta_frame_layout_new (void) { @@ -65,6 +67,7 @@ meta_frame_layout_get_borders (const MetaFrameLayout *layout, MetaFrameBorders *borders) { int buttons_height, content_height, draggable_borders; + int scale = meta_theme_get_window_scaling_factor (); meta_frame_borders_clear (borders); @@ -110,6 +113,26 @@ meta_frame_layout_get_borders (const MetaFrameLayout *layout, borders->total.right = borders->invisible.right + borders->visible.right; borders->total.bottom = borders->invisible.bottom + borders->visible.bottom; borders->total.top = borders->invisible.top + borders->visible.top; + + /* Scale geometry for HiDPI, see comment in meta_frame_layout_draw_with_style() */ + scale_border (&borders->visible, scale); + scale_border (&borders->invisible, scale); + scale_border (&borders->total, scale); +} + +int +meta_theme_get_window_scaling_factor () +{ + GdkScreen *screen; + GValue value = G_VALUE_INIT; + + g_value_init (&value, G_TYPE_INT); + + screen = gdk_screen_get_default (); + if (gdk_screen_get_setting (screen, "gdk-window-scaling-factor", &value)) + return g_value_get_int (&value); + else + return 1; } void @@ -117,8 +140,8 @@ meta_frame_layout_apply_scale (const MetaFrameLayout *layout, PangoFontDescription *font_desc) { int size = pango_font_description_get_size (font_desc); - pango_font_description_set_size (font_desc, - MAX (size * layout->title_scale, 1)); + double scale = layout->title_scale / meta_theme_get_window_scaling_factor (); + pango_font_description_set_size (font_desc, MAX (size * scale, 1)); } static MetaButtonSpace* @@ -306,6 +329,7 @@ meta_frame_layout_calc_geometry (MetaFrameLayout *layout, int content_width, content_height; int button_width, button_height; int min_size_for_rounding; + int scale = meta_theme_get_window_scaling_factor (); /* the left/right rects in order; the max # of rects * is the number of button functions @@ -325,11 +349,12 @@ meta_frame_layout_calc_geometry (MetaFrameLayout *layout, fgeom->borders = borders; + /* Scale geometry for HiDPI, see comment in meta_frame_layout_draw_with_style() */ fgeom->content_border = layout->frame_border; - fgeom->content_border.left += layout->titlebar_border.left; - fgeom->content_border.right += layout->titlebar_border.right; - fgeom->content_border.top += layout->titlebar_border.top; - fgeom->content_border.bottom += layout->titlebar_border.bottom; + fgeom->content_border.left += layout->titlebar_border.left * scale; + fgeom->content_border.right += layout->titlebar_border.right * scale; + fgeom->content_border.top += layout->titlebar_border.top * scale; + fgeom->content_border.bottom += layout->titlebar_border.bottom * scale; width = client_width + borders.total.left + borders.total.right; @@ -349,6 +374,8 @@ meta_frame_layout_calc_geometry (MetaFrameLayout *layout, layout->button_border.left + layout->button_border.right; button_height = layout->icon_size + layout->button_border.top + layout->button_border.bottom; + button_width *= scale; + button_height *= scale; /* FIXME all this code sort of pretends that duplicate buttons * with the same function are allowed, but that breaks the @@ -408,11 +435,11 @@ meta_frame_layout_calc_geometry (MetaFrameLayout *layout, space_used_by_buttons += button_width * n_left; space_used_by_buttons += (button_width * 0.75) * n_left_spacers; - space_used_by_buttons += layout->titlebar_spacing * MAX (n_left - 1, 0); + space_used_by_buttons += layout->titlebar_spacing * scale * MAX (n_left - 1, 0); space_used_by_buttons += button_width * n_right; space_used_by_buttons += (button_width * 0.75) * n_right_spacers; - space_used_by_buttons += layout->titlebar_spacing * MAX (n_right - 1, 0); + space_used_by_buttons += layout->titlebar_spacing * scale * MAX (n_right - 1, 0); if (space_used_by_buttons <= content_width) break; /* Everything fits, bail out */ @@ -564,7 +591,7 @@ meta_frame_layout_calc_geometry (MetaFrameLayout *layout, x = rect->visible.x + rect->visible.width; if (i < n_left - 1) - x += layout->titlebar_spacing; + x += layout->titlebar_spacing * scale; if (left_buttons_has_spacer[i]) x += (button_width * 0.75); } @@ -587,7 +614,7 @@ meta_frame_layout_calc_geometry (MetaFrameLayout *layout, if (flags & META_FRAME_SHADED) min_size_for_rounding = 0; else - min_size_for_rounding = 5; + min_size_for_rounding = 5 * scale; fgeom->top_left_corner_rounded_radius = 0; fgeom->top_right_corner_rounded_radius = 0; @@ -595,14 +622,14 @@ meta_frame_layout_calc_geometry (MetaFrameLayout *layout, fgeom->bottom_right_corner_rounded_radius = 0; if (borders.visible.top + borders.visible.left >= min_size_for_rounding) - fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius; + fgeom->top_left_corner_rounded_radius = layout->top_left_corner_rounded_radius * scale; if (borders.visible.top + borders.visible.right >= min_size_for_rounding) - fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius; + fgeom->top_right_corner_rounded_radius = layout->top_right_corner_rounded_radius * scale; if (borders.visible.bottom + borders.visible.left >= min_size_for_rounding) - fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius; + fgeom->bottom_left_corner_rounded_radius = layout->bottom_left_corner_rounded_radius * scale; if (borders.visible.bottom + borders.visible.right >= min_size_for_rounding) - fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius; + fgeom->bottom_right_corner_rounded_radius = layout->bottom_right_corner_rounded_radius * scale; } static void @@ -696,13 +723,27 @@ meta_frame_layout_draw_with_style (MetaFrameLayout *layout, GdkRectangle titlebar_rect; GdkRectangle button_rect; const MetaFrameBorders *borders; + int scale = meta_theme_get_window_scaling_factor (); + + /* We opt out of GTK+/Clutter's HiDPI handling, so we have to do the scaling + * ourselves; the nitty-gritty is a bit confusing, so here is an overview: + * - the values in MetaFrameLayout are always as they appear in the theme, + * i.e. unscaled + * - calculated values (borders, MetaFrameGeometry) include the scale - as + * the geometry is comprised of scaled decorations and the client size + * which we must not scale, we don't have another option + * - for drawing, we scale the canvas to have GTK+ render elements (borders, + * radii, ...) at the correct scale - as a result, we have to "unscale" + * the geometry again to not apply the scaling twice + */ + cairo_scale (cr, scale, scale); borders = &fgeom->borders; - visible_rect.x = borders->invisible.left; - visible_rect.y = borders->invisible.top; - visible_rect.width = fgeom->width - borders->invisible.left - borders->invisible.right; - visible_rect.height = fgeom->height - borders->invisible.top - borders->invisible.bottom; + visible_rect.x = borders->invisible.left / scale; + visible_rect.y = borders->invisible.top / scale; + visible_rect.width = (fgeom->width - borders->invisible.left - borders->invisible.right) / scale; + visible_rect.height = (fgeom->height - borders->invisible.top - borders->invisible.bottom) / scale; meta_style_info_set_flags (style_info, flags); @@ -717,7 +758,7 @@ meta_frame_layout_draw_with_style (MetaFrameLayout *layout, titlebar_rect.x = visible_rect.x; titlebar_rect.y = visible_rect.y; titlebar_rect.width = visible_rect.width; - titlebar_rect.height = borders->visible.top; + titlebar_rect.height = borders->visible.top / scale; style = style_info->styles[META_STYLE_ELEMENT_TITLEBAR]; gtk_render_background (style, cr, @@ -735,7 +776,7 @@ meta_frame_layout_draw_with_style (MetaFrameLayout *layout, pango_layout_set_width (title_layout, -1); pango_layout_get_pixel_extents (title_layout, NULL, &logical); - text_width = MIN(fgeom->title_rect.width, logical.width); + text_width = MIN(fgeom->title_rect.width / scale, logical.width); if (text_width < logical.width) pango_layout_set_width (title_layout, PANGO_SCALE * text_width); @@ -744,10 +785,10 @@ meta_frame_layout_draw_with_style (MetaFrameLayout *layout, x = titlebar_rect.x + (titlebar_rect.width - text_width) / 2; y = titlebar_rect.y + (titlebar_rect.height - logical.height) / 2; - if (x < fgeom->title_rect.x) - x = fgeom->title_rect.x; - else if (x + text_width > fgeom->title_rect.x + fgeom->title_rect.width) - x = fgeom->title_rect.x + fgeom->title_rect.width - text_width; + if (x < fgeom->title_rect.x / scale) + x = fgeom->title_rect.x / scale; + else if (x + text_width > (fgeom->title_rect.x + fgeom->title_rect.width) / scale) + x = (fgeom->title_rect.x + fgeom->title_rect.width) / scale - text_width; style = style_info->styles[META_STYLE_ELEMENT_TITLE]; gtk_render_layout (style, cr, x, y, title_layout); @@ -763,6 +804,11 @@ meta_frame_layout_draw_with_style (MetaFrameLayout *layout, get_button_rect (button_type, fgeom, &button_rect); + button_rect.x /= scale; + button_rect.y /= scale; + button_rect.width /= scale; + button_rect.height /= scale; + if (button_states[button_type] == META_BUTTON_STATE_PRELIGHT) gtk_style_context_set_state (style, state | GTK_STATE_PRELIGHT); else if (button_states[button_type] == META_BUTTON_STATE_PRESSED) @@ -815,9 +861,10 @@ meta_frame_layout_draw_with_style (MetaFrameLayout *layout, GtkIconInfo *info; GdkPixbuf *pixbuf; - info = gtk_icon_theme_lookup_icon (theme, icon_name, layout->icon_size, 0); + info = gtk_icon_theme_lookup_icon_for_scale (theme, icon_name, + layout->icon_size, scale, 0); pixbuf = gtk_icon_info_load_symbolic_for_context (info, style, NULL, NULL); - surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, 1, NULL); + surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, NULL); } if (surface) @@ -825,8 +872,8 @@ meta_frame_layout_draw_with_style (MetaFrameLayout *layout, float width, height; int x, y; - width = cairo_image_surface_get_width (surface); - height = cairo_image_surface_get_height (surface); + width = cairo_image_surface_get_width (surface) / scale; + height = cairo_image_surface_get_height (surface) / scale; x = button_rect.x + (button_rect.width - width) / 2; y = button_rect.y + (button_rect.height - height) / 2; @@ -939,6 +986,7 @@ create_style_context (GType widget_type, va_list ap; style = gtk_style_context_new (); + gtk_style_context_set_scale (style, meta_theme_get_window_scaling_factor ()); gtk_style_context_set_parent (style, parent_style); if (parent_style)