[gtk+/resolution-independence: 3/24] add core resolution independence code



commit c07c77a489a9dce56209fbda071d74c87036fc8c
Author: David Zeuthen <davidz redhat com>
Date:   Tue Aug 12 17:31:49 2008 -0400

    add core resolution independence code
    
    gtksize.[ch]:
     - core resolution independence code
    
    gtkwidget.[ch]:
     - use monitor number to get the Pango context
     - new ::unit-changed signal
     - port some style properties to GtkSize
     - make style getters automatically convert to units
     - provide unit preserving getters (object + style properties)
    
    gtkwindow.[ch]:
     - port some object properties to GtkSize
     - propagate ::unit-changed from GtkSettings to all widgets
     - try and guess the monitor and use it's units in gtk_window_show()
    
    gtksettings.c:
     - provide a new signal ::unit-changed. The code in gtksize.c will
       emit this signal; GtkSettings is just a convenient placeholder
       for the signal.
    
    add minimum and maximum to param spec constructors
    
    use min/max for GtkWidget
    
    use min/max for GtkWindow
    
    fixed gtkwidget.c
    
    fixed gtkwindow.c
    
    fixed gtksize.c
---
 docs/reference/gtk/Makefile.am                     |    5 +-
 docs/reference/gtk/gtk-docs.sgml                   |    1 +
 docs/reference/gtk/gtk-sections.txt                |   36 +
 .../gtk/images/gtk-ri-file-chooser-size-12.png     |  Bin 0 -> 61158 bytes
 .../gtk/images/gtk-ri-file-chooser-size-24.png     |  Bin 0 -> 138583 bytes
 .../gtk/images/gtk-ri-file-chooser-size-6.png      |  Bin 0 -> 26843 bytes
 gtk/Makefile.am                                    |    2 +
 gtk/gtk.h                                          |    1 +
 gtk/gtk.symbols                                    |   33 +
 gtk/gtkobject.h                                    |    1 +
 gtk/gtksettings.c                                  |   26 +
 gtk/gtksize.c                                      | 1140 ++++++++++++++++++++
 gtk/gtksize.h                                      |  180 +++
 gtk/gtkwidget.c                                    |  640 ++++++++++--
 gtk/gtkwidget.h                                    |   40 +-
 gtk/gtkwindow.c                                    |  149 ++-
 gtk/gtkwindow.h                                    |    7 +-
 17 files changed, 2154 insertions(+), 107 deletions(-)

diff --git a/docs/reference/gtk/Makefile.am b/docs/reference/gtk/Makefile.am
index 0c5e059..5d3d364 100644
--- a/docs/reference/gtk/Makefile.am
+++ b/docs/reference/gtk/Makefile.am
@@ -344,7 +344,10 @@ HTML_IMAGES = \
 	$(srcdir)/images/layout-rlbt.png				\
 	$(srcdir)/images/layout-rltb.png				\
 	$(srcdir)/images/layout-tblr.png				\
-	$(srcdir)/images/layout-tbrl.png
+	$(srcdir)/images/layout-tbrl.png				\
+	$(srcdir)/images/gtk-ri-file-chooser-size-6.png			\
+	$(srcdir)/images/gtk-ri-file-chooser-size-12.png		\
+	$(srcdir)/images/gtk-ri-file-chooser-size-24.png
 
 # Extra options to supply to gtkdoc-fixref
 FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html \
diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml
index 9701510..c0296e3 100644
--- a/docs/reference/gtk/gtk-docs.sgml
+++ b/docs/reference/gtk/gtk-docs.sgml
@@ -126,6 +126,7 @@ that is, GUI components such as #GtkButton or #GtkTextView.
     <xi:include href="xml/gtktypeutils.xml" />
     <xi:include href="xml/gtktesting.xml" />
     <xi:include href="xml/filesystem.xml" />
+    <xi:include href="xml/gtksize.xml" />
   </part>
 
   <part id="gtkobjects">
diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt
index 5392b75..6d0bbde 100644
--- a/docs/reference/gtk/gtk-sections.txt
+++ b/docs/reference/gtk/gtk-sections.txt
@@ -5494,6 +5494,14 @@ gtk_widget_trigger_tooltip_query
 gtk_widget_get_snapshot
 gtk_widget_get_window
 gtk_widget_get_monitor_num
+gtk_widget_get_size_request_unit
+gtk_widget_size_to_pixel
+gtk_widget_size_to_pixel_double
+gtk_widget_style_get_property_unit
+gtk_widget_style_get_unit_valist
+gtk_widget_style_get_unit
+gtk_widget_get_unit_valist
+gtk_widget_get_unit
 <SUBSECTION>
 gtk_requisition_copy
 gtk_requisition_free
@@ -5580,6 +5588,7 @@ gtk_window_get_deletable
 gtk_window_get_default_icon_list
 gtk_window_get_default_icon_name
 gtk_window_get_default_size
+gtk_window_get_default_size_unit
 gtk_window_get_destroy_with_parent
 gtk_window_get_frame_dimensions
 gtk_window_get_has_frame
@@ -6996,4 +7005,31 @@ GTK_TYPE_ORIENTABLE
 
 <SUBSECTION Private>
 gtk_orientable_get_type
+
+<SECTION>
+<TITLE>Units</TITLE>
+<FILE>gtksize</FILE>
+GtkSize
+GtkUSize
+GtkSizeUnit
+gtk_size_em
+gtk_size_mm
+gtk_size_get_em
+gtk_size_get_mm
+GTK_SIZE_ONE_TWELFTH_EM
+GTK_SIZE_MAXPIXEL
+GTK_SIZE_MINPIXEL
+gtk_size_get_unit
+gtk_size_to_pixel
+gtk_size_to_pixel_double
+gtk_size_to_string
+gtk_param_spec_size
+gtk_value_set_size
+gtk_value_get_size
+gtk_value_size_skip_conversion
+gtk_param_spec_usize
+gtk_value_set_usize
+gtk_value_get_usize
+gtk_value_usize_skip_conversion
+gtk_enable_resolution_independence
 </SECTION>
diff --git a/docs/reference/gtk/images/gtk-ri-file-chooser-size-12.png b/docs/reference/gtk/images/gtk-ri-file-chooser-size-12.png
new file mode 100644
index 0000000..7d0de82
Binary files /dev/null and b/docs/reference/gtk/images/gtk-ri-file-chooser-size-12.png differ
diff --git a/docs/reference/gtk/images/gtk-ri-file-chooser-size-24.png b/docs/reference/gtk/images/gtk-ri-file-chooser-size-24.png
new file mode 100644
index 0000000..fe3e198
Binary files /dev/null and b/docs/reference/gtk/images/gtk-ri-file-chooser-size-24.png differ
diff --git a/docs/reference/gtk/images/gtk-ri-file-chooser-size-6.png b/docs/reference/gtk/images/gtk-ri-file-chooser-size-6.png
new file mode 100644
index 0000000..d5ae68a
Binary files /dev/null and b/docs/reference/gtk/images/gtk-ri-file-chooser-size-6.png differ
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 2339a86..24198fc 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -276,6 +276,7 @@ gtk_public_h_sources =          \
 	gtkseparatortoolitem.h	\
 	gtkshow.h		\
 	gtksettings.h		\
+	gtksize.h		\
 	gtksizegroup.h		\
 	gtksocket.h		\
 	gtkspinbutton.h		\
@@ -539,6 +540,7 @@ gtk_base_c_sources =            \
 	gtkseparatormenuitem.c	\
 	gtkseparatortoolitem.c	\
 	gtksettings.c		\
+	gtksize.c		\
 	gtksizegroup.c		\
 	gtkshow.c		\
 	gtksocket.c		\
diff --git a/gtk/gtk.h b/gtk/gtk.h
index 7b9b765..b6ba4d5 100644
--- a/gtk/gtk.h
+++ b/gtk/gtk.h
@@ -163,6 +163,7 @@
 #include <gtk/gtkseparatortoolitem.h>
 #include <gtk/gtksettings.h>
 #include <gtk/gtkshow.h>
+#include <gtk/gtksize.h>
 #include <gtk/gtksizegroup.h>
 #include <gtk/gtksocket.h>
 #include <gtk/gtkspinbutton.h>
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 7d2ddc1..3d2bbd8 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -5019,6 +5019,14 @@ gtk_widget_unparent
 gtk_widget_unrealize
 gtk_widget_get_window
 gtk_widget_get_monitor_num
+gtk_widget_get_size_request_unit
+gtk_widget_size_to_pixel
+gtk_widget_size_to_pixel_double
+gtk_widget_style_get_property_unit
+gtk_widget_style_get_unit_valist
+gtk_widget_style_get_unit
+gtk_widget_get_unit_valist
+gtk_widget_get_unit
 #endif
 #endif
 
@@ -5041,6 +5049,7 @@ gtk_window_get_default_widget
 gtk_window_get_default_icon_list
 gtk_window_get_default_icon_name
 gtk_window_get_default_size
+gtk_window_get_default_size_unit
 gtk_window_get_destroy_with_parent
 gtk_window_get_focus
 gtk_window_get_focus_on_map
@@ -5155,6 +5164,30 @@ gtk_win32_embed_widget_get_type G_GNUC_CONST
 #endif
 #endif
 
+#if IN_HEADER(__GTK_SIZE_H__)
+#if IN_FILE(__GTK_SIZE_C__)
+gtk_enable_resolution_independence
+gtk_size_em
+gtk_size_mm
+gtk_size_get_unit
+gtk_size_get_em
+gtk_size_get_mm
+gtk_size_to_pixel
+gtk_size_to_pixel_double
+gtk_size_to_string
+gtk_param_size_get_type G_GNUC_CONST
+gtk_param_spec_size
+gtk_value_set_size
+gtk_value_get_size
+gtk_value_size_skip_conversion
+gtk_param_usize_get_type G_GNUC_CONST
+gtk_param_spec_usize
+gtk_value_set_usize
+gtk_value_get_usize
+gtk_value_usize_skip_conversion
+#endif
+#endif
+
 #ifdef INCLUDE_VARIABLES
 gtk_binary_age
 gtk_interface_age
diff --git a/gtk/gtkobject.h b/gtk/gtkobject.h
index de6616b..71d36df 100644
--- a/gtk/gtkobject.h
+++ b/gtk/gtkobject.h
@@ -33,6 +33,7 @@
 
 
 #include <gdkconfig.h>
+#include <gtk/gtksize.h>
 #include <gtk/gtkenums.h>
 #include <gtk/gtktypeutils.h>
 #include <gtk/gtkdebug.h>
diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c
index c3c1a78..e98944e 100644
--- a/gtk/gtksettings.c
+++ b/gtk/gtksettings.c
@@ -41,6 +41,13 @@
 
 typedef struct _GtkSettingsValuePrivate GtkSettingsValuePrivate;
 
+enum {
+  UNIT_CHANGED_SIGNAL,
+  LAST_SIGNAL,
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
 typedef enum
 {
   GTK_SETTINGS_SOURCE_DEFAULT,
@@ -961,6 +968,25 @@ gtk_settings_class_init (GtkSettingsClass *class)
                                                                    GTK_PARAM_READWRITE),
                                              NULL);
   g_assert (result == PROP_ENABLE_TOOLTIPS);
+
+  /**
+   * GtkSettings::unit-changed:
+   * @monitor_num: the monitor number on which the unit changed.
+   *
+   * The ::unit-changed signal is emitted when unit conversion factors
+   * on a screen change.
+   *
+   * Since: 2.14
+   */
+  signals[UNIT_CHANGED_SIGNAL] =
+    g_signal_new (I_("unit-changed"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, /* gah, no room in GtkSettings class */
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__INT,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_INT);
 }
 
 static void
diff --git a/gtk/gtksize.c b/gtk/gtksize.c
new file mode 100644
index 0000000..d079fa2
--- /dev/null
+++ b/gtk/gtksize.c
@@ -0,0 +1,1140 @@
+/* GTK - The GIMP Toolkit
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <math.h>
+#include "gtk.h"
+#include "gtksize.h"
+#include "gtkintl.h"
+#include "gtkprivate.h"
+#include "gtkbuildable.h"
+#include "gtkalias.h"
+
+/**
+ * SECTION:gtksize
+ * @short_description: Resolution independent rendering
+ *
+ * The #GtkSize type is used to implement resolution independent
+ * rendering in applications. This involves designing the application
+ * to use pixel-independent units. By using high bits in a #gint, the
+ * standard integer type is overloaded to be able to carry information
+ * about the unit; for example pixels or <ulink
+ * url="http://en.wikipedia.org/wiki/Em_(typography)">em</ulink>'s. At
+ * run-time, depending on physical characteristics of the output
+ * device and user preferences, a size specified in units can be
+ * converted to pixels. Here is a screenshot of #GtkFileChooserDialog
+ * rendered at 1 em equaling 6 pixels
+ *
+ * <inlinegraphic fileref="gtk-ri-file-chooser-size-6.png" format="PNG"/>
+ *
+ * and for 1 em equaling 12 pixels
+ *
+ * <inlinegraphic fileref="gtk-ri-file-chooser-size-12.png" format="PNG"/>
+ *
+ * and finally for 1 em equaling 24 pixels
+ *
+ * <inlinegraphic fileref="gtk-ri-file-chooser-size-24.png" format="PNG"/>
+ *
+ * To specify a pixel size, simply treat #GtkSize as an integer:
+ * <programlisting>
+ * GtkSize size;
+ * size = 42;
+ * </programlisting>
+ * To specify an em:
+ * <programlisting>
+ * GtkSize size;
+ * size = gtk_size_em (2.5);
+ * </programlisting>
+ * To specify a millimeter:
+ * <programlisting>
+ * GtkSize size;
+ * size = gtk_size_mm (25.4); // one inch
+ * </programlisting>
+ * Note that using millimeter or other physical units in user
+ * interfaces is mostly always a bad idea; use em instead as the UI
+ * elements will the scale correctly with the font. One notable
+ * exception to this rule is interfaces designed for finger use where
+ * it is desirable that a button matches the size of e.g. a
+ * fingertip.
+ *
+ * Internally, #GtkSize stores ems and millimeters using fixed precision; as
+ * such floating point numbers can be passed to the gtk_size_em() and
+ * gtk_size_mm() functions. Use gtk_size_get_unit(), gtk_size_get_em()
+ * and gtk_size_get_mm() to inspect a #GtkSize.
+ *
+ * To convert a #GtkSize to pixels simply use gtk_size_to_pixel() (or
+ * gtk_size_to_pixel_double() to get a floating point number). As the
+ * monitors attached to a system may have different resolution, the
+ * pixel size depends on physical characteristics of the output device
+ * as well as user preferences. Therefore, a #GdkScreen and monitor
+ * number will need to be passed in.
+ *
+ * The #GtkSize type is backwards compatible with #gint and can be
+ * used as a drop-in replacement assuming the range of values passed
+ * in doesn't exceed #GTK_SIZE_MAXPIXEL (roughly a quarter of a
+ * billion pixels). Also, #GtkSize is future proof insofar that it can
+ * be extended in the future to store other kinds of sizes than em and
+ * mm.
+ *
+ * Note that integer arithmetrics cannot be used on #GtkSize, instead
+ * convert all arguments to pixel sizes
+ * <programlisting>
+ * GtkSize border_width = gtk_size_em (0.5);
+ * GtkSize button_width = gtk_size_em (10);
+ * gint num_buttons = 5;
+ * gint total_width;
+ *
+ * // illegal
+ * total_width = gtk_size_to_pixel (2 * border_width + num_buttons * button_width);
+ *
+ * // legal
+ * total_width = 2 * gtk_size_to_pixel (screen, monitor_num, border_width) +
+ *               num_buttons * gtk_size_to_pixel (screen, monitor_num, button_width);
+ *
+ * // legal
+ * total_width = round (2.0 * gtk_size_to_pixel_double (screen, monitor_num, border_width) +
+ *                      num_buttons * gtk_size_to_pixel_double (screen, monitor_num, button_width));
+ * </programlisting>
+ * The latter form is perfectly legal though seldom used as it's often
+ * desirable to align UI elements (except text rendering) on a pixel
+ * grid.
+ *
+ * #GtkUSize is #GtkSize's unsigned companion. The construction and
+ * conversion functions for #GtkSize applies to #GtkUSize as well.
+ *
+ * <refsect2>
+ *   <title>Porting Applications</title>
+ *   Making an application resolution independent involves more than
+ *   just calling gtk_enable_resolution_independence() before
+ *   gtk_init() - a rough checklist includes
+ *   <itemizedlist>
+ *     <listitem>
+ *       Make sure your application (and any library being used) is not
+ *       accessing structure fields in widgets directly - use accessor
+ *       functions instead. This is because, when resolution
+ *       independent rendering is enabled, a widget may store the
+ *       #GtkSize directly instead of a @gint. Note that some classes
+ *       still store the pixel values (e.g. #GtkContainer's
+ *       <literal>border_width</literal>) - see the header files for
+ *       details; if the widget stores a #GtkSize instead of a #gint
+ *       the header file will reflect that. However, never rely on
+ *       this (it may change in the future), use accessor functions
+ *       instead.
+ *    </listitem>
+ *    <listitem>
+ *       Note that all accessor functions (such as
+ *       gtk_box_get_spacing()) will still return pixel values. Use
+ *       the companion unit getter (e.g. gtk_box_get_spacing_unit())
+ *       instead if you want the #GtkSize. Similary for properties
+ *       resp. style properties, g_object_get()
+ *       resp. gtk_widget_style_get() will still return pixel sizes. Use
+ *       gtk_widget_get_unit() and gtk_widget_style_get_unit() to
+ *       preserve the unit.
+ *    </listitem>
+ *    <listitem>
+ *      The application should never use pixel values, use
+ *      gtk_size_em() instead. If the application was designed for a
+ *      display with a 10 point font at 96 DPI (as most applications
+ *      are), simply use the GTK_SIZE_ONE_TWELFTH_EM() macro passing
+ *      in the pixel size. Note that #GtkBuilder now understands
+ *      <literal>em</literal> and <literal>mm</literal> meaning that
+ *      it's valid to use e.g. <literal>20.5em</literal> or
+ *      <literal>35.2mm</literal> instead of pixel sizes.
+ *    </listitem>
+ *    <listitem>
+ *       Keep in mind that the factors used for translating from
+ *       #GtkSize to pixels may change at run-time. For example, the
+ *       user may move a window onto a monitor with a different
+ *       DPI. Subclasses of #GtkWidget can hook into the
+ *       #GtkWidget::unit-changed signal (remember to chain up if
+ *       setting the class function) to recompute pixel values or
+ *       update #GdkPixbuf objects. Dialogs or windows can also
+ *       subscribe to this signal to do the same. See
+ *       <literal>assistant.c</literal> in gtk-demo for an example.
+ *    </listitem>
+ *    <listitem>
+ *      Test your application. Try changing the DPI and font sizes on
+ *      the fly. Use a multi monitor setup where the monitors have
+ *      different DPI's. Ensure that your application works as
+ *      intended.
+ *    </listitem>
+ *   </itemizedlist>
+ * </refsect2>
+ * <refsect2>
+ *   <title>Porting Theme Engines</title>
+ *   Theme engines overriding gtk_style_render_icon() need to take the
+ *   monitor into account when determining the pixel size for the
+ *   given #GtkIconSize. Use
+ *   gtk_icon_size_lookup_for_settings_for_monitor() instead of
+ *   gtk_icon_size_lookup_for_settings() with
+ *   <literal>monitor_num</literal> obtained via
+ *   gtk_widget_get_monitor_num(). TODO: need input from theme engine
+ *   authors here.
+ * </refsect2>
+ * <refsect2>
+ *   <title>Porting Themes</title>
+ *   To specify ems use the exclamation mark as a prefix,
+ *   e.g. <literal>!0.5</literal> and <literal>!2</literal> means
+ *   resp. 0.5 and 2 ems.
+ * </refsect2>
+ */
+
+/*
+ * Storage format:
+ *
+ *  10987654321098765432109876543210
+ *  SXXX
+ *
+ * Bits 28, 29 and 30 holds the unit type and is from the #GtkSizeUnit
+ * enumeration. Not all of bits 28, 29, 30 can be set at once since it
+ * would look like an unsigned integer. This gives 7 different units.
+ *
+ * Bit 31 holds the sign.
+ *
+ * Bit 0 through 27 is used for storing the value. This leaves the
+ * range [-268,435,456, 268,435,456] to be used for pixel sizes.
+ *
+ * For em, we store the value times EM_PRECISION and for mm we store
+ * the value times MM_PRECISION. This allows people to use non-integer
+ * units.
+ */
+
+/* the amount of precision we use for storing ems */
+#define EM_PRECISION 120
+
+/* the amount of precision we use for storing mm's */
+#define MM_PRECISION 100
+
+/* if we can't determine the font, fall back to this size */
+#define FALLBACK_FONT_SIZE_POINTS 12
+
+/* if we can't determine the DPI, fall back to this value */
+#define FALLBACK_DPI 96
+
+typedef struct _GtkParamSpecSize GtkParamSpecSize;
+struct _GtkParamSpecSize
+{
+  GParamSpecInt parent_instance;
+};
+
+typedef struct _GtkParamSpecUSize GtkParamSpecUSize;
+struct _GtkParamSpecUSize
+{
+  GParamSpecUInt parent_instance;
+};
+
+static gboolean units_enabled = FALSE;
+static gboolean application_wants_to_use_units = FALSE;
+static gboolean have_checked = FALSE;
+
+static void
+check_if_resolution_independence_is_enabled (void)
+{
+  const char *s;
+
+  if (G_LIKELY (have_checked))
+    return;
+
+  units_enabled = FALSE;
+
+  s = g_getenv ("GTK_RESOLUTION_INDEPENDENCE_FORCE");
+  if (s != NULL)
+    {
+      if (g_ascii_strcasecmp (s, "disabled") == 0 || g_ascii_strcasecmp (s, "0") == 0)
+        {
+          goto out;
+        }
+
+      if (g_ascii_strcasecmp (s, "enabled") == 0 || g_ascii_strcasecmp (s, "1") == 0)
+        {
+          units_enabled = TRUE;
+          goto use_units;
+        }
+    }
+
+  if (!application_wants_to_use_units)
+    goto out;
+
+ use_units:
+
+  units_enabled = TRUE;
+
+ out:
+  have_checked = TRUE;
+}
+
+static GHashTable *screen_settings_hash = NULL;
+
+typedef struct {
+  gdouble resolution;
+  gdouble pixels_per_em;
+  gdouble pixels_per_mm;
+} MonitorSettings;
+
+typedef struct {
+  GdkScreen *screen;
+  gboolean needs_refresh;
+
+  gint num_monitors;
+  MonitorSettings *monitor_settings;
+} ScreenSettings;
+
+static void
+screen_settings_free (ScreenSettings *screen_settings)
+{
+  g_free (screen_settings->monitor_settings);
+  g_free (screen_settings);
+}
+
+static void
+screen_settings_update (ScreenSettings *screen_settings, gboolean emit_signal)
+{
+  int n;
+  char *font_name;
+  gdouble font_size;
+  GtkSettings *settings;
+  MonitorSettings *old_monitor_settings;
+  gint old_num_monitors;
+
+  /* fall back to font size */
+  font_size = FALLBACK_FONT_SIZE_POINTS;
+
+  settings = gtk_settings_get_for_screen (screen_settings->screen);
+  if (settings != NULL)
+    {
+      g_object_get (settings,
+                    "gtk-font-name", &font_name,
+                    NULL);
+      if (font_name != NULL)
+        {
+          PangoFontDescription *font_desc;
+          font_desc = pango_font_description_from_string (font_name);
+          if (font_desc != NULL)
+            {
+              gint pango_size;
+              gboolean is_absolute;
+              pango_size = pango_font_description_get_size (font_desc);
+              is_absolute = pango_font_description_get_size_is_absolute (font_desc);
+              if (!is_absolute)
+                {
+                  font_size = ((gdouble) pango_size) / PANGO_SCALE;
+                }
+              /* TODO: handle the case where is_absolute is TRUE */
+              pango_font_description_free (font_desc);
+            }
+        }
+    }
+
+  old_num_monitors = screen_settings->num_monitors;
+  old_monitor_settings = screen_settings->monitor_settings;
+
+  screen_settings->num_monitors = gdk_screen_get_n_monitors (screen_settings->screen);
+  screen_settings->monitor_settings = g_new0 (MonitorSettings, screen_settings->num_monitors);
+  for (n = 0; n < screen_settings->num_monitors; n++)
+    {
+      MonitorSettings *monitor_settings = &(screen_settings->monitor_settings[n]);
+
+      monitor_settings->resolution = gdk_screen_get_resolution_for_monitor (screen_settings->screen, n);
+      if (monitor_settings->resolution < 0)
+        monitor_settings->resolution = FALLBACK_DPI; /* fall back */
+
+      /* 10 points at 96 DPI is 12 pixels; convert accordingly */
+      monitor_settings->pixels_per_em = 1.2 * font_size * monitor_settings->resolution / 96.0;
+
+      /* 1 inch ~ 25.4 mm */
+      monitor_settings->pixels_per_mm = monitor_settings->resolution / 25.4;
+
+#if 0
+      /* debug spew; useful for debugging */
+      g_debug ("using 1em -> %g pixels, 1mm -> %g pixels for monitor %d of screen %p (resolution %g DPI, font '%s')\n",
+               monitor_settings->pixels_per_em,
+               monitor_settings->pixels_per_mm,
+               n,
+               screen_settings->screen,
+               monitor_settings->resolution,
+               font_name != NULL ? font_name : "<unknown>");
+#endif
+    }
+
+  screen_settings->needs_refresh = FALSE;
+
+  /* emit change signals only have the whole ScreenSettings structure have been updated */
+  if (emit_signal && old_monitor_settings != NULL && settings != NULL)
+    {
+      gboolean have_invalidated_icon_caches = FALSE;
+
+      for (n = 0; n < screen_settings->num_monitors && n < old_num_monitors; n++)
+        {
+          MonitorSettings *monitor_settings = &(screen_settings->monitor_settings[n]);
+
+          if ((fabs (monitor_settings->pixels_per_em - (old_monitor_settings[n]).pixels_per_em) > 0.01) ||
+              (fabs (monitor_settings->pixels_per_mm - (old_monitor_settings[n]).pixels_per_mm) > 0.01))
+            {
+              if (!have_invalidated_icon_caches)
+                {
+                  have_invalidated_icon_caches = TRUE;
+                  _gtk_icon_set_invalidate_caches ();
+                }
+              g_signal_emit_by_name (settings, "unit-changed", n);
+            }
+        }
+    }
+
+  g_free (old_monitor_settings);
+
+  g_free (font_name);
+}
+
+static void
+invalidate_screen_settings_for_screen (GdkScreen *screen,
+                                        ScreenSettings *screen_settings,
+                                        GdkScreen *for_screen)
+{
+  if (screen == for_screen)
+    screen_settings->needs_refresh = TRUE;
+}
+
+void
+_gtk_size_invalidate_caches_for_screen (GdkScreen *screen)
+{
+  g_hash_table_foreach (screen_settings_hash,
+                        (GHFunc) invalidate_screen_settings_for_screen,
+                        screen);
+}
+
+static void monitors_changed  (GdkScreen    *screen,
+                               gpointer      user_data);
+
+static void dpi_changed       (GtkSettings  *settings,
+                               GParamSpec   *spec,
+                               gpointer      user_data);
+
+static void font_name_changed (GtkSettings  *settings,
+                               GParamSpec   *spec,
+                               gpointer      user_data);
+
+static void
+screen_settings_screen_went_away (gpointer user_data, GObject *where_the_object_was)
+{
+  g_hash_table_remove (screen_settings_hash, where_the_object_was);
+}
+
+/* this will never return #NULL */
+static ScreenSettings *
+screen_settings_get (GdkScreen *screen)
+{
+  GtkSettings *settings;
+  ScreenSettings *screen_settings;
+
+  if (G_UNLIKELY (screen_settings_hash == NULL))
+    {
+      screen_settings_hash = g_hash_table_new_full (g_direct_hash,
+                                                   g_direct_equal,
+                                                   NULL,
+                                                   (GDestroyNotify) screen_settings_free);
+    }
+
+  if (screen == NULL)
+    screen = gdk_screen_get_default ();
+
+  /* TODO: verify screen is a GdkScreen */
+
+  screen_settings = g_hash_table_lookup (screen_settings_hash, screen);
+
+  if (G_LIKELY (screen_settings != NULL))
+    {
+      if (G_UNLIKELY (screen_settings->needs_refresh))
+        screen_settings_update (screen_settings, FALSE);
+      goto out;
+    }
+
+  screen_settings = g_new0 (ScreenSettings, 1);
+  screen_settings->screen = screen;
+  screen_settings_update (screen_settings, FALSE);
+
+  g_hash_table_insert (screen_settings_hash, (gpointer) screen, screen_settings);
+  g_object_weak_ref (G_OBJECT (screen), screen_settings_screen_went_away, NULL);
+
+  g_signal_connect (screen,
+                    "monitors-changed",
+                    G_CALLBACK (monitors_changed),
+                    NULL);
+
+  settings = gtk_settings_get_for_screen (screen);
+  if (settings != NULL)
+    {
+      g_signal_connect (settings,
+                        "notify::gtk-font-name",
+                        G_CALLBACK (font_name_changed),
+                        NULL);
+
+      /* right now monitors-changed doesn't fire on dpi changes;
+       * hook up to gtk-xft-dpi on GtkSettings for now
+       */
+      g_signal_connect (settings,
+                        "notify::gtk-xft-dpi",
+                        G_CALLBACK (dpi_changed),
+                        NULL);
+    }
+
+ out:
+  return screen_settings;
+}
+
+static void
+monitors_changed (GdkScreen    *screen,
+                  gpointer      user_data)
+{
+  ScreenSettings *screen_settings;
+
+  screen_settings = screen_settings_get (screen);
+  if (screen_settings != NULL)
+    screen_settings_update (screen_settings, TRUE);
+}
+
+static void
+dpi_changed (GtkSettings  *settings,
+             GParamSpec   *spec,
+             gpointer      user_data)
+{
+  ScreenSettings *screen_settings;
+
+  screen_settings = screen_settings_get (settings->screen);
+  if (screen_settings != NULL)
+    screen_settings_update (screen_settings, TRUE);
+}
+
+
+static void
+font_name_changed (GtkSettings  *settings,
+                   GParamSpec   *spec,
+                   gpointer      user_data)
+{
+  ScreenSettings *screen_settings;
+
+  screen_settings = screen_settings_get (settings->screen);
+  if (screen_settings != NULL)
+    screen_settings_update (screen_settings, TRUE);
+}
+
+
+
+static void
+screen_settings_get_pixel_conversion_factors (GdkScreen *screen,
+                                              gint       monitor_num,
+                                              gdouble   *pixels_per_em,
+                                              gdouble   *pixels_per_mm)
+{
+  ScreenSettings *s;
+
+  /* -1 means "use default".. that's 0 for now */
+  if (monitor_num < 0)
+    monitor_num = 0;
+
+  s = screen_settings_get (screen);
+  if (monitor_num >= s->num_monitors)
+    {
+      g_warning ("monitor number %d out of range for screen (screen has %d monitors)",
+                 monitor_num, s->num_monitors);
+      monitor_num = 0;
+    }
+
+  *pixels_per_em = s->monitor_settings[monitor_num].pixels_per_em;
+  *pixels_per_mm = s->monitor_settings[monitor_num].pixels_per_mm;
+}
+
+
+/**
+ * gtk_enable_resolution_independence:
+ *
+ * Resolution independent rendering is an opt-in feature; applications
+ * need to enable it by default by calling this function before
+ * invoking gtk_init().
+ *
+ * Since: 2.14
+ **/
+void
+gtk_enable_resolution_independence (void)
+{
+  application_wants_to_use_units = TRUE;
+}
+
+/**
+ * gtk_size_get_unit:
+ * @size: A #GtkSize or #GtkUSize value
+ *
+ * Gets the unit for @size.
+ *
+ * Returns: a value from the #GtkSizeUnit enumeration
+ **/
+GtkSizeUnit
+gtk_size_get_unit (GtkSize size)
+{
+  if (abs (size) <= ((1<<28) - 1))
+    return GTK_SIZE_UNIT_PIXEL;
+
+  return (size >> 28) & 0x07;
+}
+
+/**
+ * gtk_size_em:
+ * @em: Size in em
+ *
+ * This function returns @em as a #GtkSize. If resolution independent
+ * rendering is not enabled (see
+ * gtk_enable_resolution_independence()), then 12 * @em is
+ * returned as a pixel value instead.
+ *
+ * Returns: a #GtkSize
+ *
+ * Since: 2.14
+ */
+GtkSize
+gtk_size_em (gdouble em)
+{
+  check_if_resolution_independence_is_enabled ();
+
+  /* if units are not enabled; assume 1em == 12 pixels */
+  if (G_LIKELY (!units_enabled))
+    return (gint) (em*12.0 + 0.5);
+
+  if (em >= 0)
+    return ((gint) (EM_PRECISION * em)) | (GTK_SIZE_UNIT_EM<<28);
+  else
+    return ((gint) (EM_PRECISION * (-em))) | (GTK_SIZE_UNIT_EM<<28) | (1<<31);
+}
+
+/**
+ * gtk_size_mm:
+ * @mm: Size in mm
+ *
+ * This function returns @mm as a #GtkSize. If resolution independent
+ * rendering is not enabled (see
+ * gtk_enable_resolution_independence()), then 4 * @mm is returned as
+ * a pixel value instead.
+ *
+ * Returns: a #GtkSize
+ *
+ * Since: 2.14
+ **/
+GtkSize
+gtk_size_mm (gdouble mm)
+{
+  check_if_resolution_independence_is_enabled ();
+
+  if (G_LIKELY (!units_enabled))
+    return (gint) (mm*MM_PRECISION + 0.5);
+
+  /* right now hardcode 1mm == 1 pixel */
+
+  if (mm >= 0)
+    return ((gint) (MM_PRECISION * mm)) | (GTK_SIZE_UNIT_MM<<28);
+  else
+    return ((gint) (MM_PRECISION * (-mm))) | (GTK_SIZE_UNIT_MM<<28) | (1<<31);
+}
+
+/**
+ * gtk_size_get_em:
+ * @size: a #GtkSize of type #GTK_SIZE_UNIT_EM
+ *
+ * Gets the number of ems stored in @size. Returns -1 if the unit of
+ * @size is not @GTK_SIZE_UNIT_EM.
+ *
+ * Returns: a #gdouble
+ *
+ * Since: 2.14
+ **/
+gdouble
+gtk_size_get_em (GtkSize size)
+{
+  g_return_val_if_fail (gtk_size_get_unit (size) == GTK_SIZE_UNIT_EM, -1.0);
+  if (size >= 0)
+    return (size & ((1<<28)-1)) / ((gdouble) EM_PRECISION);
+  else
+    return -(size & ((1<<28)-1)) / ((gdouble) EM_PRECISION);
+}
+
+/**
+ * gtk_size_get_mm:
+ * @size: a #GtkSize of type #GTK_SIZE_UNIT_MM
+ *
+ * Gets the number of millimeters stored in @size. Returns -1 if the
+ * unit of @size is not @GTK_SIZE_UNIT_MM.
+ *
+ * Returns: a #gdouble
+ *
+ * Since: 2.14
+ **/
+gdouble
+gtk_size_get_mm (GtkSize size)
+{
+  g_return_val_if_fail (gtk_size_get_unit (size) == GTK_SIZE_UNIT_MM, -1.0);
+  if (size >= 0)
+    return (size & ((1<<28)-1)) / ((gdouble) MM_PRECISION);
+  else
+    return -(size & ((1<<28)-1)) / ((gdouble) MM_PRECISION);
+}
+
+static void
+get_pixel_conversion_factors (GdkScreen *screen,
+                              gint monitor_num,
+                              gdouble *pixels_per_em,
+                              gdouble *pixels_per_mm)
+{
+  if (screen == NULL || monitor_num == -1)
+    {
+      GTK_NOTE (MULTIHEAD,
+		g_warning ("gtk_size_to_pixel ()) called with screen=%p monitor_num=%d", screen, monitor_num));
+    }
+  screen_settings_get_pixel_conversion_factors (screen, monitor_num, pixels_per_em, pixels_per_mm);
+}
+
+/**
+ * gtk_size_to_pixel:
+ * @screen: A #GdkScreen or #NULL to use the default #GdkScreen
+ * @monitor_num: number of the monitor or -1 to use the default monitor
+ * @size: A #GtkSize or #GtkUSize
+ *
+ * Converts @size to an integer representing the number of pixels
+ * taking factors like font size etc. into account.
+ *
+ * See also gtk_widget_size_to_pixel().
+ *
+ * Returns: @size converted to pixel value
+ *
+ * Since: 2.14
+ */
+gint
+gtk_size_to_pixel (GdkScreen *screen,
+                   gint       monitor_num,
+                   GtkSize    size)
+{
+  return (gint) (gtk_size_to_pixel_double (screen, monitor_num, size) + 0.5);
+}
+
+/**
+ * gtk_size_to_pixel_double:
+ * @screen: A #GdkScreen or #NULL to use the default #GdkScreen
+ * @monitor_num: number of the monitor or -1 to use the default monitor
+ * @size: A #GtkSize or #GtkUSize
+ *
+ * Like gtk_size_to_pixel() but returns the pixel size in a @gdouble.
+ *
+ * See also gtk_widget_size_to_pixel_double().
+ *
+ * Returns: @size converted to pixel value
+ *
+ * Since: 2.14
+ */
+gdouble
+gtk_size_to_pixel_double (GdkScreen *screen,
+                          gint       monitor_num,
+                          GtkSize    size)
+{
+  gdouble val;
+  gdouble pixels_per_em;
+  gdouble pixels_per_mm;
+
+  check_if_resolution_independence_is_enabled ();
+
+  if (G_LIKELY (!units_enabled))
+    return size;
+
+  get_pixel_conversion_factors (screen, monitor_num, &pixels_per_em, &pixels_per_mm);
+
+  switch (gtk_size_get_unit (size))
+    {
+    case GTK_SIZE_UNIT_PIXEL:
+      val = size;
+      //g_debug ("converted 0x%08x (%d pixels) to %g pixels", size, size, val);
+      break;
+
+    case GTK_SIZE_UNIT_EM:
+      val = gtk_size_get_em (size) * pixels_per_em;
+      //g_debug ("converted 0x%08x (%g em) to %g pixels", size, gtk_size_get_em (size), val);
+      break;
+
+    case GTK_SIZE_UNIT_MM:
+      val = gtk_size_get_mm (size) * pixels_per_mm;
+      //g_debug ("converted 0x%08x (%g mm) to %g pixels", size, gtk_size_get_mm (size), val);
+      break;
+
+    default:
+      g_warning ("gtk_size_to_pixel_double(): unknown unit for size 0x%08x", size);
+      val = -1.0;
+      break;
+    }
+
+  return val;
+}
+
+/* -------------------------------------------------------------------------------- */
+
+/**
+ * gtk_size_to_string:
+ * @size: A #GtkSize or #GtkUSize
+ *
+ * Gets a human readable textual representation of @size such as "2
+ * px" or "0.5 em". The caller cannot rely on the string being machine
+ * readable; the format may change in a future release.
+ *
+ * Returns: the textual representation of @size - free with g_free().
+ *
+ * Since: 2.14
+ **/
+gchar *
+gtk_size_to_string (GtkSize size)
+{
+  gchar *s;
+
+  switch (gtk_size_get_unit (size))
+    {
+    case GTK_SIZE_UNIT_PIXEL:
+      if (size == GTK_SIZE_MAXPIXEL)
+        s = g_strdup ("GTK_SIZE_MAXPIXEL");
+      else if (size == -GTK_SIZE_MAXPIXEL)
+        s = g_strdup ("-GTK_SIZE_MAXPIXEL");
+      else
+        s = g_strdup_printf ("%d px", size);
+      break;
+
+    case GTK_SIZE_UNIT_EM:
+      s = g_strdup_printf ("%g em", gtk_size_get_em (size));
+      break;
+
+    case GTK_SIZE_UNIT_MM:
+      s = g_strdup_printf ("%g mm", gtk_size_get_mm (size));
+      break;
+
+    default:
+      s = g_strdup_printf ("unknown unit for size 0x%08x", size);
+      break;
+    }
+
+  return s;
+}
+
+/* -------------------------------------------------------------------------------- */
+
+static gboolean
+gtk_param_size_validate (GParamSpec *pspec,
+                         GValue     *value)
+{
+  GParamSpecInt *ispec = G_PARAM_SPEC_INT (pspec);
+  gint oldval;
+
+  if (gtk_size_get_unit (value->data[0].v_int) != GTK_SIZE_UNIT_PIXEL)
+    return FALSE;
+
+  oldval = value->data[0].v_int;
+  value->data[0].v_int = CLAMP (value->data[0].v_int, ispec->minimum, ispec->maximum);
+
+  return value->data[0].v_int != oldval;
+}
+
+static void
+gtk_param_size_class_init (GParamSpecClass *class)
+{
+  class->value_type = G_TYPE_INT;
+  class->value_validate = gtk_param_size_validate;
+}
+
+GType
+gtk_param_size_get_type (void)
+{
+  static GType type = 0;
+
+  if (G_UNLIKELY (type == 0))
+    {
+      static const GTypeInfo type_info =
+      {
+        sizeof (GParamSpecClass),
+        NULL,
+        NULL,
+        (GClassInitFunc) gtk_param_size_class_init,
+        NULL,
+        NULL,
+        sizeof (GtkParamSpecSize),
+        0,
+        NULL,
+        NULL
+      };
+
+      type = g_type_register_static (G_TYPE_PARAM_INT,
+                                     "GtkParamSize",
+                                     &type_info,
+                                     0);
+    }
+
+  return type;
+}
+
+/**
+ * gtk_param_spec_size:
+ * @name: canonical name of the property specified
+ * @nick: nick name for the property specified
+ * @blurb: description of the property specified
+ * @minimum: minimum value for the property specified
+ * @maximum: maximum value for the property specified
+ * @default_value: default value for the property specified
+ * @flags: flags for the property specified
+ *
+ * Creates a new #GParamSpec instance specifying a #GtkSize property.
+ *
+ * See g_param_spec_internal() for details on property names.
+ *
+ * Returns: a newly created parameter specification
+ *
+ * Since: 2.14
+ **/
+GParamSpec *
+gtk_param_spec_size (const gchar *name,
+                     const gchar *nick,
+                     const gchar *blurb,
+                     GtkSize      minimum,
+                     GtkSize      maximum,
+                     GtkSize      default_value,
+                     GParamFlags  flags)
+{
+  GtkParamSpecSize *pspec;
+  GParamSpecInt *ispec;
+  pspec = g_param_spec_internal (GTK_TYPE_PARAM_SIZE,
+                                 name, nick, blurb, flags);
+  ispec = G_PARAM_SPEC_INT (pspec);
+  ispec->default_value = default_value;
+  ispec->minimum = minimum;
+  ispec->maximum = maximum;
+  return G_PARAM_SPEC (pspec);
+}
+
+/**
+ * gtk_value_set_size:
+ * @value: a valid #GValue of type #G_TYPE_INT
+ * @v_size: size value to be set
+ * @widget: a #GtkWidget used for converting to pixel sizes or #NULL
+ *
+ * Sets the content of a #GValue of type #G_TYPE_INT to @v_size.
+ *
+ * Unless gtk_value_size_skip_conversion() have been called on
+ * @v_size, the contents will be converted to pixel values using
+ * gtk_widget_size_to_pixel() on @widget.
+ *
+ * Since: 2.14
+ **/
+void
+gtk_value_set_size (GValue    *value,
+                    GtkSize    v_size,
+                    gpointer   widget)
+{
+  g_return_if_fail (G_VALUE_HOLDS_INT (value));
+  if (value->data[1].v_int == 1)
+    value->data[0].v_int = v_size;
+  else
+    value->data[0].v_int = gtk_widget_size_to_pixel (widget, v_size);
+}
+
+/**
+ * gtk_value_get_size:
+ * @value: a valid #GValue of type #G_TYPE_INT
+ *
+ * Get the contents of a #GValue of type #G_TYPE_INT.
+ *
+ * Returns: a #GtkSize
+ *
+ * Since: 2.14
+ **/
+GtkSize
+gtk_value_get_size (const GValue *value)
+{
+  g_return_val_if_fail (G_VALUE_HOLDS_INT (value), 0);
+  return value->data[0].v_int;
+}
+
+/**
+ * gtk_value_size_skip_conversion:
+ * @value: a valid #GValue of type #G_TYPE_INT
+ *
+ * Specify that conversion to pixel values should be skipped in
+ * gtk_value_set_size().
+ *
+ * Since: 2.14
+ **/
+void
+gtk_value_size_skip_conversion (GValue *value)
+{
+  g_return_if_fail (G_VALUE_HOLDS_INT (value));
+  value->data[1].v_int = 1;
+}
+
+/* -------------------------------------------------------------------------------- */
+
+static gboolean
+gtk_param_usize_validate (GParamSpec *pspec,
+                          GValue     *value)
+{
+  GParamSpecUInt *uspec = G_PARAM_SPEC_UINT (pspec);
+  gint oldval;
+
+  if (gtk_size_get_unit (value->data[0].v_int) != GTK_SIZE_UNIT_PIXEL)
+    return FALSE;
+
+  oldval = value->data[0].v_int;
+  value->data[0].v_int = CLAMP (value->data[0].v_int, uspec->minimum, uspec->maximum);
+
+  return value->data[0].v_int != oldval;
+}
+
+static void
+gtk_param_usize_class_init (GParamSpecClass *class)
+{
+  class->value_type = G_TYPE_UINT;
+  class->value_validate = gtk_param_usize_validate;
+}
+
+GType
+gtk_param_usize_get_type (void)
+{
+  static GType type = 0;
+
+  if (G_UNLIKELY (type == 0))
+    {
+      static const GTypeInfo type_info =
+      {
+        sizeof (GParamSpecClass),
+        NULL,
+        NULL,
+        (GClassInitFunc) gtk_param_usize_class_init,
+        NULL,
+        NULL,
+        sizeof (GtkParamSpecUSize),
+        0,
+        NULL,
+        NULL
+      };
+
+      type = g_type_register_static (G_TYPE_PARAM_UINT,
+                                     "GtkParamUSize",
+                                     &type_info,
+                                     0);
+    }
+
+  return type;
+}
+
+/**
+ * gtk_param_spec_usize:
+ * @name: canonical name of the property specified
+ * @nick: nick name for the property specified
+ * @blurb: description of the property specified
+ * @minimum: minimum value for the property specified
+ * @maximum: maximum value for the property specified
+ * @default_value: default value for the property specified
+ * @flags: flags for the property specified
+ *
+ * Creates a new #GParamSpec instance specifying a #GtkUSize property.
+ *
+ * See g_param_spec_internal() for details on property names.
+ *
+ * Returns: a newly created parameter specification
+ *
+ * Since: 2.14
+ **/
+GParamSpec *
+gtk_param_spec_usize (const gchar *name,
+                      const gchar *nick,
+                      const gchar *blurb,
+                      GtkUSize     minimum,
+                      GtkUSize     maximum,
+                      GtkUSize     default_value,
+                      GParamFlags  flags)
+{
+  GtkParamSpecUSize *pspec;
+  GParamSpecUInt *uspec;
+  pspec = g_param_spec_internal (GTK_TYPE_PARAM_USIZE,
+                                 name, nick, blurb, flags);
+  uspec = G_PARAM_SPEC_UINT (pspec);
+  uspec->default_value = default_value;
+  uspec->minimum = minimum;
+  uspec->maximum = maximum;
+  return G_PARAM_SPEC (pspec);
+}
+
+/**
+ * gtk_value_set_usize:
+ * @value: a valid #GValue of type #G_TYPE_UINT
+ * @v_size: size value to be set
+ * @widget: a #GtkWidget used for converting to pixel sizes or #NULL
+ *
+ * Sets the content of a #GValue of type #G_TYPE_UINT to @v_size.
+ *
+ * Unless gtk_value_usize_skip_conversion() have been called on
+ * @v_size, the contents will be converted to pixel values using
+ * gtk_widget_size_to_pixel() on @widget.
+ *
+ * Since: 2.14
+ **/
+void
+gtk_value_set_usize (GValue    *value,
+                     GtkUSize   v_size,
+                     gpointer   widget)
+{
+  g_return_if_fail (G_VALUE_HOLDS_UINT (value));
+  if (value->data[1].v_int == 1)
+    value->data[0].v_uint = v_size;
+  else
+    value->data[0].v_uint = gtk_widget_size_to_pixel (widget, v_size);
+}
+
+/**
+ * gtk_value_get_usize:
+ * @value: a valid #GValue of type #G_TYPE_UINT
+ *
+ * Get the contents of a #GValue of type #G_TYPE_UINT.
+ *
+ * Returns: a #GtkUSize
+ *
+ * Since: 2.14
+ **/
+GtkUSize
+gtk_value_get_usize (const GValue *value)
+{
+  g_return_val_if_fail (G_VALUE_HOLDS_UINT (value), 0);
+  return value->data[0].v_uint;
+}
+
+/**
+ * gtk_value_usize_skip_conversion:
+ * @value: a valid #GValue of type #G_TYPE_UINT
+ *
+ * Specify that conversion to pixel values should be skipped in
+ * gtk_value_set_usize().
+ *
+ * Since: 2.14
+ **/
+void
+gtk_value_usize_skip_conversion (GValue *value)
+{
+  g_return_if_fail (G_VALUE_HOLDS_UINT (value));
+  value->data[1].v_int = 1;
+}
+
+/* -------------------------------------------------------------------------------- */
+
+#define __GTK_SIZE_C__
+#include "gtkaliasdef.c"
diff --git a/gtk/gtksize.h b/gtk/gtksize.h
new file mode 100644
index 0000000..07c2b9c
--- /dev/null
+++ b/gtk/gtksize.h
@@ -0,0 +1,180 @@
+/* GTK - The GIMP Toolkit
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#if defined(GTK_DISABLE_SINGLE_INCLUDES) && !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gtk/gtk.h> can be included directly."
+#endif
+
+#ifndef __GTK_SIZE_H__
+#define __GTK_SIZE_H__
+
+#include <gdk/gdk.h>
+#include <gtk/gtkstyle.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GtkSize:
+ *
+ * A data type for storing both a size and a unit.
+ *
+ * Note that the binary representation of a #GtkUnit may vary
+ * depending on whether resolution independent rendering is enabled
+ * (see gtk_enable_resolution_independence()). As such, a #GtkSize
+ * cannot e.g. be stored on disk or passed to other processes.
+ *
+ * Since: 2.14
+ */
+typedef gint GtkSize;
+
+/**
+ * GtkUSize:
+ *
+ * Like #GtkSize but for unsigned sizes.
+ *
+ * Since: 2.14
+ */
+typedef guint GtkUSize;
+
+/**
+ * GtkSizeUnit:
+ * @GTK_SIZE_UNIT_PIXEL: the size is measure in pixels
+ * @GTK_SIZE_UNIT_EM: the size is measured in em
+ * @GTK_SIZE_UNIT_MM: the size is measured in millimeters
+ *
+ * The unit used to interpret the value stored in #GtkSize or
+ * #GtkUSize. Use gtk_size_get_unit().
+ *
+ * Since: 2.14
+ */
+typedef enum
+{
+  GTK_SIZE_UNIT_PIXEL   = 0,
+  GTK_SIZE_UNIT_EM      = 1,
+  GTK_SIZE_UNIT_MM      = 2,
+} GtkSizeUnit;
+
+/**
+ * GTK_SIZE_MAXPIXEL:
+ *
+ * The largest pixel size allowed when using #GtkSize. When using
+ * units instead of pixel sizes, use this constant instead of G_MAXINT
+ * when needing to specify a huge default for a bounded value.
+ *
+ * Since: 2.14
+ */
+#define GTK_SIZE_MAXPIXEL ((1<<28) - 1)
+
+/**
+ * GTK_SIZE_MINPIXEL:
+ *
+ * The smallest pixel size allowed when using #GtkSize. When using
+ * units instead of pixel sizes, use this constant instead of G_MININT
+ * when needing to specify a small default for a bounded value.
+ *
+ * Since: 2.14
+ */
+#define GTK_SIZE_MINPIXEL (-GTK_SIZE_MAXPIXEL)
+
+GtkSize     gtk_size_em              (gdouble      em);
+GtkSize     gtk_size_mm              (gdouble      mm);
+gdouble     gtk_size_get_em          (GtkSize      size);
+gdouble     gtk_size_get_mm          (GtkSize      size);
+GtkSizeUnit gtk_size_get_unit        (GtkSize      size);
+
+gint        gtk_size_to_pixel        (GdkScreen   *screen,
+                                      gint         monitor_num,
+                                      GtkSize      size) G_GNUC_WARN_UNUSED_RESULT;
+gdouble     gtk_size_to_pixel_double (GdkScreen   *screen,
+                                      gint         monitor_num,
+                                      GtkSize      size) G_GNUC_WARN_UNUSED_RESULT;
+gchar      *gtk_size_to_string       (GtkSize      size);
+
+/**
+ * GtkSizeError:
+ * @GTK_SIZE_ERROR_INVALID_VALUE: an invalid value was passed
+ *
+ * Error codes returned by size/unit parsing.
+ *
+ * Since: 2.14
+ */
+typedef enum
+{
+  GTK_SIZE_ERROR_INVALID_VALUE,
+} GtkSizeError;
+
+/* for now, use functions so apps can "opt in" to using resolution
+ * independent units - when this is mandatory (e.g. gtk 3.x) this
+ * can be changed into macros
+ */
+void gtk_enable_resolution_independence (void);
+
+/**
+ * GTK_SIZE_ONE_TWELFTH_EM:
+ * @value: A value in 1/12th of an em
+ *
+ * Convenience macro returning @value / 12 em's in a #GtkSize. See
+ * gtk_unit_em() for details.
+ *
+ * Since: 2.14
+ */
+#define GTK_SIZE_ONE_TWELFTH_EM(value) gtk_size_em((value)/12.0)
+
+#define GTK_IS_PARAM_SPEC_SIZE(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GTK_TYPE_PARAM_SIZE))
+#define GTK_PARAM_SPEC_SIZE(pspec)    (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GTK_TYPE_PARAM_SIZE, GtkParamSpecSize))
+#define GTK_TYPE_PARAM_SIZE           (gtk_param_size_get_type())
+
+GType gtk_param_size_get_type (void) G_GNUC_CONST;
+
+GParamSpec *gtk_param_spec_size (const gchar  *name,
+                                 const gchar  *nick,
+                                 const gchar  *blurb,
+                                 GtkSize       minimum,
+                                 GtkSize       maximum,
+                                 GtkSize       default_value,
+                                 GParamFlags   flags);
+void gtk_value_set_size         (GValue       *value,
+                                 GtkSize       v_size,
+                                 gpointer      widget);
+GtkSize gtk_value_get_size      (const GValue *value);
+
+void gtk_value_size_skip_conversion (GValue *value);
+
+#define GTK_IS_PARAM_SPEC_USIZE(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GTK_TYPE_PARAM_USIZE))
+#define GTK_PARAM_SPEC_USIZE(pspec)    (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GTK_TYPE_PARAM_USIZE, GtkParamSpecUSize))
+#define GTK_TYPE_PARAM_USIZE           (gtk_param_usize_get_type())
+
+GType gtk_param_usize_get_type (void) G_GNUC_CONST;
+
+GParamSpec *gtk_param_spec_usize (const gchar  *name,
+                                  const gchar  *nick,
+                                  const gchar  *blurb,
+                                  GtkUSize      minimum,
+                                  GtkUSize      maximum,
+                                  GtkUSize      default_value,
+                                  GParamFlags   flags);
+void gtk_value_set_usize         (GValue       *value,
+                                  GtkUSize      v_size,
+                                  gpointer      widget);
+GtkUSize gtk_value_get_usize     (const GValue *value);
+
+void gtk_value_usize_skip_conversion (GValue *value);
+
+G_END_DECLS
+
+#endif /* __GTK_SIZE_H__ */
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 9a45e42..dceb7a8 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -128,6 +128,7 @@ enum {
   KEYNAV_FAILED,
   DRAG_FAILED,
   DAMAGE_EVENT,
+  UNIT_CHANGED,
   LAST_SIGNAL
 };
 
@@ -276,11 +277,12 @@ static void             gtk_widget_buildable_parser_finished    (GtkBuildable
 
      
 static void gtk_widget_set_usize_internal (GtkWidget *widget,
-					   gint       width,
-					   gint       height);
+					   GtkSize    width,
+					   GtkSize    height);
 static void gtk_widget_get_draw_rectangle (GtkWidget    *widget,
 					   GdkRectangle *rect);
 
+static void gtk_widget_unit_changed (GtkWidget *widget);
 
 /* --- variables --- */
 static gpointer         gtk_widget_parent_class = NULL;
@@ -476,6 +478,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
   klass->get_accessible = gtk_widget_real_get_accessible;
 
   klass->no_expose_event = NULL;
+  klass->unit_changed = gtk_widget_unit_changed;
 
   g_object_class_install_property (gobject_class,
 				   PROP_NAME,
@@ -494,22 +497,18 @@ gtk_widget_class_init (GtkWidgetClass *klass)
 
   g_object_class_install_property (gobject_class,
 				   PROP_WIDTH_REQUEST,
-				   g_param_spec_int ("width-request",
- 						     P_("Width request"),
- 						     P_("Override for width request of the widget, or -1 if natural request should be used"),
- 						     -1,
- 						     G_MAXINT,
- 						     -1,
- 						     GTK_PARAM_READWRITE));
+				   gtk_param_spec_size ("width-request",
+                                                        P_("Width request"),
+                                                        P_("Override for width request of the widget, or -1 if natural request should be used"),
+                                                        -1, G_MAXINT, -1,
+                                                        GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
 				   PROP_HEIGHT_REQUEST,
-				   g_param_spec_int ("height-request",
- 						     P_("Height request"),
- 						     P_("Override for height request of the widget, or -1 if natural request should be used"),
- 						     -1,
- 						     G_MAXINT,
- 						     -1,
- 						     GTK_PARAM_READWRITE));
+				   gtk_param_spec_size ("height-request",
+                                                        P_("Height request"),
+                                                        P_("Override for height request of the widget, or -1 if natural request should be used"),
+                                                        -1, G_MAXINT, -1,
+                                                        GTK_PARAM_READWRITE));
   g_object_class_install_property (gobject_class,
 				   PROP_VISIBLE,
 				   g_param_spec_boolean ("visible",
@@ -1094,6 +1093,24 @@ gtk_widget_class_init (GtkWidgetClass *klass)
 		  G_TYPE_NONE, 0);
 
   /**
+   * GtkWidget::unit-changed:
+   * @widget: the object on which the signal is emitted
+   *
+   * The ::unit-changed signal is emitted when the units
+   * change. @widget should recompute internal pixel sizes.
+   *
+   * Since: 2.14
+   */
+  widget_signals[UNIT_CHANGED] =
+    g_signal_new (I_("unit_changed"),
+		  G_TYPE_FROM_CLASS (gobject_class),
+		  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+		  G_STRUCT_OFFSET (GtkWidgetClass, unit_changed),
+		  NULL, NULL,
+		  _gtk_marshal_VOID__VOID,
+		  G_TYPE_NONE, 0);
+
+  /**
    * GtkWidget::keynav-failed:
    * @widget: the object which received the signal
    * @direction: the direction of movement
@@ -2215,11 +2232,11 @@ gtk_widget_class_init (GtkWidgetClass *klass)
 								 GTK_PARAM_READABLE));
 
   gtk_widget_class_install_style_property (klass,
-					   g_param_spec_int ("focus-line-width",
-							     P_("Focus linewidth"),
-							     P_("Width, in pixels, of the focus indicator line"),
-							     0, G_MAXINT, 1,
-							     GTK_PARAM_READABLE));
+					   gtk_param_spec_size ("focus-line-width",
+                                                                P_("Focus linewidth"),
+                                                                P_("Width, in pixels, of the focus indicator line"),
+                                                                0, G_MAXINT, GTK_SIZE_ONE_TWELFTH_EM (1),
+                                                                GTK_PARAM_READABLE));
 
   gtk_widget_class_install_style_property (klass,
 					   g_param_spec_string ("focus-line-pattern",
@@ -2228,11 +2245,11 @@ gtk_widget_class_init (GtkWidgetClass *klass)
 								"\1\1",
 								GTK_PARAM_READABLE));
   gtk_widget_class_install_style_property (klass,
-					   g_param_spec_int ("focus-padding",
-							     P_("Focus padding"),
-							     P_("Width, in pixels, between focus indicator and the widget 'box'"),
-							     0, G_MAXINT, 1,
-							     GTK_PARAM_READABLE));
+					   gtk_param_spec_size ("focus-padding",
+                                                                P_("Focus padding"),
+                                                                P_("Width, in pixels, between focus indicator and the widget 'box'"),
+                                                                0, G_MAXINT, GTK_SIZE_ONE_TWELFTH_EM (1),
+                                                                GTK_PARAM_READABLE));
   gtk_widget_class_install_style_property (klass,
 					   g_param_spec_boxed ("cursor-color",
 							       P_("Cursor color"),
@@ -2319,11 +2336,11 @@ gtk_widget_class_init (GtkWidgetClass *klass)
    * Since: 2.10
    */
   gtk_widget_class_install_style_property (klass,
-                                           g_param_spec_int ("separator-width",
-                                                             P_("Separator Width"),
-                                                             P_("The width of separators if wide-separators is TRUE"),
-                                                             0, G_MAXINT, 0,
-                                                             GTK_PARAM_READABLE));
+                                           gtk_param_spec_size ("separator-width",
+                                                                P_("Separator Width"),
+                                                                P_("The width of separators if wide-separators is TRUE"),
+                                                                0, G_MAXINT, 0,
+                                                                GTK_PARAM_READABLE));
 
   /**
    * GtkWidget:separator-height:
@@ -2334,11 +2351,11 @@ gtk_widget_class_init (GtkWidgetClass *klass)
    * Since: 2.10
    */
   gtk_widget_class_install_style_property (klass,
-                                           g_param_spec_int ("separator-height",
-                                                             P_("Separator Height"),
-                                                             P_("The height of separators if \"wide-separators\" is TRUE"),
-                                                             0, G_MAXINT, 0,
-                                                             GTK_PARAM_READABLE));
+                                           gtk_param_spec_size ("separator-height",
+                                                                P_("Separator Height"),
+                                                                P_("The height of separators if \"wide-separators\" is TRUE"),
+                                                                0, G_MAXINT, 0,
+                                                                GTK_PARAM_READABLE));
 
   /**
    * GtkWidget:scroll-arrow-hlength:
@@ -2349,11 +2366,11 @@ gtk_widget_class_init (GtkWidgetClass *klass)
    * Since: 2.10
    */
   gtk_widget_class_install_style_property (klass,
-                                           g_param_spec_int ("scroll-arrow-hlength",
-                                                             P_("Horizontal Scroll Arrow Length"),
-                                                             P_("The length of horizontal scroll arrows"),
-                                                             1, G_MAXINT, 16,
-                                                             GTK_PARAM_READABLE));
+                                           gtk_param_spec_size ("scroll-arrow-hlength",
+                                                                P_("Horizontal Scroll Arrow Length"),
+                                                                P_("The length of horizontal scroll arrows"),
+                                                                0, G_MAXINT, GTK_SIZE_ONE_TWELFTH_EM (16),
+                                                                GTK_PARAM_READABLE));
 
   /**
    * GtkWidget:scroll-arrow-vlength:
@@ -2364,11 +2381,11 @@ gtk_widget_class_init (GtkWidgetClass *klass)
    * Since: 2.10
    */
   gtk_widget_class_install_style_property (klass,
-                                           g_param_spec_int ("scroll-arrow-vlength",
-                                                             P_("Vertical Scroll Arrow Length"),
-                                                             P_("The length of vertical scroll arrows"),
-                                                             1, G_MAXINT, 16,
-                                                             GTK_PARAM_READABLE));
+                                           gtk_param_spec_size ("scroll-arrow-vlength",
+                                                                P_("Vertical Scroll Arrow Length"),
+                                                                P_("The length of vertical scroll arrows"),
+                                                                0, G_MAXINT, GTK_SIZE_ONE_TWELFTH_EM (16),
+                                                                GTK_PARAM_READABLE));
 }
 
 static void
@@ -2410,10 +2427,10 @@ gtk_widget_set_property (GObject         *object,
       gtk_container_add (GTK_CONTAINER (g_value_get_object (value)), widget);
       break;
     case PROP_WIDTH_REQUEST:
-      gtk_widget_set_usize_internal (widget, g_value_get_int (value), -2);
+      gtk_widget_set_usize_internal (widget, gtk_value_get_size (value), -2);
       break;
     case PROP_HEIGHT_REQUEST:
-      gtk_widget_set_usize_internal (widget, -2, g_value_get_int (value));
+      gtk_widget_set_usize_internal (widget, -2, gtk_value_get_size (value));
       break;
     case PROP_VISIBLE:
       if (g_value_get_boolean (value))
@@ -2552,14 +2569,14 @@ gtk_widget_get_property (GObject         *object,
       {
         int w;
         gtk_widget_get_size_request (widget, &w, NULL);
-        g_value_set_int (value, w);
+        gtk_value_set_size (value, w, widget);
       }
       break;
     case PROP_HEIGHT_REQUEST:
       {
         int h;
         gtk_widget_get_size_request (widget, NULL, &h);
-        g_value_set_int (value, h);
+        gtk_value_set_size (value, h, widget);
       }
       break;
     case PROP_VISIBLE:
@@ -5632,6 +5649,8 @@ gtk_widget_set_parent (GtkWidget *widget,
 
       gtk_widget_queue_resize (widget);
     }
+
+  _gtk_widget_propagate_unit_changed (widget);
 }
 
 /**
@@ -6297,6 +6316,52 @@ _gtk_widget_propagate_composited_changed (GtkWidget *widget)
   propagate_composited_changed (widget, NULL);
 }
 
+static void
+propagate_unit_changed (GtkWidget *widget,
+                        gpointer dummy)
+{
+  /* It's important to do parents before childs here - just consider a
+   * dialog with a tree view - the dialog will want to redo all
+   * pixbufs *before* the tree view (packed in the dialog) gets the
+   * signal...
+   */
+  g_signal_emit (widget, widget_signals[UNIT_CHANGED], 0);
+  if (GTK_IS_CONTAINER (widget))
+    {
+      gtk_container_forall (GTK_CONTAINER (widget),
+			    propagate_unit_changed,
+			    NULL);
+    }
+}
+
+static void
+propagate_resize (GtkWidget *widget,
+                  gpointer dummy)
+{
+  gtk_widget_queue_resize (widget);
+  if (GTK_IS_CONTAINER (widget))
+    {
+      gtk_container_forall (GTK_CONTAINER (widget),
+			    propagate_resize,
+			    NULL);
+    }
+}
+
+void
+_gtk_widget_propagate_unit_changed (GtkWidget *widget)
+{
+  propagate_unit_changed (widget, NULL);
+  propagate_resize (widget, NULL);
+}
+
+static void
+gtk_widget_unit_changed (GtkWidget *widget)
+{
+  PangoContext *context = g_object_get_qdata (G_OBJECT (widget), quark_pango_context);
+  if (context)
+    g_object_set_qdata (G_OBJECT (widget), quark_pango_context, NULL);
+}
+
 /**
  * _gtk_widget_propagate_screen_changed:
  * @widget: a #GtkWidget
@@ -6321,6 +6386,9 @@ _gtk_widget_propagate_screen_changed (GtkWidget    *widget,
 
   if (previous_screen)
     g_object_unref (previous_screen);
+
+  /* also, the unit is most probably different; update now that the new screen is set */
+  _gtk_widget_propagate_unit_changed (widget);
 }
 
 static void
@@ -6424,6 +6492,7 @@ gtk_widget_update_pango_context (GtkWidget *widget)
   
   if (context)
     {
+      gdouble resolution;
       GdkScreen *screen;
 
       update_pango_context (widget, context);
@@ -6431,10 +6500,13 @@ gtk_widget_update_pango_context (GtkWidget *widget)
       screen = gtk_widget_get_screen_unchecked (widget);
       if (screen)
 	{
-	  pango_cairo_context_set_resolution (context,
-					      gdk_screen_get_resolution (screen));
+          gint monitor_num;
+
+          monitor_num = gtk_widget_get_monitor_num (widget);
+          resolution = gdk_screen_get_resolution_for_monitor (screen, monitor_num);
+	  pango_cairo_context_set_resolution (context, resolution);
 	  pango_cairo_context_set_font_options (context,
-						gdk_screen_get_font_options (screen));
+						gdk_screen_get_font_options_for_monitor (screen, monitor_num));
 	}
     }
 }
@@ -6466,7 +6538,7 @@ gtk_widget_create_pango_context (GtkWidget *widget)
       screen = gdk_screen_get_default ();
     }
 
-  context = gdk_pango_context_get_for_screen (screen);
+  context = gdk_pango_context_get_for_screen_for_monitor (screen, gtk_widget_get_monitor_num (widget));
 
   update_pango_context (widget, context);
   pango_context_set_language (context, gtk_get_default_language ());
@@ -7045,8 +7117,8 @@ gtk_widget_set_uposition (GtkWidget *widget,
 
 static void
 gtk_widget_set_usize_internal (GtkWidget *widget,
-			       gint       width,
-			       gint       height)
+			       GtkSize    width,
+			       GtkSize    height)
 {
   GtkWidgetAuxInfo *aux_info;
   gboolean changed = FALSE;
@@ -7102,8 +7174,8 @@ gtk_widget_set_usize_internal (GtkWidget *widget,
  **/
 void
 gtk_widget_set_usize (GtkWidget *widget,
-		      gint	 width,
-		      gint	 height)
+		      GtkSize	 width,
+		      GtkSize	 height)
 {
   g_return_if_fail (GTK_IS_WIDGET (widget));
   
@@ -7148,8 +7220,8 @@ gtk_widget_set_usize (GtkWidget *widget,
  **/
 void
 gtk_widget_set_size_request (GtkWidget *widget,
-                             gint       width,
-                             gint       height)
+                             GtkSize    width,
+                             GtkSize    height)
 {
   g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (width >= -1);
@@ -7190,6 +7262,58 @@ gtk_widget_get_size_request (GtkWidget *widget,
   aux_info = _gtk_widget_get_aux_info (widget, FALSE);
 
   if (width)
+    {
+      if (aux_info != NULL &&
+          aux_info->width != -1 &&
+          gtk_widget_size_to_pixel (widget, aux_info->width) != aux_info->width)
+        {
+          if (gtk_widget_get_monitor_num (widget) >= 0)
+            *width = gtk_widget_size_to_pixel (widget, aux_info->width);
+          else
+            *width = -1;
+        }
+      else
+        *width = aux_info ? gtk_widget_size_to_pixel (widget, aux_info->width) : -1;
+    }
+
+  if (height)
+    {
+      if (aux_info != NULL &&
+          aux_info->height != -1 &&
+          gtk_widget_size_to_pixel (widget, aux_info->height) != aux_info->height)
+        {
+          if (gtk_widget_get_monitor_num (widget) >= 0)
+            *height = gtk_widget_size_to_pixel (widget, aux_info->height);
+          else
+            *height = -1;
+        }
+      else
+        *height = aux_info ? gtk_widget_size_to_pixel (widget, aux_info->height) : -1;
+    }
+}
+
+/**
+ * gtk_widget_get_size_request_unit:
+ * @widget: a #GtkWidget
+ * @width: return location for width, or %NULL
+ * @height: return location for height, or %NULL
+ *
+ * Like gtk_widget_get_size_request() but preserves the unit.
+ *
+ * Since: 2.14
+ **/
+void
+gtk_widget_get_size_request_unit (GtkWidget *widget,
+                                  GtkSize   *width,
+                                  GtkSize   *height)
+{
+  GtkWidgetAuxInfo *aux_info;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  aux_info = _gtk_widget_get_aux_info (widget, FALSE);
+
+  if (width)
     *width = aux_info ? aux_info->width : -1;
 
   if (height)
@@ -9041,18 +9165,38 @@ gtk_widget_style_get_property (GtkWidget   *widget,
   else
     {
       const GValue *peek_value;
+      GValue unit_val = {0, };
+      GValue uunit_val = {0, };
+      const GValue *value_to_use;
 
       peek_value = _gtk_style_peek_property_value (widget->style,
 						   G_OBJECT_TYPE (widget),
 						   pspec,
 						   (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser));
       
+      if (GTK_IS_PARAM_SPEC_SIZE (pspec))
+        {
+          g_value_init (&unit_val, G_TYPE_INT);
+          gtk_value_set_size (&unit_val, gtk_widget_size_to_pixel (widget, g_value_get_int (peek_value)), NULL);
+          value_to_use = &unit_val;
+        }
+      else if (GTK_IS_PARAM_SPEC_USIZE (pspec))
+        {
+          g_value_init (&uunit_val, G_TYPE_UINT);
+          gtk_value_set_size (&uunit_val, gtk_widget_size_to_pixel (widget, g_value_get_int (peek_value)), NULL);
+          value_to_use = &uunit_val;
+        }
+      else
+        {
+          value_to_use = peek_value;
+        }
+
       /* auto-conversion of the caller's value type
        */
       if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
-	g_value_copy (peek_value, value);
+	g_value_copy (value_to_use, value);
       else if (g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
-	g_value_transform (peek_value, value);
+	g_value_transform (value_to_use, value);
       else
 	g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
 		   pspec->name,
@@ -9106,10 +9250,27 @@ gtk_widget_style_get_valist (GtkWidget   *widget,
       /* style pspecs are always readable so we can spare that check here */
 
       peek_value = _gtk_style_peek_property_value (widget->style,
-						   G_OBJECT_TYPE (widget),
-						   pspec,
-						   (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser));
-      G_VALUE_LCOPY (peek_value, var_args, 0, &error);
+                                                   G_OBJECT_TYPE (widget),
+                                                   pspec,
+                                                   (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser));
+      if (GTK_IS_PARAM_SPEC_SIZE (pspec))
+        {
+          GValue unit_val = {0, };
+          g_value_init (&unit_val, G_TYPE_INT);
+          gtk_value_set_size (&unit_val, g_value_get_int (peek_value), widget);
+          G_VALUE_LCOPY (&unit_val, var_args, 0, &error);
+        }
+      else if (GTK_IS_PARAM_SPEC_USIZE (pspec))
+        {
+          GValue uunit_val = {0, };
+          g_value_init (&uunit_val, G_TYPE_UINT);
+          gtk_value_set_size (&uunit_val, g_value_get_uint (peek_value), widget);
+          G_VALUE_LCOPY (&uunit_val, var_args, 0, &error);
+        }
+      else
+        {
+          G_VALUE_LCOPY (peek_value, var_args, 0, &error);
+        }
       if (error)
 	{
 	  g_warning ("%s: %s", G_STRLOC, error);
@@ -9131,7 +9292,9 @@ gtk_widget_style_get_valist (GtkWidget   *widget,
  *   return the property values, starting with the location for 
  *   @first_property_name, terminated by %NULL.
  *
- * Gets the values of a multiple style properties of @widget.
+ * Gets the values of a multiple style properties of @widget. All
+ * #GtkSize properties will be converted to pixels; use
+ * gtk_widget_style_get_unit() to preserve the units.
  */
 void
 gtk_widget_style_get (GtkWidget   *widget,
@@ -9148,6 +9311,152 @@ gtk_widget_style_get (GtkWidget   *widget,
 }
 
 /**
+ * gtk_widget_style_get_property_unit:
+ * @widget: a #GtkWidget
+ * @property_name: the name of a style property
+ * @value: location to return the property value 
+ *
+ * Like gtk_widget_style_get_property() but preserves units.
+ *
+ * Since: 2.14
+ */
+void
+gtk_widget_style_get_property_unit (GtkWidget   *widget,
+                                    const gchar *property_name,
+                                    GValue      *value)
+{
+  GParamSpec *pspec;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (property_name != NULL);
+  g_return_if_fail (G_IS_VALUE (value));
+
+  g_object_ref (widget);
+  pspec = g_param_spec_pool_lookup (style_property_spec_pool,
+				    property_name,
+				    G_OBJECT_TYPE (widget),
+				    TRUE);
+  if (!pspec)
+    g_warning ("%s: widget class `%s' has no property named `%s'",
+	       G_STRLOC,
+	       G_OBJECT_TYPE_NAME (widget),
+	       property_name);
+  else
+    {
+      const GValue *peek_value;
+
+      peek_value = _gtk_style_peek_property_value (widget->style,
+						   G_OBJECT_TYPE (widget),
+						   pspec,
+						   (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser));
+      
+      /* auto-conversion of the caller's value type
+       */
+      if (G_VALUE_TYPE (value) == G_PARAM_SPEC_VALUE_TYPE (pspec))
+	g_value_copy (peek_value, value);
+      else if (g_value_type_transformable (G_PARAM_SPEC_VALUE_TYPE (pspec), G_VALUE_TYPE (value)))
+	g_value_transform (peek_value, value);
+      else
+	g_warning ("can't retrieve style property `%s' of type `%s' as value of type `%s'",
+		   pspec->name,
+		   g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)),
+		   G_VALUE_TYPE_NAME (value));
+    }
+  g_object_unref (widget);
+}
+
+/**
+ * gtk_widget_style_get_unit_valist:
+ * @widget: a #GtkWidget
+ * @first_property_name: the name of the first property to get
+ * @var_args: a <type>va_list</type> of pairs of property names and
+ *     locations to return the property values, starting with the location
+ *     for @first_property_name.
+ *
+ * Non-vararg variant of gtk_widget_style_get_unit(). Used
+ * primarily by language bindings.
+ *
+ * Since: 2.14
+ */
+void
+gtk_widget_style_get_unit_valist (GtkWidget   *widget,
+                                  const gchar *first_property_name,
+                                  va_list      var_args)
+{
+  const gchar *name;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  g_object_ref (widget);
+
+  name = first_property_name;
+  while (name)
+    {
+      const GValue *peek_value;
+      GParamSpec *pspec;
+      gchar *error;
+
+      pspec = g_param_spec_pool_lookup (style_property_spec_pool,
+					name,
+					G_OBJECT_TYPE (widget),
+					TRUE);
+      if (!pspec)
+	{
+	  g_warning ("%s: widget class `%s' has no property named `%s'",
+		     G_STRLOC,
+		     G_OBJECT_TYPE_NAME (widget),
+		     name);
+	  break;
+	}
+      /* style pspecs are always readable so we can spare that check here */
+
+      peek_value = _gtk_style_peek_property_value (widget->style,
+						   G_OBJECT_TYPE (widget),
+						   pspec,
+						   (GtkRcPropertyParser) g_param_spec_get_qdata (pspec, quark_property_parser));
+      G_VALUE_LCOPY (peek_value, var_args, 0, &error);
+
+      if (error)
+	{
+	  g_warning ("%s: %s", G_STRLOC, error);
+	  g_free (error);
+	  break;
+	}
+
+      name = va_arg (var_args, gchar*);
+    }
+
+  g_object_unref (widget);
+}
+
+/**
+ * gtk_widget_style_get_unit:
+ * @widget: a #GtkWidget
+ * @first_property_name: the name of the first property to get
+ * @Varargs: pairs of property names and locations to 
+ *   return the property values, starting with the location for 
+ *   @first_property_name, terminated by %NULL.
+ *
+ * Like gtk_widget_stylet_get() but preserves all #GtkSize values
+ * rather than using gtk_size_to_pixel().
+ *
+ * Since: 2.14
+ */
+void
+gtk_widget_style_get_unit (GtkWidget   *widget,
+                           const gchar *first_property_name,
+                           ...)
+{
+  va_list var_args;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  va_start (var_args, first_property_name);
+  gtk_widget_style_get_unit_valist (widget, first_property_name, var_args);
+  va_end (var_args);
+}
+
+/**
  * gtk_widget_path:
  * @widget: a #GtkWidget
  * @path_length: location to store length of the path, or %NULL
@@ -10370,5 +10679,202 @@ gtk_widget_get_monitor_num (GtkWidget *widget)
   return monitor_num;
 }
 
+static void
+get_screen_and_monitor (GtkWidget *widget, GdkScreen **screen, gint *monitor_num)
+{
+  *screen = NULL;
+  *monitor_num = -1;
+
+  if (widget != NULL)
+    {
+      GtkWidget *w;
+      GtkWidget *toplevel;
+      w = GTK_WIDGET (widget);
+      toplevel = gtk_widget_get_toplevel (w);
+      if (toplevel != NULL)
+        {
+          *screen = gtk_widget_get_screen (toplevel);
+          if (*screen != NULL && GTK_WIDGET_TOPLEVEL (toplevel) && GTK_IS_WINDOW (toplevel))
+            *monitor_num = gtk_window_get_monitor_num (GTK_WINDOW (toplevel));
+        }
+    }
+}
+
+/**
+ * gtk_widget_size_to_pixel:
+ * @wid: a #GtkWidget or %NULL
+ * @size: a #GtkSize or #GtkUSize
+ *
+ * Converts @size to an integer representing the number of pixels on
+ * the monitor that @wid's top-level belongs to.
+ *
+ * See also gtk_size_to_pixel().
+ *
+ * Returns: @size converted to pixel value
+ *
+ * Since: 2.14
+ */
+gint
+gtk_widget_size_to_pixel (gpointer widget, GtkSize size)
+{
+  gint monitor_num;
+  GdkScreen *screen;
+
+  get_screen_and_monitor (widget, &screen, &monitor_num);
+
+  return gtk_size_to_pixel (screen, monitor_num, size);
+}
+
+
+/**
+ * gtk_widget_size_to_pixel_double:
+ * @wid: a #GtkWidget or %NULL
+ * @size: a #GtkSize or #GtkUSize
+ *
+ * Like gtk_widget_size_to_pixel() but returns the pixel size as a
+ * @gdouble.
+ *
+ * See also gtk_size_to_pixel_double().
+ *
+ * Returns: @size converted to pixel value
+ *
+ * Since: 2.14
+ */
+gdouble
+gtk_widget_size_to_pixel_double (gpointer widget, GtkSize size)
+{
+  gint monitor_num;
+  GdkScreen *screen;
+
+  get_screen_and_monitor (widget, &screen, &monitor_num);
+
+  return gtk_size_to_pixel_double (screen, monitor_num, size);
+}
+
+/*****************************************
+ * GtkWidget unit-preserving property getter
+ *
+ *****************************************/
+
+static inline void
+object_get_property (GObject     *object,
+		     GParamSpec  *pspec,
+		     GValue      *value)
+{
+  GObjectClass *class = g_type_class_peek (pspec->owner_type);
+  guint param_id = pspec->param_id;
+  GParamSpec *redirect;
+
+  redirect = g_param_spec_get_redirect_target (pspec);
+  if (redirect)
+    pspec = redirect;
+
+  class->get_property (object, param_id, value, pspec);
+}
+
+/**
+ * gtk_widget_get_unit_valist:
+ * @object: a #GtkWidget
+ * @first_property_name: name of the first property to get
+ * @var_args: return location for the first property, followed
+ * optionally by more name/return location pairs, followed by NULL
+ *
+ * Like g_object_get_valist() but preserves the unit for properties of
+ * type #GtkSize and #GtkUSize.
+ *
+ * Since: 2.14
+ **/
+void
+gtk_widget_get_unit_valist (GtkWidget *widget,
+                            const gchar *first_property_name,
+                            va_list	  var_args)
+{
+  const gchar *name;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  g_object_ref (widget);
+
+  name = first_property_name;
+
+  while (name)
+    {
+      GValue value = { 0, };
+      GParamSpec *pspec;
+      gchar *error;
+
+      pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (widget), name);
+      if (!pspec)
+	{
+	  g_warning ("%s: object class `%s' has no property named `%s'",
+		     G_STRFUNC,
+		     G_OBJECT_TYPE_NAME (widget),
+		     name);
+	  break;
+	}
+      if (!(pspec->flags & G_PARAM_READABLE))
+	{
+	  g_warning ("%s: property `%s' of object class `%s' is not readable",
+		     G_STRFUNC,
+		     pspec->name,
+		     G_OBJECT_TYPE_NAME (widget));
+	  break;
+	}
+
+      g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+      /* this tells gtk_value_set_size() and gtk_value_set_usize() to
+       * avoid conversion when storing the data
+       */
+      if (GTK_IS_PARAM_SPEC_SIZE (pspec))
+        gtk_value_size_skip_conversion (&value);
+      else if (GTK_IS_PARAM_SPEC_USIZE (pspec))
+        gtk_value_usize_skip_conversion (&value);
+
+      object_get_property (G_OBJECT (widget), pspec, &value);
+
+      G_VALUE_LCOPY (&value, var_args, 0, &error);
+      if (error)
+	{
+	  g_warning ("%s: %s", G_STRFUNC, error);
+	  g_free (error);
+	  g_value_unset (&value);
+	  break;
+	}
+
+      g_value_unset (&value);
+
+      name = va_arg (var_args, gchar*);
+    }
+
+  g_object_unref (widget);
+}
+
+/**
+ * gtk_widget_get_unit:
+ * @object: a #GtkWidget
+ * @first_property_name: name of the first property to get
+ * @...: return location for the first property, followed optionally
+ * by more name/return location pairs, followed by NULL
+ *
+ * Like g_object_get() but preserves the unit for properties of type
+ * #GtkSize and #GtkUSize.
+ *
+ * Since: 2.14
+ **/
+void
+gtk_widget_get_unit (gpointer widget,
+                     const gchar *first_property_name,
+                     ...)
+{
+  va_list var_args;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  va_start (var_args, first_property_name);
+  gtk_widget_get_unit_valist (widget, first_property_name, var_args);
+  va_end (var_args);
+}
+
 #define __GTK_WIDGET_C__
 #include "gtkaliasdef.c"
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 0fb6c9a..d5b4a86 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -133,6 +133,9 @@ typedef enum
 #define GTK_WIDGET_SET_FLAGS(wid,flag)	  G_STMT_START{ (GTK_WIDGET_FLAGS (wid) |= (flag)); }G_STMT_END
 #define GTK_WIDGET_UNSET_FLAGS(wid,flag)  G_STMT_START{ (GTK_WIDGET_FLAGS (wid) &= ~(flag)); }G_STMT_END
 
+gint gtk_widget_size_to_pixel (gpointer widget, GtkSize size);
+gdouble gtk_widget_size_to_pixel_double (gpointer widget, GtkSize size);
+
 #define GTK_TYPE_REQUISITION              (gtk_requisition_get_type ())
 
 /* forward declaration to avoid excessive includes (and concurrent includes)
@@ -425,8 +428,10 @@ struct _GtkWidgetClass
    *                             GdkEventExpose *event);
    */
 
+  /* subclasses MUST chain up to their parent class */
+  void         (* unit_changed) (GtkWidget *widget);
+
   /* Padding for future expansion */
-  void (*_gtk_reserved5) (void);
   void (*_gtk_reserved6) (void);
   void (*_gtk_reserved7) (void);
 };
@@ -435,8 +440,8 @@ struct _GtkWidgetAuxInfo
 {
   gint x;
   gint y;
-  gint width;
-  gint height;
+  GtkSize width;
+  GtkSize height;
   guint x_set : 1;
   guint y_set : 1;
 };
@@ -583,18 +588,21 @@ gboolean   gtk_widget_keynav_failed       (GtkWidget           *widget,
 void       gtk_widget_error_bell          (GtkWidget           *widget);
 
 void       gtk_widget_set_size_request    (GtkWidget           *widget,
-                                           gint                 width,
-                                           gint                 height);
+                                           GtkSize              width,
+                                           GtkSize              height);
 void       gtk_widget_get_size_request    (GtkWidget           *widget,
                                            gint                *width,
                                            gint                *height);
+void       gtk_widget_get_size_request_unit (GtkWidget           *widget,
+                                             GtkSize             *width,
+                                             GtkSize             *height);
 #ifndef GTK_DISABLE_DEPRECATED
 void	   gtk_widget_set_uposition	  (GtkWidget	       *widget,
 					   gint			x,
 					   gint			y);
 void	   gtk_widget_set_usize		  (GtkWidget	       *widget,
-					   gint			width,
-					   gint			height);
+					   GtkSize		width,
+					   GtkSize		height);
 #endif
 
 void	   gtk_widget_set_events	  (GtkWidget	       *widget,
@@ -742,6 +750,23 @@ void gtk_widget_style_get          (GtkWidget	     *widget,
 				    const gchar    *first_property_name,
 				    ...) G_GNUC_NULL_TERMINATED;
 
+void gtk_widget_style_get_property_unit (GtkWidget	     *widget,
+                                         const gchar    *property_name,
+                                         GValue	     *value);
+void gtk_widget_style_get_unit_valist   (GtkWidget	     *widget,
+                                         const gchar    *first_property_name,
+                                         va_list         var_args);
+void gtk_widget_style_get_unit (GtkWidget	     *widget,
+                                const gchar    *first_property_name,
+                                ...) G_GNUC_NULL_TERMINATED;
+
+void gtk_widget_get_unit_valist (GtkWidget *object,
+                                 const gchar *first_property_name,
+                                 va_list	  var_args);
+
+void gtk_widget_get_unit (gpointer object,
+                          const gchar *first_property_name,
+                          ...)  G_GNUC_NULL_TERMINATED;
 
 gint gtk_widget_get_monitor_num (GtkWidget *widget);
 
@@ -832,6 +857,7 @@ void              _gtk_widget_propagate_hierarchy_changed (GtkWidget    *widget,
 void              _gtk_widget_propagate_screen_changed    (GtkWidget    *widget,
 							   GdkScreen    *previous_screen);
 void		  _gtk_widget_propagate_composited_changed (GtkWidget    *widget);
+void              _gtk_widget_propagate_unit_changed      (GtkWidget    *widget);
 
 void	   _gtk_widget_set_pointer_window  (GtkWidget      *widget,
 					    GdkWindow      *pointer_window);
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 3ecf507..3293917 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -145,8 +145,8 @@ struct _GtkWindowGeometryInfo
   /* Default size - used only the FIRST time we map a window,
    * only if > 0.
    */
-  gint           default_width; 
-  gint           default_height;
+  GtkSize        default_width; 
+  GtkSize        default_height;
   /* whether to use initial_x, initial_y */
   guint          initial_pos_set : 1;
   /* CENTER_ALWAYS or other position constraint changed since
@@ -283,9 +283,9 @@ static void     gtk_window_compute_configure_request (GtkWindow    *window,
 
 static void     gtk_window_set_default_size_internal (GtkWindow    *window,
                                                       gboolean      change_width,
-                                                      gint          width,
+                                                      GtkSize       width,
                                                       gboolean      change_height,
-                                                      gint          height,
+                                                      GtkSize       height,
 						      gboolean      is_geometry);
 
 static void     update_themed_icon                    (GtkIconTheme *theme,
@@ -302,6 +302,13 @@ static void	   gtk_window_on_composited_changed (GdkScreen *screen,
 						     GtkWindow *window);
 static void gtk_window_update_monitor_num (GtkWindow *window);
 
+static void gtk_window_on_unit_changed (GtkSettings *settings,
+                                        gint         monitor_number,
+                                        GtkWindow   *window);
+
+static int get_monitor_containing_pointer (GtkWindow *window);
+
+
 
 static GSList      *toplevel_list = NULL;
 static guint        window_signals[LAST_SIGNAL] = { 0 };
@@ -563,23 +570,19 @@ gtk_window_class_init (GtkWindowClass *klass)
  
   g_object_class_install_property (gobject_class,
                                    PROP_DEFAULT_WIDTH,
-                                   g_param_spec_int ("default-width",
-						     P_("Default Width"),
-						     P_("The default width of the window, used when initially showing the window"),
-						     -1,
-						     G_MAXINT,
-						     -1,
-						     GTK_PARAM_READWRITE));
+                                   gtk_param_spec_size ("default-width",
+                                                        P_("Default Width"),
+                                                        P_("The default width of the window, used when initially showing the window"),
+                                                        -1, G_MAXINT, -1,
+                                                        GTK_PARAM_READWRITE));
   
   g_object_class_install_property (gobject_class,
                                    PROP_DEFAULT_HEIGHT,
-                                   g_param_spec_int ("default-height",
-						     P_("Default Height"),
-						     P_("The default height of the window, used when initially showing the window"),
-						     -1,
-						     G_MAXINT,
-						     -1,
-						     GTK_PARAM_READWRITE));
+                                   gtk_param_spec_size ("default-height",
+                                                        P_("Default Height"),
+                                                        P_("The default height of the window, used when initially showing the window"),
+                                                        -1, G_MAXINT, -1,
+                                                        GTK_PARAM_READWRITE));
   
   g_object_class_install_property (gobject_class,
                                    PROP_DESTROY_WITH_PARENT,
@@ -966,6 +969,20 @@ gtk_window_init (GtkWindow *window)
 
   g_signal_connect (window->screen, "composited-changed",
 		    G_CALLBACK (gtk_window_on_composited_changed), window);
+  g_signal_connect (gtk_settings_get_for_screen (window->screen),
+                    "unit-changed",
+                    G_CALLBACK (gtk_window_on_unit_changed),
+                    window);
+}
+
+static void
+gtk_window_on_unit_changed (GtkSettings *settings,
+                            gint         monitor_number,
+                            GtkWindow   *window)
+{
+  GtkWidget *widget = GTK_WIDGET (window);
+  if (gtk_widget_get_monitor_num (widget) == monitor_number)
+    _gtk_widget_propagate_unit_changed (widget);
 }
 
 static void
@@ -1014,13 +1031,13 @@ gtk_window_set_property (GObject      *object,
       break;
     case PROP_DEFAULT_WIDTH:
       gtk_window_set_default_size_internal (window,
-                                            TRUE, g_value_get_int (value),
+                                            TRUE, gtk_value_get_size (value),
                                             FALSE, -1, FALSE);
       break;
     case PROP_DEFAULT_HEIGHT:
       gtk_window_set_default_size_internal (window,
                                             FALSE, -1,
-                                            TRUE, g_value_get_int (value), FALSE);
+                                            TRUE, gtk_value_get_size (value), FALSE);
       break;
     case PROP_DESTROY_WITH_PARENT:
       gtk_window_set_destroy_with_parent (window, g_value_get_boolean (value));
@@ -1122,16 +1139,16 @@ gtk_window_get_property (GObject      *object,
     case PROP_DEFAULT_WIDTH:
       info = gtk_window_get_geometry_info (window, FALSE);
       if (!info)
-	g_value_set_int (value, -1);
+	gtk_value_set_size (value, -1, window);
       else
-	g_value_set_int (value, info->default_width);
+	gtk_value_set_size (value, info->default_width, window);
       break;
     case PROP_DEFAULT_HEIGHT:
       info = gtk_window_get_geometry_info (window, FALSE);
       if (!info)
-	g_value_set_int (value, -1);
+	gtk_value_set_size (value, -1, window);
       else
-	g_value_set_int (value, info->default_height);
+	gtk_value_set_size (value, info->default_height, window);
       break;
     case PROP_DESTROY_WITH_PARENT:
       g_value_set_boolean (value, window->destroy_with_parent);
@@ -3856,9 +3873,9 @@ gtk_window_get_default_icon_list (void)
 static void
 gtk_window_set_default_size_internal (GtkWindow    *window,
                                       gboolean      change_width,
-                                      gint          width,
+                                      GtkSize       width,
                                       gboolean      change_height,
-                                      gint          height,
+                                      GtkSize       height,
 				      gboolean      is_geometry)
 {
   GtkWindowGeometryInfo *info;
@@ -3940,8 +3957,8 @@ gtk_window_set_default_size_internal (GtkWindow    *window,
  **/
 void       
 gtk_window_set_default_size (GtkWindow   *window,
-			     gint         width,
-			     gint         height)
+			     GtkSize      width,
+			     GtkSize      height)
 {
   g_return_if_fail (GTK_IS_WINDOW (window));
   g_return_if_fail (width >= -1);
@@ -3974,6 +3991,34 @@ gtk_window_get_default_size (GtkWindow *window,
   info = gtk_window_get_geometry_info (window, FALSE);
 
   if (width)
+    *width = info ? gtk_widget_size_to_pixel (window, info->default_width) : -1;
+
+  if (height)
+    *height = info ? gtk_widget_size_to_pixel (window, info->default_height) : -1;
+}
+
+/**
+ * gtk_window_get_default_size_unit:
+ * @window: a #GtkWindow
+ * @width: location to store the default width, or %NULL
+ * @height: location to store the default height, or %NULL
+ *
+ * Like gtk_window_get_default_size() but preserves the unit.
+ *
+ * Since: 2.14
+ **/
+void
+gtk_window_get_default_size_unit (GtkWindow *window,
+                                  GtkSize   *width,
+                                  GtkSize   *height)
+{
+  GtkWindowGeometryInfo *info;
+
+  g_return_if_fail (GTK_IS_WINDOW (window));
+
+  info = gtk_window_get_geometry_info (window, FALSE);
+
+  if (width)
     *width = info ? info->default_width : -1;
 
   if (height)
@@ -4457,6 +4502,8 @@ gtk_window_finalize (GObject *object)
     {
       g_signal_handlers_disconnect_by_func (window->screen,
 					    gtk_window_on_composited_changed, window);
+      g_signal_handlers_disconnect_by_func (gtk_settings_get_for_screen (window->screen),
+					    gtk_window_on_unit_changed, window);
     }
       
   G_OBJECT_CLASS (gtk_window_parent_class)->finalize (object);
@@ -4466,6 +4513,7 @@ static void
 gtk_window_show (GtkWidget *widget)
 {
   GtkWindow *window = GTK_WINDOW (widget);
+  GtkWindowPrivate *priv = GTK_WINDOW_GET_PRIVATE (window);
   GtkContainer *container = GTK_CONTAINER (window);
   gboolean need_resize;
 
@@ -4483,6 +4531,20 @@ gtk_window_show (GtkWidget *widget)
       guint new_flags;
       gboolean was_realized;
 
+      /* For unit to pixel conversions, which is needed for doing
+       * size_allocate(), we really need to know the monitor since
+       * that affects the conversion - so if the monitor is not
+       * currently set, take the one the pointer is on... if we get it
+       * wrong then monitor_num is updated every time we get a
+       * configure event.
+       */
+      if (priv->monitor_num == -1)
+        {
+          priv->monitor_num = get_monitor_containing_pointer (window);
+          /* also update the widget since we're "on" a new monitor now */
+          _gtk_widget_propagate_unit_changed (GTK_WIDGET (window));
+        }
+
       /* We are going to go ahead and perform this configure request
        * and then emulate a configure notify by going ahead and
        * doing a size allocate. Sort of a synchronous
@@ -5054,6 +5116,9 @@ gtk_window_update_monitor_num (GtkWindow *window)
     {
       /*g_debug ("monitor num changed from %d to %d for top-level %p (screen %p)", prev_monitor_num, priv->monitor_num, window, window->screen);*/
       g_object_notify (G_OBJECT (window), "monitor-num");
+
+      /* new monitor -> units might have changed */
+      _gtk_widget_propagate_unit_changed (GTK_WIDGET (window));
     }
 }
 
@@ -5650,6 +5715,10 @@ gtk_window_compute_configure_request_size (GtkWindow *window,
 	   gint min_height = 0;
 	   gint width_inc = 1;
 	   gint height_inc = 1;
+           GdkScreen *screen;
+           gint monitor_num;
+           gint pixel_width;
+           gint pixel_height;
 	   
 	   if (info->default_is_geometry &&
 	       (info->default_width > 0 || info->default_height > 0))
@@ -5676,11 +5745,22 @@ gtk_window_compute_configure_request_size (GtkWindow *window,
 		 }
 	     }
 	     
+           /* Catch 22. The default size may be in units but those in
+            * turn depend on the screen/monitor the window belongs
+            * to. Which we don't yet know. For now use the monitor
+            * containing the pointer for converting from units to
+            * pixels
+            */
+           screen = gtk_window_check_screen (window);
+           monitor_num = get_monitor_containing_pointer (window);
+           pixel_width = gtk_size_to_pixel (screen, monitor_num, info->default_width);
+           pixel_height = gtk_size_to_pixel (screen, monitor_num, info->default_height);
+             
 	   if (info->default_width > 0)
-	     *width = MAX (info->default_width * width_inc + base_width, min_width);
+	     *width = MAX (pixel_width * width_inc + base_width, min_width);
 	   
 	   if (info->default_height > 0)
-	     *height = MAX (info->default_height * height_inc + base_height, min_height);
+	     *height = MAX (pixel_height * height_inc + base_height, min_height);
          }
     }
   else
@@ -7477,6 +7557,15 @@ gtk_window_set_screen (GtkWindow *window,
       g_signal_connect (screen, "composited-changed", 
 			G_CALLBACK (gtk_window_on_composited_changed), window);
       
+      g_signal_handlers_disconnect_by_func (gtk_settings_get_for_screen (previous_screen),
+					    gtk_window_on_unit_changed, window);
+      g_signal_connect (gtk_settings_get_for_screen (window->screen),
+                        "unit-changed",
+                        G_CALLBACK (gtk_window_on_unit_changed),
+                        window);
+
+      gtk_window_update_monitor_num (window);
+
       _gtk_widget_propagate_screen_changed (widget, previous_screen);
       _gtk_widget_propagate_composited_changed (widget);
     }
diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h
index 06d1553..bee0eb1 100644
--- a/gtk/gtkwindow.h
+++ b/gtk/gtkwindow.h
@@ -361,11 +361,14 @@ void       gtk_window_set_policy               (GtkWindow           *window,
  * resize operations)
  */
 void     gtk_window_set_default_size (GtkWindow   *window,
-                                      gint         width,
-                                      gint         height);
+                                      GtkSize      width,
+                                      GtkSize      height);
 void     gtk_window_get_default_size (GtkWindow   *window,
                                       gint        *width,
                                       gint        *height);
+void     gtk_window_get_default_size_unit (GtkWindow   *window,
+                                           GtkSize     *width,
+                                           GtkSize     *height);
 void     gtk_window_resize           (GtkWindow   *window,
                                       gint         width,
                                       gint         height);



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