diff --git a/gdk/gdkmonitor.c b/gdk/gdkmonitor.c index b99408696e..685a5ad62f 100644 --- a/gdk/gdkmonitor.c +++ b/gdk/gdkmonitor.c @@ -26,6 +26,8 @@ #include "gdkenumtypes.h" #include "gdkrectangle.h" +#include + /** * GdkMonitor: * @@ -46,6 +48,7 @@ enum { PROP_MODEL, PROP_CONNECTOR, PROP_SCALE_FACTOR, + PROP_SCALE, PROP_GEOMETRY, PROP_WIDTH_MM, PROP_HEIGHT_MM, @@ -70,6 +73,8 @@ static void gdk_monitor_init (GdkMonitor *monitor) { monitor->scale_factor = 1; + monitor->scale = 1.0; + monitor->scale_set = FALSE; monitor->valid = TRUE; } @@ -107,6 +112,10 @@ gdk_monitor_get_property (GObject *object, g_value_set_int (value, monitor->scale_factor); break; + case PROP_SCALE: + g_value_set_double (value, monitor->scale); + break; + case PROP_GEOMETRY: g_value_set_boxed (value, &monitor->geometry); break; @@ -233,13 +242,28 @@ gdk_monitor_class_init (GdkMonitorClass *class) * GdkMonitor:scale-factor: (attributes org.gtk.Property.get=gdk_monitor_get_scale_factor) * * The scale factor. + * + * The scale factor is the next larger integer, + * compared to [property@Gdk.Surface:scale]. */ props[PROP_SCALE_FACTOR] = g_param_spec_int ("scale-factor", NULL, NULL, - 0, G_MAXINT, + 1, G_MAXINT, 1, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + /** + * GdkMonitor:scale: (attributes org.gtk.Property.get=gdk_monitor_get_scale) + * + * The scale of the monitor. + * + * Since: 4.14 + */ + props[PROP_SCALE] = + g_param_spec_double ("scale", NULL, NULL, + 1., G_MAXDOUBLE, 1., + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + /** * GdkMonitor:geometry: (attributes org.gtk.Property.get=gdk_monitor_get_geometry) * @@ -346,7 +370,7 @@ gdk_monitor_get_display (GdkMonitor *monitor) * display coordinate space. * * The returned geometry is in ”application pixels”, not in - * ”device pixels” (see [method@Gdk.Monitor.get_scale_factor]). + * ”device pixels” (see [method@Gdk.Monitor.get_scale]). */ void gdk_monitor_get_geometry (GdkMonitor *monitor, @@ -472,6 +496,29 @@ gdk_monitor_get_scale_factor (GdkMonitor *monitor) return monitor->scale_factor; } +/** + * gdk_monitor_get_scale: (attributes org.gtk.Method.get_property=scale) + * @monitor: a `GdkMonitor` + * + * Gets the internal scale factor that maps from monitor coordinates + * to device pixels. + * + * This can be used if you want to create pixel based data for a + * particular monitor, but most of the time you’re drawing to a surface + * where it is better to use [method@Gdk.Surface.get_scale] instead. + * + * Returns: the scale + * + * Since: 4.14 + */ +double +gdk_monitor_get_scale (GdkMonitor *monitor) +{ + g_return_val_if_fail (GDK_IS_MONITOR (monitor), 1.); + + return monitor->scale; +} + /** * gdk_monitor_get_refresh_rate: (attributes org.gtk.Method.get_property=refresh-rate) * @monitor: a `GdkMonitor` @@ -583,12 +630,37 @@ void gdk_monitor_set_scale_factor (GdkMonitor *monitor, int scale_factor) { + g_return_if_fail (scale_factor >= 1); + + if (monitor->scale_set) + return; + if (monitor->scale_factor == scale_factor) return; monitor->scale_factor = scale_factor; + monitor->scale = scale_factor; g_object_notify (G_OBJECT (monitor), "scale-factor"); + g_object_notify (G_OBJECT (monitor), "scale"); +} + +void +gdk_monitor_set_scale (GdkMonitor *monitor, + double scale) +{ + g_return_if_fail (scale >= 1.); + + monitor->scale_set = TRUE; + + if (monitor->scale == scale) + return; + + monitor->scale = scale; + monitor->scale_factor = (int) ceil (scale); + + g_object_notify (G_OBJECT (monitor), "scale"); + g_object_notify (G_OBJECT (monitor), "scale-factor"); } void diff --git a/gdk/gdkmonitor.h b/gdk/gdkmonitor.h index 1cdb4f9a3e..6d99c6d2bc 100644 --- a/gdk/gdkmonitor.h +++ b/gdk/gdkmonitor.h @@ -77,6 +77,8 @@ GDK_AVAILABLE_IN_ALL const char * gdk_monitor_get_connector (GdkMonitor *monitor); GDK_AVAILABLE_IN_ALL int gdk_monitor_get_scale_factor (GdkMonitor *monitor); +GDK_AVAILABLE_IN_4_14 +double gdk_monitor_get_scale (GdkMonitor *monitor); GDK_AVAILABLE_IN_ALL int gdk_monitor_get_refresh_rate (GdkMonitor *monitor); GDK_AVAILABLE_IN_ALL diff --git a/gdk/gdkmonitorprivate.h b/gdk/gdkmonitorprivate.h index 2a48ae1e28..a696fbce3c 100644 --- a/gdk/gdkmonitorprivate.h +++ b/gdk/gdkmonitorprivate.h @@ -44,6 +44,8 @@ struct _GdkMonitor { int refresh_rate; GdkSubpixelLayout subpixel_layout; gboolean valid; + double scale; + gboolean scale_set; }; struct _GdkMonitorClass { @@ -64,7 +66,9 @@ void gdk_monitor_set_physical_size (GdkMonitor *monitor, int width_mm, int height_mm); void gdk_monitor_set_scale_factor (GdkMonitor *monitor, - int scale); + int scale_factor); +void gdk_monitor_set_scale (GdkMonitor *monitor, + double scale); void gdk_monitor_set_refresh_rate (GdkMonitor *monitor, int refresh_rate); void gdk_monitor_set_subpixel_layout (GdkMonitor *monitor, diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index d205ca5b10..b767359e10 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -2430,15 +2430,47 @@ apply_monitor_change (GdkWaylandMonitor *monitor) { GDK_DEBUG (MISC, "monitor %d changed position %d %d, size %d %d", monitor->id, - monitor->x, monitor->y, - monitor->width, monitor->height); + monitor->output_geometry.x, monitor->output_geometry.y, + monitor->output_geometry.width, monitor->output_geometry.height); - gdk_monitor_set_geometry (GDK_MONITOR (monitor), - &(GdkRectangle) { - monitor->x, monitor->y, - monitor->width, monitor->height }); + GdkRectangle logical_geometry; + gboolean needs_scaling = FALSE; + double scale; + + if (monitor->xdg_output_done) + { + logical_geometry = monitor->xdg_output_geometry; + needs_scaling = + logical_geometry.width == monitor->output_geometry.width || + logical_geometry.height == monitor->output_geometry.height; + } + else + { + logical_geometry = monitor->output_geometry; + needs_scaling = TRUE; + } + + if (needs_scaling) + { + int scale_factor = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor)); + logical_geometry.y /= scale_factor; + logical_geometry.x /= scale_factor; + logical_geometry.width /= scale_factor; + logical_geometry.height /= scale_factor; + + scale = scale_factor; + } + else + { + scale = MAX (monitor->output_geometry.width / (double) logical_geometry.width, + monitor->output_geometry.height / (double) logical_geometry.height); + } + + gdk_monitor_set_geometry (GDK_MONITOR (monitor), &logical_geometry); gdk_monitor_set_connector (GDK_MONITOR (monitor), monitor->name); gdk_monitor_set_description (GDK_MONITOR (monitor), monitor->description); + gdk_monitor_set_scale (GDK_MONITOR (monitor), scale); + monitor->wl_output_done = FALSE; monitor->xdg_output_done = FALSE; @@ -2456,8 +2488,8 @@ xdg_output_handle_logical_position (void *data, GDK_DEBUG (MISC, "handle logical position xdg-output %d, position %d %d", monitor->id, x, y); - monitor->x = x; - monitor->y = y; + monitor->xdg_output_geometry.x = x; + monitor->xdg_output_geometry.y = y; } static void @@ -2471,8 +2503,8 @@ xdg_output_handle_logical_size (void *data, GDK_DEBUG (MISC, "handle logical size xdg-output %d, size %d %d", monitor->id, width, height); - monitor->width = width; - monitor->height = height; + monitor->xdg_output_geometry.width = width; + monitor->xdg_output_geometry.height = height; } static void @@ -2558,8 +2590,8 @@ output_handle_geometry (void *data, make, model, transform_to_string (transform)); - monitor->x = x; - monitor->y = y; + monitor->output_geometry.x = x; + monitor->output_geometry.y = y; switch (transform) { @@ -2603,28 +2635,12 @@ output_handle_scale (void *data, int32_t scale) { GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data; - GdkRectangle previous_geometry; - int previous_scale; - int width; - int height; GDK_DEBUG (MISC, "handle scale output %d, scale %d", monitor->id, scale); - gdk_monitor_get_geometry (GDK_MONITOR (monitor), &previous_geometry); - previous_scale = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor)); - /* Set the scale from wl_output protocol, regardless of xdg-output support */ gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), scale); - if (monitor_has_xdg_output (monitor)) - return; - - width = previous_geometry.width * previous_scale; - height = previous_geometry.height * previous_scale; - - monitor->width = width / scale; - monitor->height = height / scale; - if (should_update_monitor (monitor)) apply_monitor_change (monitor); } @@ -2638,7 +2654,6 @@ output_handle_mode (void *data, int refresh) { GdkWaylandMonitor *monitor = (GdkWaylandMonitor *)data; - int scale; GDK_DEBUG (MISC, "handle mode output %d, size %d %d, rate %d", monitor->id, width, height, refresh); @@ -2646,9 +2661,8 @@ output_handle_mode (void *data, if ((flags & WL_OUTPUT_MODE_CURRENT) == 0) return; - scale = gdk_monitor_get_scale_factor (GDK_MONITOR (monitor)); - monitor->width = width / scale; - monitor->height = height / scale; + monitor->output_geometry.width = width; + monitor->output_geometry.height = height; gdk_monitor_set_refresh_rate (GDK_MONITOR (monitor), refresh); if (should_update_monitor (monitor) || !monitor_has_xdg_output (monitor)) diff --git a/gdk/wayland/gdkmonitor-wayland.h b/gdk/wayland/gdkmonitor-wayland.h index a9658cd8cc..a6950303df 100644 --- a/gdk/wayland/gdkmonitor-wayland.h +++ b/gdk/wayland/gdkmonitor-wayland.h @@ -31,11 +31,10 @@ struct _GdkWaylandMonitor { gboolean added; struct zxdg_output_v1 *xdg_output; - /* Size and position, can be either from wl_output or xdg_output */ - int32_t x; - int32_t y; - int32_t width; - int32_t height; + /* Raw wl_output data */ + GdkRectangle output_geometry; + /* Raw xdg_output data */ + GdkRectangle xdg_output_geometry; char *name; char *description; gboolean wl_output_done; diff --git a/gtk/inspector/general.c b/gtk/inspector/general.c index c485dd4388..c5b218c4c9 100644 --- a/gtk/inspector/general.c +++ b/gtk/inspector/general.c @@ -730,7 +730,7 @@ add_monitor (GtkInspectorGeneral *gen, GtkListBox *list; char *value; GdkRectangle rect; - int scale; + double scale; char *name; char *scale_str = NULL; const char *manufacturer; @@ -753,9 +753,9 @@ add_monitor (GtkInspectorGeneral *gen, add_label_row (gen, list, "Connector", gdk_monitor_get_connector (monitor), 10); gdk_monitor_get_geometry (monitor, &rect); - scale = gdk_monitor_get_scale_factor (monitor); - if (scale != 1) - scale_str = g_strdup_printf (" @ %d", scale); + scale = gdk_monitor_get_scale (monitor); + if (scale != 1.0) + scale_str = g_strdup_printf (" @ %.2f", scale); value = g_strdup_printf ("%d × %d%s at %d, %d", rect.width, rect.height, @@ -765,6 +765,12 @@ add_monitor (GtkInspectorGeneral *gen, g_free (value); g_free (scale_str); + value = g_strdup_printf ("%d × %d", + (int) (rect.width * scale), + (int) (rect.height * scale)); + add_label_row (gen, list, "Pixels", value, 10); + g_free (value); + value = g_strdup_printf ("%d × %d mm²", gdk_monitor_get_width_mm (monitor), gdk_monitor_get_height_mm (monitor));