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
This commit is contained in:
parent
3a2920d4bc
commit
57c1078ee7
3 changed files with 84 additions and 30 deletions
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
|
104
src/ui/theme.c
104
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)
|
||||
|
|
Loading…
Reference in a new issue