[gtk+/resolution-independence: 3/24] add core resolution independence code
- From: Davyd Madeley <davyd src gnome org>
- To: svn-commits-list gnome org
- Subject: [gtk+/resolution-independence: 3/24] add core resolution independence code
- Date: Sat, 2 May 2009 02:17:16 -0400 (EDT)
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]