[gtk+] Handle resolution changes in the GDK backend code



commit fc6e2cc4b27403707bf2a9f4717442842914e626
Author: Owen W. Taylor <otaylor fishsoup net>
Date:   Fri Jul 11 16:42:38 2014 -0400

    Handle resolution changes in the GDK backend code
    
    gdk_x11_display_set_window_scale() affects the interpretation of the
    Xft/DPI XSETTING - it is substituted inside GDK with the value of
    Gdk/UnscaledDPI xsetting. However, this change is not propagated to
    GTK+ and from GTK+ back to gdk_screen_set_resolution() until the
    main loop is run.
    
    Fix this by handling the screen resolution directly in gdk/x11.
    This requires duplication of code between GDK and GTK+ since we still
    have to handle DPI in GTK+ in the case that GdkSettings:gtk-xft-dpi
    is set by the application.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=733076

 gdk/gdkinternals.h              |    2 ++
 gdk/gdkscreen.c                 |   25 +++++++++++++++++++++++++
 gdk/gdkscreenprivate.h          |    1 +
 gdk/quartz/gdkscreen-quartz.c   |    4 ++--
 gdk/wayland/gdkscreen-wayland.c |   15 +++++++++++++++
 gdk/x11/xsettings-client.c      |   37 +++++++++++++++++++++++++++++++++++++
 gtk/gtksettings.c               |   37 ++++++++++++++++++++++---------------
 7 files changed, 104 insertions(+), 17 deletions(-)
---
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index a2c4e53..f58ccb0 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -345,6 +345,8 @@ gboolean   _gdk_window_update_viewable   (GdkWindow      *window);
 void       _gdk_window_process_updates_recurse (GdkWindow *window,
                                                 cairo_region_t *expose_region);
 
+void       _gdk_screen_set_resolution    (GdkScreen      *screen,
+                                          gdouble         dpi);
 void       _gdk_screen_close             (GdkScreen      *screen);
 
 /*****************************************
diff --git a/gdk/gdkscreen.c b/gdk/gdkscreen.c
index e2cbfb7..cc170c5 100644
--- a/gdk/gdkscreen.c
+++ b/gdk/gdkscreen.c
@@ -462,6 +462,31 @@ gdk_screen_set_resolution (GdkScreen *screen,
   if (dpi < 0)
     dpi = -1.0;
 
+  screen->resolution_set = TRUE;
+
+  if (screen->resolution != dpi)
+    {
+      screen->resolution = dpi;
+
+      g_object_notify (G_OBJECT (screen), "resolution");
+    }
+}
+
+/* Just like gdk_screen_set_resolution(), but doesn't change
+ * screen->resolution. This is us to allow us to distinguish
+ * resolution changes that the backend picks up from resolution
+ * changes made through the public API - perhaps using
+ * g_object_set(<GtkSetting>, "gtk-xft-dpi", ...);
+ */
+void
+_gdk_screen_set_resolution (GdkScreen *screen,
+                            gdouble    dpi)
+{
+  g_return_if_fail (GDK_IS_SCREEN (screen));
+
+  if (dpi < 0)
+    dpi = -1.0;
+
   if (screen->resolution != dpi)
     {
       screen->resolution = dpi;
diff --git a/gdk/gdkscreenprivate.h b/gdk/gdkscreenprivate.h
index 23cf1bd..15c4056 100644
--- a/gdk/gdkscreenprivate.h
+++ b/gdk/gdkscreenprivate.h
@@ -35,6 +35,7 @@ struct _GdkScreen
 
   cairo_font_options_t *font_options;
   gdouble resolution; /* pixels/points scale factor for fonts */
+  guint resolution_set : 1; /* resolution set through public API */
   guint closed : 1;
 };
 
diff --git a/gdk/quartz/gdkscreen-quartz.c b/gdk/quartz/gdkscreen-quartz.c
index e4d4090..ca655a5 100644
--- a/gdk/quartz/gdkscreen-quartz.c
+++ b/gdk/quartz/gdkscreen-quartz.c
@@ -75,8 +75,8 @@ gdk_quartz_screen_init (GdkQuartzScreen *quartz_screen)
   NSScreen *nsscreen;
 
   nsscreen = [[NSScreen screens] objectAtIndex:0];
-  gdk_screen_set_resolution (screen,
-                             72.0 * [nsscreen userSpaceScaleFactor]);
+  _gdk_screen_set_resolution (screen,
+                              72.0 * [nsscreen userSpaceScaleFactor]);
 
   gdk_quartz_screen_calculate_layout (quartz_screen);
 
diff --git a/gdk/wayland/gdkscreen-wayland.c b/gdk/wayland/gdkscreen-wayland.c
index 4cbc51e..baa1bc8 100644
--- a/gdk/wayland/gdkscreen-wayland.c
+++ b/gdk/wayland/gdkscreen-wayland.c
@@ -477,7 +477,22 @@ update_xft_settings (GdkScreen *screen)
 
   if (screen_wayland->xft_settings.dpi != xft_settings.dpi)
     {
+      double dpi = xft_settings.dpi / 1024.;
+      const char *scale_env;
+      double scale;
+
       screen_wayland->xft_settings.dpi = xft_settings.dpi;
+
+      scale_env = g_getenv ("GDK_DPI_SCALE");
+      if (scale_env)
+        {
+          scale = g_ascii_strtod (scale_env, NULL);
+          if (scale != 0 && dpi > 0)
+            dpi *= scale;
+        }
+
+      _gdk_screen_set_resolution (screen, dpi);
+
       notify_setting (screen, "gtk-xft-dpi");
     }
 }
diff --git a/gdk/x11/xsettings-client.c b/gdk/x11/xsettings-client.c
index 87b4add..f807e52 100644
--- a/gdk/x11/xsettings-client.c
+++ b/gdk/x11/xsettings-client.c
@@ -402,6 +402,8 @@ static void
 read_settings (GdkX11Screen *x11_screen,
                gboolean      do_notify)
 {
+  GdkScreen *screen = GDK_SCREEN (x11_screen);
+
   Atom type;
   int format;
   unsigned long n_items;
@@ -466,6 +468,41 @@ read_settings (GdkX11Screen *x11_screen,
     g_hash_table_unref (old_list);
 
   g_value_init (&value, G_TYPE_INT);
+
+  if (!screen->resolution_set)
+    {
+      /* This code is duplicated with gtksettings.c:settings_update_resolution().
+       * The update of the screen resolution needs to happen immediately when
+       * gdk_x11_display_set_window_scale() is called, and not wait for events
+       * to be processed, so we can't always handling it in gtksettings.c.
+       * But we can't always handle it here because the DPI can be set through
+       * GtkSettings, which we don't have access to.
+       */
+      int dpi_int = 0;
+      double dpi;
+      const char *scale_env;
+      double scale;
+
+      if (gdk_screen_get_setting (GDK_SCREEN (x11_screen),
+                                  "gtk-xft-dpi", &value))
+        dpi_int = g_value_get_int (&value);
+
+      if (dpi_int > 0)
+        dpi = dpi_int / 1024.;
+      else
+        dpi = -1.;
+
+      scale_env = g_getenv ("GDK_DPI_SCALE");
+      if (scale_env)
+        {
+          scale = g_ascii_strtod (scale_env, NULL);
+          if (scale != 0 && dpi > 0)
+            dpi *= scale;
+        }
+
+      _gdk_screen_set_resolution (screen, dpi);
+    }
+
   if (!x11_screen->fixed_window_scale &&
       gdk_screen_get_setting (GDK_SCREEN (x11_screen),
                              "gdk-window-scaling-factor", &value))
diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c
index 64912ce..7549c8d 100644
--- a/gtk/gtksettings.c
+++ b/gtk/gtksettings.c
@@ -2944,24 +2944,31 @@ settings_update_resolution (GtkSettings *settings)
   const char *scale_env;
   double scale;
 
-  g_object_get (settings,
-                "gtk-xft-dpi", &dpi_int,
-                NULL);
+  /* We handle this here in the case that the dpi was set on the GtkSettings
+   * object by the application. Other cases are handled in
+   * xsettings-client.c:read-settings(). See comment there for the rationale.
+   */
+  if (priv->property_values[PROP_XFT_DPI - 1].source == GTK_SETTINGS_SOURCE_APPLICATION)
+    {
+      g_object_get (settings,
+                    "gtk-xft-dpi", &dpi_int,
+                    NULL);
 
-  if (dpi_int > 0)
-    dpi = dpi_int / 1024.;
-  else
-    dpi = -1.;
+      if (dpi_int > 0)
+        dpi = dpi_int / 1024.;
+      else
+        dpi = -1.;
 
-  scale_env = g_getenv ("GDK_DPI_SCALE");
-  if (scale_env)
-    {
-      scale = g_ascii_strtod (scale_env, NULL);
-      if (scale != 0 && dpi > 0)
-       dpi *= scale;
-    }
+      scale_env = g_getenv ("GDK_DPI_SCALE");
+      if (scale_env)
+        {
+          scale = g_ascii_strtod (scale_env, NULL);
+          if (scale != 0 && dpi > 0)
+            dpi *= scale;
+        }
 
-  gdk_screen_set_resolution (priv->screen, dpi);
+      gdk_screen_set_resolution (priv->screen, dpi);
+    }
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]