[mutter] theme: Scale window decorations on HiDPI displays
- From: Florian Müllner <fmuellner src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] theme: Scale window decorations on HiDPI displays
- Date: Tue, 17 Mar 2015 16:10:14 +0000 (UTC)
commit 57c1078ee742d9f01e80e7fe05c88adfec4b4ac3
Author: Florian Müllner <fmuellner gnome org>
Date: Thu Oct 2 01:05:18 2014 +0200
theme: Scale window decorations on HiDPI displays
As we opt out of GTK+/Clutter's HiDPI handling, we need to apply the
window scaling factor manually to decorations, both the geometry and
when drawing.
https://bugzilla.gnome.org/show_bug.cgi?id=744354
src/ui/frames.c | 9 +++-
src/ui/theme-private.h | 1 +
src/ui/theme.c | 104 +++++++++++++++++++++++++++++++++++-------------
3 files changed, 84 insertions(+), 30 deletions(-)
---
diff --git a/src/ui/frames.c b/src/ui/frames.c
index 74135d9..362d7b6 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 4a5eddb..cdf23a0 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 243d369..f73b428 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)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]