diff --git a/gdk/macos/gdkdisplaylinksource.c b/gdk/macos/gdkdisplaylinksource.c
index 292b8be519..6a613b40a4 100644
--- a/gdk/macos/gdkdisplaylinksource.c
+++ b/gdk/macos/gdkdisplaylinksource.c
@@ -26,7 +26,9 @@
#include "gdkdisplaylinksource.h"
+#include "gdkdebug.h"
#include "gdkmacoseventsource-private.h"
+#include "gdkmacosmonitor-private.h"
#include "gdk-private.h"
static gint64 host_to_frame_clock_time (gint64 val);
@@ -65,7 +67,7 @@ gdk_display_link_source_dispatch (GSource *source,
impl->needs_dispatch = FALSE;
- if (callback != NULL)
+ if (!impl->paused && callback != NULL)
ret = callback (user_data);
return ret;
@@ -76,7 +78,9 @@ gdk_display_link_source_finalize (GSource *source)
{
GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
- CVDisplayLinkStop (impl->display_link);
+ if (!impl->paused)
+ CVDisplayLinkStop (impl->display_link);
+
CVDisplayLinkRelease (impl->display_link);
}
@@ -90,12 +94,18 @@ static GSourceFuncs gdk_display_link_source_funcs = {
void
gdk_display_link_source_pause (GdkDisplayLinkSource *source)
{
+ g_return_if_fail (source->paused == FALSE);
+
+ source->paused = TRUE;
CVDisplayLinkStop (source->display_link);
}
void
gdk_display_link_source_unpause (GdkDisplayLinkSource *source)
{
+ g_return_if_fail (source->paused == TRUE);
+
+ source->paused = FALSE;
CVDisplayLinkStart (source->display_link);
}
@@ -147,6 +157,7 @@ gdk_display_link_source_frame_cb (CVDisplayLinkRef display_link,
/**
* gdk_display_link_source_new:
+ * @display_id: the identifier of the monitor
*
* Creates a new `GSource` that will activate the dispatch function upon
* notification from a CVDisplayLink that a new frame should be drawn.
@@ -159,41 +170,61 @@ gdk_display_link_source_frame_cb (CVDisplayLinkRef display_link,
* Returns: (transfer full): A newly created `GSource`
*/
GSource *
-gdk_display_link_source_new (void)
+gdk_display_link_source_new (CGDirectDisplayID display_id,
+ CGDisplayModeRef mode)
{
GdkDisplayLinkSource *impl;
GSource *source;
- CVReturn ret;
- double period;
+ char *name;
source = g_source_new (&gdk_display_link_source_funcs, sizeof *impl);
impl = (GdkDisplayLinkSource *)source;
+ impl->display_id = display_id;
+ impl->paused = TRUE;
- /*
- * Create our link based on currently connected displays.
- * If there are multiple displays, this will be something that tries
- * to work for all of them. In the future, we may want to explore multiple
- * links based on the connected displays.
+ /* Create DisplayLink for timing information for the display in
+ * question so that we can produce graphics for that display at whatever
+ * rate it can provide.
*/
- ret = CVDisplayLinkCreateWithActiveCGDisplays (&impl->display_link);
- if (ret != kCVReturnSuccess)
+ if (CVDisplayLinkCreateWithCGDisplay (display_id, &impl->display_link) != kCVReturnSuccess)
{
g_warning ("Failed to initialize CVDisplayLink!");
- return source;
+ goto failure;
}
- /*
- * Determine our nominal period between frames.
- */
- period = CVDisplayLinkGetActualOutputVideoRefreshPeriod (impl->display_link);
- if (period == 0.0)
- period = 1.0 / 60.0;
- impl->refresh_interval = period * 1000000L;
- impl->refresh_rate = 1.0 / period * 1000L;
+ impl->refresh_rate = CGDisplayModeGetRefreshRate (mode) * 1000.0;
- /*
- * Wire up our callback to be executed within the high-priority thread.
- */
+ if (impl->refresh_rate == 0)
+ {
+ const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod (impl->display_link);
+ if (!(time.flags & kCVTimeIsIndefinite))
+ impl->refresh_rate = (double)time.timeScale / (double)time.timeValue * 1000.0;
+ }
+
+ if (impl->refresh_rate != 0)
+ {
+ impl->refresh_interval = 1000000.0 / (double)impl->refresh_rate * 1000.0;
+ }
+ else
+ {
+ double period = CVDisplayLinkGetActualOutputVideoRefreshPeriod (impl->display_link);
+
+ if (period == 0.0)
+ period = 1.0 / 60.0;
+
+ impl->refresh_rate = 1.0 / period * 1000L;
+ impl->refresh_interval = period * 1000000L;
+ }
+
+ name = _gdk_macos_monitor_get_connector_name (display_id);
+ GDK_NOTE (MISC,
+ g_message ("Monitor \"%s\" discovered with Refresh Rate %d and Interval %"G_GINT64_FORMAT,
+ name ? name : "unknown",
+ impl->refresh_rate,
+ impl->refresh_interval));
+ g_free (name);
+
+ /* Wire up our callback to be executed within the high-priority thread. */
CVDisplayLinkSetOutputCallback (impl->display_link,
gdk_display_link_source_frame_cb,
source);
@@ -201,6 +232,10 @@ gdk_display_link_source_new (void)
g_source_set_static_name (source, "[gdk] quartz frame clock");
return source;
+
+failure:
+ g_source_unref (source);
+ return NULL;
}
static gint64
diff --git a/gdk/macos/gdkdisplaylinksource.h b/gdk/macos/gdkdisplaylinksource.h
index ed769b59f8..6f465907a2 100644
--- a/gdk/macos/gdkdisplaylinksource.h
+++ b/gdk/macos/gdkdisplaylinksource.h
@@ -30,17 +30,20 @@ G_BEGIN_DECLS
typedef struct
{
- GSource source;
+ GSource source;
- CVDisplayLinkRef display_link;
- gint64 refresh_interval;
- guint refresh_rate;
+ CGDirectDisplayID display_id;
+ CVDisplayLinkRef display_link;
+ gint64 refresh_interval;
+ guint refresh_rate;
+ guint paused : 1;
- volatile gint64 presentation_time;
- volatile guint needs_dispatch;
+ volatile gint64 presentation_time;
+ volatile guint needs_dispatch;
} GdkDisplayLinkSource;
-GSource *gdk_display_link_source_new (void);
+GSource *gdk_display_link_source_new (CGDirectDisplayID display_id,
+ CGDisplayModeRef mode);
void gdk_display_link_source_pause (GdkDisplayLinkSource *source);
void gdk_display_link_source_unpause (GdkDisplayLinkSource *source);
diff --git a/gdk/macos/gdkmacosbuffer-private.h b/gdk/macos/gdkmacosbuffer-private.h
index 6be201147c..4b446a7212 100644
--- a/gdk/macos/gdkmacosbuffer-private.h
+++ b/gdk/macos/gdkmacosbuffer-private.h
@@ -41,6 +41,8 @@ GdkMacosBuffer *_gdk_macos_buffer_new (int width
IOSurfaceRef _gdk_macos_buffer_get_native (GdkMacosBuffer *self);
void _gdk_macos_buffer_lock (GdkMacosBuffer *self);
void _gdk_macos_buffer_unlock (GdkMacosBuffer *self);
+void _gdk_macos_buffer_read_lock (GdkMacosBuffer *self);
+void _gdk_macos_buffer_read_unlock (GdkMacosBuffer *self);
guint _gdk_macos_buffer_get_width (GdkMacosBuffer *self);
guint _gdk_macos_buffer_get_height (GdkMacosBuffer *self);
guint _gdk_macos_buffer_get_stride (GdkMacosBuffer *self);
diff --git a/gdk/macos/gdkmacosbuffer.c b/gdk/macos/gdkmacosbuffer.c
index ac99302ee4..eb8a719dbc 100644
--- a/gdk/macos/gdkmacosbuffer.c
+++ b/gdk/macos/gdkmacosbuffer.c
@@ -192,6 +192,45 @@ _gdk_macos_buffer_unlock (GdkMacosBuffer *self)
IOSurfaceUnlock (self->surface, 0, NULL);
}
+/**
+ * _gdk_macos_buffer_lock_readonly:
+ *
+ * Like _gdk_macos_buffer_lock() but uses the read-only flag to
+ * indicate we are not interested in retrieving the updates from
+ * the GPU before modifying the CPU-side cache.
+ *
+ * Must be used with _gdk_macos_buffer_unlock_readonly().
+ */
+void
+_gdk_macos_buffer_read_lock (GdkMacosBuffer *self)
+{
+ kern_return_t ret;
+
+ g_return_if_fail (GDK_IS_MACOS_BUFFER (self));
+ g_return_if_fail (self->lock_count == 0);
+
+ self->lock_count++;
+
+ ret = IOSurfaceLock (self->surface, kIOSurfaceLockReadOnly, NULL);
+
+ g_return_if_fail (ret == KERN_SUCCESS);
+}
+
+void
+_gdk_macos_buffer_read_unlock (GdkMacosBuffer *self)
+{
+ kern_return_t ret;
+
+ g_return_if_fail (GDK_IS_MACOS_BUFFER (self));
+ g_return_if_fail (self->lock_count == 1);
+
+ self->lock_count--;
+
+ ret = IOSurfaceUnlock (self->surface, kIOSurfaceLockReadOnly, NULL);
+
+ g_return_if_fail (ret == KERN_SUCCESS);
+}
+
guint
_gdk_macos_buffer_get_width (GdkMacosBuffer *self)
{
@@ -242,7 +281,7 @@ _gdk_macos_buffer_set_damage (GdkMacosBuffer *self,
return;
g_clear_pointer (&self->damage, cairo_region_destroy);
- self->damage = cairo_region_reference (damage);
+ self->damage = cairo_region_copy (damage);
}
gpointer
diff --git a/gdk/macos/gdkmacoscairocontext.c b/gdk/macos/gdkmacoscairocontext.c
index 041f1193e6..31eecd5df6 100644
--- a/gdk/macos/gdkmacoscairocontext.c
+++ b/gdk/macos/gdkmacoscairocontext.c
@@ -42,19 +42,6 @@ struct _GdkMacosCairoContextClass
G_DEFINE_TYPE (GdkMacosCairoContext, _gdk_macos_cairo_context, GDK_TYPE_CAIRO_CONTEXT)
-static const cairo_user_data_key_t buffer_key;
-
-static void
-unlock_buffer (gpointer data)
-{
- GdkMacosBuffer *buffer = data;
-
- g_assert (GDK_IS_MACOS_BUFFER (buffer));
-
- _gdk_macos_buffer_unlock (buffer);
- g_clear_object (&buffer);
-}
-
static cairo_t *
_gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context)
{
@@ -106,12 +93,9 @@ _gdk_macos_cairo_context_cairo_create (GdkCairoContext *cairo_context)
stride);
cairo_surface_set_device_scale (image_surface, scale, scale);
- /* Lock the buffer so we can modify it safely */
- _gdk_macos_buffer_lock (buffer);
- cairo_surface_set_user_data (image_surface,
- &buffer_key,
- g_object_ref (buffer),
- unlock_buffer);
+ /* The buffer should already be locked at this point, and will
+ * be unlocked as part of end_frame.
+ */
if (!(cr = cairo_create (image_surface)))
goto failure;
@@ -158,6 +142,52 @@ failure:
return cr;
}
+static void
+copy_surface_data (GdkMacosBuffer *from,
+ GdkMacosBuffer *to,
+ const cairo_region_t *region,
+ int scale)
+{
+ const guint8 *from_base;
+ guint8 *to_base;
+ guint from_stride;
+ guint to_stride;
+ guint n_rects;
+
+ g_assert (GDK_IS_MACOS_BUFFER (from));
+ g_assert (GDK_IS_MACOS_BUFFER (to));
+ g_assert (region != NULL);
+ g_assert (!cairo_region_is_empty (region));
+
+ from_base = _gdk_macos_buffer_get_data (from);
+ from_stride = _gdk_macos_buffer_get_stride (from);
+
+ to_base = _gdk_macos_buffer_get_data (to);
+ to_stride = _gdk_macos_buffer_get_stride (to);
+
+ n_rects = cairo_region_num_rectangles (region);
+
+ for (guint i = 0; i < n_rects; i++)
+ {
+ cairo_rectangle_int_t rect;
+ int y2;
+
+ cairo_region_get_rectangle (region, i, &rect);
+
+ rect.y *= scale;
+ rect.height *= scale;
+ rect.x *= scale;
+ rect.width *= scale;
+
+ y2 = rect.y + rect.height;
+
+ for (int y = rect.y; y < y2; y++)
+ memcpy (&to_base[y * to_stride + rect.x * 4],
+ &from_base[y * from_stride + rect.x * 4],
+ rect.width * 4);
+ }
+}
+
static void
_gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context,
gboolean prefers_high_depth,
@@ -165,34 +195,68 @@ _gdk_macos_cairo_context_begin_frame (GdkDrawContext *draw_context,
{
GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
GdkMacosBuffer *buffer;
- GdkSurface *surface;
+ GdkMacosSurface *surface;
g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
[CATransaction begin];
[CATransaction setDisableActions:YES];
- surface = gdk_draw_context_get_surface (draw_context);
- buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
+ surface = GDK_MACOS_SURFACE (gdk_draw_context_get_surface (draw_context));
+ buffer = _gdk_macos_surface_get_buffer (surface);
_gdk_macos_buffer_set_damage (buffer, region);
_gdk_macos_buffer_set_flipped (buffer, FALSE);
+
+ _gdk_macos_buffer_lock (buffer);
+
+ /* If there is damage that was on the previous frame that is not on
+ * this frame, we need to copy that rendered region over to the back
+ * buffer so that when swapping buffers, we still have that content.
+ * This is done with a read-only lock on the IOSurface to avoid
+ * invalidating the buffer contents.
+ */
+ if (surface->front != NULL)
+ {
+ const cairo_region_t *previous = _gdk_macos_buffer_get_damage (surface->front);
+
+ if (previous != NULL)
+ {
+ cairo_region_t *copy;
+
+ copy = cairo_region_copy (previous);
+ cairo_region_subtract (copy, region);
+
+ if (!cairo_region_is_empty (copy))
+ {
+ int scale = gdk_surface_get_scale_factor (GDK_SURFACE (surface));
+
+ _gdk_macos_buffer_read_lock (surface->front);
+ copy_surface_data (surface->front, buffer, copy, scale);
+ _gdk_macos_buffer_read_unlock (surface->front);
+ }
+
+ cairo_region_destroy (copy);
+ }
+ }
}
static void
_gdk_macos_cairo_context_end_frame (GdkDrawContext *draw_context,
cairo_region_t *painted)
{
+ GdkMacosCairoContext *self = (GdkMacosCairoContext *)draw_context;
+ GdkMacosSurface *surface;
GdkMacosBuffer *buffer;
- GdkSurface *surface;
- g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (draw_context));
+ g_assert (GDK_IS_MACOS_CAIRO_CONTEXT (self));
- surface = gdk_draw_context_get_surface (draw_context);
- buffer = _gdk_macos_surface_get_buffer (GDK_MACOS_SURFACE (surface));
+ surface = GDK_MACOS_SURFACE (gdk_draw_context_get_surface (draw_context));
+ buffer = _gdk_macos_surface_get_buffer (surface);
- _gdk_macos_surface_swap_buffers (GDK_MACOS_SURFACE (surface), painted);
- _gdk_macos_buffer_set_damage (buffer, NULL);
+ _gdk_macos_buffer_unlock (buffer);
+
+ _gdk_macos_surface_swap_buffers (surface, painted);
[CATransaction commit];
}
diff --git a/gdk/macos/gdkmacosdisplay-feedback.c b/gdk/macos/gdkmacosdisplay-feedback.c
new file mode 100644
index 0000000000..868ac0fbcd
--- /dev/null
+++ b/gdk/macos/gdkmacosdisplay-feedback.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright © 2022 Red Hat, Inc.
+ *
+ * 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.1 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, see .
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include
+
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacossurface-private.h"
+
+static void
+gdk_macos_display_user_defaults_changed_cb (CFNotificationCenterRef center,
+ void *observer,
+ CFStringRef name,
+ const void *object,
+ CFDictionaryRef userInfo)
+{
+ GdkMacosDisplay *self = observer;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ _gdk_macos_display_reload_settings (self);
+}
+
+static void
+gdk_macos_display_monitors_changed_cb (CFNotificationCenterRef center,
+ void *observer,
+ CFStringRef name,
+ const void *object,
+ CFDictionaryRef userInfo)
+{
+ GdkMacosDisplay *self = observer;
+
+ g_assert (GDK_IS_MACOS_DISPLAY (self));
+
+ _gdk_macos_display_reload_monitors (self);
+
+ /* Now we need to update all our surface positions since they
+ * probably just changed origins.
+ */
+ for (const GList *iter = _gdk_macos_display_get_surfaces (self);
+ iter != NULL;
+ iter = iter->next)
+ {
+ GdkMacosSurface *surface = iter->data;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ _gdk_macos_surface_monitor_changed (surface);
+ }
+}
+
+
+void
+_gdk_macos_display_feedback_init (GdkMacosDisplay *self)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ CFNotificationCenterAddObserver (CFNotificationCenterGetLocalCenter (),
+ self,
+ gdk_macos_display_monitors_changed_cb,
+ CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
+ NULL,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+
+ CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
+ self,
+ gdk_macos_display_user_defaults_changed_cb,
+ CFSTR ("NSUserDefaultsDidChangeNotification"),
+ NULL,
+ CFNotificationSuspensionBehaviorDeliverImmediately);
+}
+
+void
+_gdk_macos_display_feedback_destroy (GdkMacosDisplay *self)
+{
+ g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
+
+ CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
+ self,
+ CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
+ NULL);
+
+ CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
+ self,
+ CFSTR ("NSUserDefaultsDidChangeNotification"),
+ NULL);
+
+}
diff --git a/gdk/macos/gdkmacosdisplay-private.h b/gdk/macos/gdkmacosdisplay-private.h
index be2290b89a..ef17618d61 100644
--- a/gdk/macos/gdkmacosdisplay-private.h
+++ b/gdk/macos/gdkmacosdisplay-private.h
@@ -68,16 +68,6 @@ struct _GdkMacosDisplay
*/
GQueue sorted_surfaces;
- /* Our CVDisplayLink based GSource which we use to freeze/thaw the
- * GdkFrameClock for the surface.
- */
- GSource *frame_source;
-
- /* A queue of surfaces which we know are awaiting frames to be drawn. This
- * uses the GdkMacosSurface.frame link.
- */
- GQueue awaiting_frames;
-
/* The surface that is receiving keyboard events */
GdkMacosSurface *keyboard_surface;
@@ -124,6 +114,8 @@ GdkMonitor *_gdk_macos_display_get_monitor_at_display_coords (GdkMacosDisp
int y);
GdkEvent *_gdk_macos_display_translate (GdkMacosDisplay *self,
NSEvent *event);
+void _gdk_macos_display_feedback_init (GdkMacosDisplay *self);
+void _gdk_macos_display_feedback_destroy (GdkMacosDisplay *self);
void _gdk_macos_display_break_all_grabs (GdkMacosDisplay *self,
guint32 time);
GdkModifierType _gdk_macos_display_get_current_keyboard_modifiers (GdkMacosDisplay *self);
@@ -136,10 +128,6 @@ GdkMacosSurface *_gdk_macos_display_get_surface_at_display_coords (GdkMacosDisp
void _gdk_macos_display_reload_monitors (GdkMacosDisplay *self);
void _gdk_macos_display_surface_removed (GdkMacosDisplay *self,
GdkMacosSurface *surface);
-void _gdk_macos_display_add_frame_callback (GdkMacosDisplay *self,
- GdkMacosSurface *surface);
-void _gdk_macos_display_remove_frame_callback (GdkMacosDisplay *self,
- GdkMacosSurface *surface);
NSWindow *_gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
int *x,
int *y);
@@ -155,7 +143,6 @@ void _gdk_macos_display_surface_resigned_key (GdkMacosDisp
GdkMacosSurface *surface);
void _gdk_macos_display_surface_became_key (GdkMacosDisplay *self,
GdkMacosSurface *surface);
-int _gdk_macos_display_get_nominal_refresh_rate (GdkMacosDisplay *self);
void _gdk_macos_display_clear_sorting (GdkMacosDisplay *self);
const GList *_gdk_macos_display_get_surfaces (GdkMacosDisplay *self);
void _gdk_macos_display_send_button_event (GdkMacosDisplay *self,
diff --git a/gdk/macos/gdkmacosdisplay-translate.c b/gdk/macos/gdkmacosdisplay-translate.c
index 646ba0cd9e..e3fb03fea5 100644
--- a/gdk/macos/gdkmacosdisplay-translate.c
+++ b/gdk/macos/gdkmacosdisplay-translate.c
@@ -635,6 +635,17 @@ fill_scroll_event (GdkMacosDisplay *self,
state = _gdk_macos_display_get_current_mouse_modifiers (self) |
_gdk_macos_display_get_current_keyboard_modifiers (self);
+ /* If we are starting a new phase, send a stop so any previous
+ * scrolling immediately stops.
+ */
+ if (phase == NSEventPhaseMayBegin)
+ return gdk_scroll_event_new (GDK_SURFACE (surface),
+ pointer,
+ NULL,
+ get_time_from_ns_event (nsevent),
+ state,
+ 0.0, 0.0, TRUE);
+
dx = [nsevent deltaX];
dy = [nsevent deltaY];
@@ -678,31 +689,17 @@ fill_scroll_event (GdkMacosDisplay *self,
dy = 0.0;
}
- if (dx != 0.0 || dy != 0.0)
+ if ((dx != 0.0 || dy != 0.0) && ![nsevent hasPreciseScrollingDeltas])
{
- if ([nsevent hasPreciseScrollingDeltas])
- {
- GdkEvent *emulated;
+ g_assert (ret == NULL);
- emulated = gdk_scroll_event_new_discrete (GDK_SURFACE (surface),
- pointer,
- NULL,
- get_time_from_ns_event (nsevent),
- state,
- direction,
- TRUE);
- _gdk_event_queue_append (GDK_DISPLAY (self), emulated);
- }
- else
- {
- ret = gdk_scroll_event_new_discrete (GDK_SURFACE (surface),
- pointer,
- NULL,
- get_time_from_ns_event (nsevent),
- state,
- direction,
- FALSE);
- }
+ ret = gdk_scroll_event_new_discrete (GDK_SURFACE (surface),
+ pointer,
+ NULL,
+ get_time_from_ns_event (nsevent),
+ state,
+ direction,
+ FALSE);
}
if (phase == NSEventPhaseEnded || phase == NSEventPhaseCancelled)
diff --git a/gdk/macos/gdkmacosdisplay.c b/gdk/macos/gdkmacosdisplay.c
index 74095504a2..ddcc274372 100644
--- a/gdk/macos/gdkmacosdisplay.c
+++ b/gdk/macos/gdkmacosdisplay.c
@@ -159,48 +159,6 @@ gdk_macos_display_update_bounds (GdkMacosDisplay *self)
GDK_END_MACOS_ALLOC_POOL;
}
-static void
-gdk_macos_display_monitors_changed_cb (CFNotificationCenterRef center,
- void *observer,
- CFStringRef name,
- const void *object,
- CFDictionaryRef userInfo)
-{
- GdkMacosDisplay *self = observer;
-
- g_assert (GDK_IS_MACOS_DISPLAY (self));
-
- _gdk_macos_display_reload_monitors (self);
-
- /* Now we need to update all our surface positions since they
- * probably just changed origins.
- */
- for (const GList *iter = _gdk_macos_display_get_surfaces (self);
- iter != NULL;
- iter = iter->next)
- {
- GdkMacosSurface *surface = iter->data;
-
- g_assert (GDK_IS_MACOS_SURFACE (surface));
-
- _gdk_macos_surface_monitor_changed (surface);
- }
-}
-
-static void
-gdk_macos_display_user_defaults_changed_cb (CFNotificationCenterRef center,
- void *observer,
- CFStringRef name,
- const void *object,
- CFDictionaryRef userInfo)
-{
- GdkMacosDisplay *self = observer;
-
- g_assert (GDK_IS_MACOS_DISPLAY (self));
-
- _gdk_macos_display_reload_settings (self);
-}
-
void
_gdk_macos_display_reload_monitors (GdkMacosDisplay *self)
{
@@ -273,56 +231,6 @@ gdk_macos_display_load_seat (GdkMacosDisplay *self)
g_object_unref (seat);
}
-static gboolean
-gdk_macos_display_frame_cb (gpointer data)
-{
- GdkMacosDisplay *self = data;
- GdkDisplayLinkSource *source;
- gint64 presentation_time;
- gint64 now;
- GList *iter;
-
- g_assert (GDK_IS_MACOS_DISPLAY (self));
-
- source = (GdkDisplayLinkSource *)self->frame_source;
-
- presentation_time = source->presentation_time;
- now = g_source_get_time ((GSource *)source);
-
- iter = self->awaiting_frames.head;
-
- while (iter != NULL)
- {
- GdkMacosSurface *surface = iter->data;
-
- g_assert (GDK_IS_MACOS_SURFACE (surface));
-
- iter = iter->next;
-
- _gdk_macos_surface_publish_timings (surface,
- source->presentation_time,
- source->refresh_interval);
-
- _gdk_macos_display_remove_frame_callback (self, surface);
-
- if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (surface)))
- gdk_surface_thaw_updates (GDK_SURFACE (surface));
- }
-
- return G_SOURCE_CONTINUE;
-}
-
-static void
-gdk_macos_display_load_display_link (GdkMacosDisplay *self)
-{
- self->frame_source = gdk_display_link_source_new ();
- g_source_set_callback (self->frame_source,
- gdk_macos_display_frame_cb,
- self,
- NULL);
- g_source_attach (self->frame_source, NULL);
-}
-
static const char *
gdk_macos_display_get_name (GdkDisplay *display)
{
@@ -426,7 +334,6 @@ _gdk_macos_display_surface_added (GdkMacosDisplay *self,
g_assert (GDK_IS_MACOS_SURFACE (surface));
g_assert (!queue_contains (&self->sorted_surfaces, &surface->sorted));
g_assert (!queue_contains (&self->main_surfaces, &surface->main));
- g_assert (!queue_contains (&self->awaiting_frames, &surface->frame));
g_assert (surface->sorted.data == surface);
g_assert (surface->main.data == surface);
g_assert (surface->frame.data == surface);
@@ -453,9 +360,6 @@ _gdk_macos_display_surface_removed (GdkMacosDisplay *self,
if (queue_contains (&self->main_surfaces, &surface->main))
_gdk_macos_display_surface_resigned_main (self, surface);
- if (queue_contains (&self->awaiting_frames, &surface->frame))
- g_queue_unlink (&self->awaiting_frames, &surface->frame);
-
g_return_if_fail (self->keyboard_surface != surface);
}
@@ -686,20 +590,11 @@ gdk_macos_display_finalize (GObject *object)
{
GdkMacosDisplay *self = (GdkMacosDisplay *)object;
- CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
- self,
- CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
- NULL);
-
- CFNotificationCenterRemoveObserver (CFNotificationCenterGetDistributedCenter (),
- self,
- CFSTR ("NSUserDefaultsDidChangeNotification"),
- NULL);
+ _gdk_macos_display_feedback_destroy (self);
g_clear_pointer (&self->active_drags, g_hash_table_unref);
g_clear_pointer (&self->active_drops, g_hash_table_unref);
g_clear_object (&GDK_DISPLAY (self)->clipboard);
- g_clear_pointer (&self->frame_source, g_source_unref);
g_clear_object (&self->monitors);
g_clear_pointer (&self->name, g_free);
@@ -774,24 +669,10 @@ _gdk_macos_display_open (const char *display_name)
gdk_macos_display_load_seat (self);
gdk_macos_display_load_clipboard (self);
-
- /* Load CVDisplayLink before monitors to access refresh rates */
- gdk_macos_display_load_display_link (self);
_gdk_macos_display_reload_monitors (self);
- CFNotificationCenterAddObserver (CFNotificationCenterGetLocalCenter (),
- self,
- gdk_macos_display_monitors_changed_cb,
- CFSTR ("NSApplicationDidChangeScreenParametersNotification"),
- NULL,
- CFNotificationSuspensionBehaviorDeliverImmediately);
-
- CFNotificationCenterAddObserver (CFNotificationCenterGetDistributedCenter (),
- self,
- gdk_macos_display_user_defaults_changed_cb,
- CFSTR ("NSUserDefaultsDidChangeNotification"),
- NULL,
- CFNotificationSuspensionBehaviorDeliverImmediately);
+ /* Initialize feedback from display server */
+ _gdk_macos_display_feedback_init (self);
if (event_source == NULL)
{
@@ -803,6 +684,8 @@ _gdk_macos_display_open (const char *display_name)
gdk_display_emit_opened (GDK_DISPLAY (self));
+ [NSApp activateIgnoringOtherApps:YES];
+
return GDK_DISPLAY (self);
}
@@ -1033,42 +916,6 @@ _gdk_macos_display_get_surface_at_display_coords (GdkMacosDisplay *self,
return _gdk_macos_display_get_surface_at_coords (self, x_gdk, y_gdk, surface_x, surface_y);
}
-void
-_gdk_macos_display_add_frame_callback (GdkMacosDisplay *self,
- GdkMacosSurface *surface)
-{
- g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
- g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
-
- if (!queue_contains (&self->awaiting_frames, &surface->frame))
- {
- /* Processing frames is always head to tail, so push to the
- * head so that we don't possibly re-enter this right after
- * adding to the queue.
- */
- g_queue_push_head_link (&self->awaiting_frames, &surface->frame);
-
- if (self->awaiting_frames.length == 1)
- gdk_display_link_source_unpause ((GdkDisplayLinkSource *)self->frame_source);
- }
-}
-
-void
-_gdk_macos_display_remove_frame_callback (GdkMacosDisplay *self,
- GdkMacosSurface *surface)
-{
- g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
- g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
-
- if (queue_contains (&self->awaiting_frames, &surface->frame))
- {
- g_queue_unlink (&self->awaiting_frames, &surface->frame);
-
- if (self->awaiting_frames.length == 0)
- gdk_display_link_source_pause ((GdkDisplayLinkSource *)self->frame_source);
- }
-}
-
NSWindow *
_gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
int *x,
@@ -1088,17 +935,6 @@ _gdk_macos_display_find_native_under_pointer (GdkMacosDisplay *self,
return NULL;
}
-int
-_gdk_macos_display_get_nominal_refresh_rate (GdkMacosDisplay *self)
-{
- g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), 60 * 1000);
-
- if (self->frame_source == NULL)
- return 60 * 1000;
-
- return ((GdkDisplayLinkSource *)self->frame_source)->refresh_rate;
-}
-
void
_gdk_macos_display_clear_sorting (GdkMacosDisplay *self)
{
diff --git a/gdk/macos/gdkmacosmonitor-private.h b/gdk/macos/gdkmacosmonitor-private.h
index e15f17352d..dfde4142c0 100644
--- a/gdk/macos/gdkmacosmonitor-private.h
+++ b/gdk/macos/gdkmacosmonitor-private.h
@@ -24,16 +24,23 @@
#include "gdkmacosdisplay.h"
#include "gdkmacosmonitor.h"
+#include "gdkmacossurface.h"
#include "gdkmonitorprivate.h"
G_BEGIN_DECLS
-GdkMacosMonitor *_gdk_macos_monitor_new (GdkMacosDisplay *display,
- CGDirectDisplayID screen_id);
-CGDirectDisplayID _gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self);
-gboolean _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self);
-CGColorSpaceRef _gdk_macos_monitor_copy_colorspace (GdkMacosMonitor *self);
+char *_gdk_macos_monitor_get_localized_name (NSScreen *screen);
+char *_gdk_macos_monitor_get_connector_name (CGDirectDisplayID screen_id);
+GdkMacosMonitor *_gdk_macos_monitor_new (GdkMacosDisplay *display,
+ CGDirectDisplayID screen_id);
+CGDirectDisplayID _gdk_macos_monitor_get_screen_id (GdkMacosMonitor *self);
+gboolean _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self);
+CGColorSpaceRef _gdk_macos_monitor_copy_colorspace (GdkMacosMonitor *self);
+void _gdk_macos_monitor_add_frame_callback (GdkMacosMonitor *self,
+ GdkMacosSurface *surface);
+void _gdk_macos_monitor_remove_frame_callback (GdkMacosMonitor *self,
+ GdkMacosSurface *surface);
G_END_DECLS
diff --git a/gdk/macos/gdkmacosmonitor.c b/gdk/macos/gdkmacosmonitor.c
index 6df1da0edc..bfec76b7ef 100644
--- a/gdk/macos/gdkmacosmonitor.c
+++ b/gdk/macos/gdkmacosmonitor.c
@@ -22,16 +22,21 @@
#include
#include
+#include "gdkdisplaylinksource.h"
#include "gdkmacosdisplay-private.h"
#include "gdkmacosmonitor-private.h"
+#include "gdkmacossurface-private.h"
#include "gdkmacosutils-private.h"
struct _GdkMacosMonitor
{
- GdkMonitor parent_instance;
- CGDirectDisplayID screen_id;
- NSRect workarea;
- guint has_opengl : 1;
+ GdkMonitor parent_instance;
+ CGDirectDisplayID screen_id;
+ GdkDisplayLinkSource *display_link;
+ NSRect workarea;
+ GQueue awaiting_frames;
+ guint has_opengl : 1;
+ guint in_frame : 1;
};
struct _GdkMacosMonitorClass
@@ -75,9 +80,26 @@ gdk_macos_monitor_get_workarea (GdkMonitor *monitor,
geometry->height = self->workarea.size.height;
}
+static void
+gdk_macos_monitor_dispose (GObject *object)
+{
+ GdkMacosMonitor *self = (GdkMacosMonitor *)object;
+
+ if (self->display_link)
+ {
+ g_source_destroy ((GSource *)self->display_link);
+ g_clear_pointer ((GSource **)&self->display_link, g_source_unref);
+ }
+
+ G_OBJECT_CLASS (gdk_macos_monitor_parent_class)->dispose (object);
+}
+
static void
gdk_macos_monitor_class_init (GdkMacosMonitorClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = gdk_macos_monitor_dispose;
}
static void
@@ -138,8 +160,8 @@ GetSubpixelLayout (CGDirectDisplayID screen_id)
return GDK_SUBPIXEL_LAYOUT_UNKNOWN;
}
-static char *
-GetLocalizedName (NSScreen *screen)
+char *
+_gdk_macos_monitor_get_localized_name (NSScreen *screen)
{
#ifdef AVAILABLE_MAC_OS_X_VERSION_10_15_AND_LATER
GDK_BEGIN_MACOS_ALLOC_POOL;
@@ -160,8 +182,8 @@ GetLocalizedName (NSScreen *screen)
#endif
}
-static char *
-GetConnectorName (CGDirectDisplayID screen_id)
+char *
+_gdk_macos_monitor_get_connector_name (CGDirectDisplayID screen_id)
{
guint unit = CGDisplayUnitNumber (screen_id);
return g_strdup_printf ("unit-%u", unit);
@@ -188,6 +210,68 @@ find_screen (CGDirectDisplayID screen_id)
return screen;
}
+static gboolean
+gdk_macos_monitor_display_link_cb (GdkMacosMonitor *self)
+{
+ gint64 presentation_time;
+ gint64 refresh_interval;
+ gint64 now;
+ GList *iter;
+
+ g_assert (GDK_IS_MACOS_MONITOR (self));
+ g_assert (!self->display_link->paused);
+
+ self->in_frame = TRUE;
+
+ presentation_time = self->display_link->presentation_time;
+ refresh_interval = self->display_link->refresh_interval;
+ now = g_source_get_time ((GSource *)self->display_link);
+
+ iter = self->awaiting_frames.head;
+
+ while (iter != NULL)
+ {
+ GdkMacosSurface *surface = iter->data;
+
+ g_assert (GDK_IS_MACOS_SURFACE (surface));
+
+ iter = iter->next;
+
+ g_queue_unlink (&self->awaiting_frames, &surface->frame);
+ _gdk_macos_surface_frame_presented (surface, presentation_time, refresh_interval);
+ }
+
+ if (self->awaiting_frames.length == 0 && !self->display_link->paused)
+ gdk_display_link_source_pause (self->display_link);
+
+ self->in_frame = FALSE;
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+_gdk_macos_monitor_reset_display_link (GdkMacosMonitor *self,
+ CGDisplayModeRef mode)
+{
+ GSource *source;
+
+ g_assert (GDK_IS_MACOS_MONITOR (self));
+
+ if (self->display_link)
+ {
+ g_source_destroy ((GSource *)self->display_link);
+ g_clear_pointer ((GSource **)&self->display_link, g_source_unref);
+ }
+
+ source = gdk_display_link_source_new (self->screen_id, mode);
+ self->display_link = (GdkDisplayLinkSource *)source;
+ g_source_set_callback (source,
+ (GSourceFunc) gdk_macos_monitor_display_link_cb,
+ self,
+ NULL);
+ g_source_attach (source, NULL);
+}
+
gboolean
_gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
{
@@ -222,8 +306,8 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
pixel_width = CGDisplayModeGetPixelWidth (mode);
has_opengl = CGDisplayUsesOpenGLAcceleration (self->screen_id);
subpixel_layout = GetSubpixelLayout (self->screen_id);
- name = GetLocalizedName (screen);
- connector = GetConnectorName (self->screen_id);
+ name = _gdk_macos_monitor_get_localized_name (screen);
+ connector = _gdk_macos_monitor_get_connector_name (self->screen_id);
if (width != 0 && pixel_width != 0)
scale_factor = MAX (1, pixel_width / width);
@@ -241,7 +325,7 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
* setting (which is also used by the frame clock).
*/
if (!(refresh_rate = CGDisplayModeGetRefreshRate (mode)))
- refresh_rate = _gdk_macos_display_get_nominal_refresh_rate (display);
+ refresh_rate = 60 * 1000;
gdk_monitor_set_connector (GDK_MONITOR (self), connector);
gdk_monitor_set_model (GDK_MONITOR (self), name);
@@ -261,6 +345,9 @@ _gdk_macos_monitor_reconfigure (GdkMacosMonitor *self)
*/
self->has_opengl = !!has_opengl;
+ /* Create a new display link to receive feedback about when to render */
+ _gdk_macos_monitor_reset_display_link (self, mode);
+
CGDisplayModeRelease (mode);
g_free (name);
g_free (connector);
@@ -302,3 +389,45 @@ _gdk_macos_monitor_copy_colorspace (GdkMacosMonitor *self)
return CGDisplayCopyColorSpace (self->screen_id);
}
+
+void
+_gdk_macos_monitor_add_frame_callback (GdkMacosMonitor *self,
+ GdkMacosSurface *surface)
+{
+ g_return_if_fail (GDK_IS_MACOS_MONITOR (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+ g_return_if_fail (surface->frame.data == (gpointer)surface);
+ g_return_if_fail (surface->frame.prev == NULL);
+ g_return_if_fail (surface->frame.next == NULL);
+ g_return_if_fail (self->awaiting_frames.head != &surface->frame);
+ g_return_if_fail (self->awaiting_frames.tail != &surface->frame);
+
+ /* Processing frames is always head to tail, so push to the
+ * head so that we don't possibly re-enter this right after
+ * adding to the queue.
+ */
+ if (!queue_contains (&self->awaiting_frames, &surface->frame))
+ {
+ g_queue_push_head_link (&self->awaiting_frames, &surface->frame);
+
+ if (!self->in_frame && self->awaiting_frames.length == 1)
+ gdk_display_link_source_unpause (self->display_link);
+ }
+}
+
+void
+_gdk_macos_monitor_remove_frame_callback (GdkMacosMonitor *self,
+ GdkMacosSurface *surface)
+{
+ g_return_if_fail (GDK_IS_MACOS_MONITOR (self));
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
+ g_return_if_fail (surface->frame.data == (gpointer)surface);
+
+ if (queue_contains (&self->awaiting_frames, &surface->frame))
+ {
+ g_queue_unlink (&self->awaiting_frames, &surface->frame);
+
+ if (!self->in_frame && self->awaiting_frames.length == 0)
+ gdk_display_link_source_pause (self->display_link);
+ }
+}
diff --git a/gdk/macos/gdkmacospopupsurface.c b/gdk/macos/gdkmacospopupsurface.c
index 477961503f..5a2d7ed481 100644
--- a/gdk/macos/gdkmacospopupsurface.c
+++ b/gdk/macos/gdkmacospopupsurface.c
@@ -87,6 +87,9 @@ gdk_macos_popup_surface_layout (GdkMacosPopupSurface *self,
gdk_surface_get_origin (GDK_SURFACE (self)->parent, &x, &y);
+ GDK_SURFACE (self)->x = final_rect.x;
+ GDK_SURFACE (self)->y = final_rect.y;
+
x += final_rect.x;
y += final_rect.y;
@@ -391,9 +394,7 @@ _gdk_macos_popup_surface_reposition (GdkMacosPopupSurface *self)
{
g_return_if_fail (GDK_IS_MACOS_POPUP_SURFACE (self));
- if (self->layout == NULL ||
- !gdk_surface_get_mapped (GDK_SURFACE (self)) ||
- GDK_SURFACE (self)->parent == NULL)
+ if (self->layout == NULL || GDK_SURFACE (self)->parent == NULL)
return;
gdk_macos_popup_surface_layout (self,
diff --git a/gdk/macos/gdkmacossurface-private.h b/gdk/macos/gdkmacossurface-private.h
index 08947f1ce3..15a7442c17 100644
--- a/gdk/macos/gdkmacossurface-private.h
+++ b/gdk/macos/gdkmacossurface-private.h
@@ -49,7 +49,7 @@ struct _GdkMacosSurface
GdkMacosBuffer *buffer;
GdkMacosBuffer *front;
GPtrArray *monitors;
- cairo_region_t *opaque_region;
+ GdkMonitor *best_monitor;
char *title;
int root_x;
@@ -75,6 +75,8 @@ struct _GdkMacosSurface
guint geometry_dirty : 1;
guint next_frame_set : 1;
guint show_on_next_swap : 1;
+ guint in_frame : 1;
+ guint awaiting_frame : 1;
};
struct _GdkMacosSurfaceClass
@@ -116,10 +118,11 @@ void _gdk_macos_surface_resize (GdkMacosSurface
int width,
int height);
void _gdk_macos_surface_update_fullscreen_state (GdkMacosSurface *self);
-void _gdk_macos_surface_show (GdkMacosSurface *self);
-void _gdk_macos_surface_publish_timings (GdkMacosSurface *self,
+void _gdk_macos_surface_request_frame (GdkMacosSurface *self);
+void _gdk_macos_surface_frame_presented (GdkMacosSurface *self,
gint64 predicted_presentation_time,
gint64 refresh_interval);
+void _gdk_macos_surface_show (GdkMacosSurface *self);
void _gdk_macos_surface_synthesize_null_key (GdkMacosSurface *self);
void _gdk_macos_surface_move (GdkMacosSurface *self,
int x,
diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c
index f837e2c650..cb900a7328 100644
--- a/gdk/macos/gdkmacossurface.c
+++ b/gdk/macos/gdkmacossurface.c
@@ -27,6 +27,7 @@
#include "gdkmacossurface-private.h"
+#include "gdkdebug.h"
#include "gdkdeviceprivate.h"
#include "gdkdisplay.h"
#include "gdkeventsprivate.h"
@@ -63,6 +64,73 @@ window_is_fullscreen (GdkMacosSurface *self)
return ([self->window styleMask] & NSWindowStyleMaskFullScreen) != 0;
}
+void
+_gdk_macos_surface_request_frame (GdkMacosSurface *self)
+{
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ if (self->awaiting_frame)
+ return;
+
+ self->awaiting_frame = TRUE;
+ _gdk_macos_monitor_add_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self);
+ gdk_surface_freeze_updates (GDK_SURFACE (self));
+}
+
+static void
+_gdk_macos_surface_cancel_frame (GdkMacosSurface *self)
+{
+ g_assert (GDK_IS_MACOS_SURFACE (self));
+
+ if (!self->awaiting_frame)
+ return;
+
+ self->awaiting_frame = FALSE;
+ _gdk_macos_monitor_remove_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self);
+ gdk_surface_thaw_updates (GDK_SURFACE (self));
+}
+
+void
+_gdk_macos_surface_frame_presented (GdkMacosSurface *self,
+ gint64 presentation_time,
+ gint64 refresh_interval)
+{
+ GdkFrameTimings *timings;
+ GdkFrameClock *frame_clock;
+
+ g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+ self->awaiting_frame = FALSE;
+
+ if (GDK_SURFACE_DESTROYED (self))
+ return;
+
+ frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
+
+ if (self->pending_frame_counter)
+ {
+ timings = gdk_frame_clock_get_timings (frame_clock, self->pending_frame_counter);
+
+ if (timings != NULL)
+ {
+ timings->presentation_time = presentation_time - refresh_interval;
+ timings->complete = TRUE;
+ }
+
+ self->pending_frame_counter = 0;
+ }
+
+ timings = gdk_frame_clock_get_current_timings (frame_clock);
+
+ if (timings != NULL)
+ {
+ timings->refresh_interval = refresh_interval;
+ timings->predicted_presentation_time = presentation_time;
+ }
+
+ if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
+ gdk_surface_thaw_updates (GDK_SURFACE (self));
+}
void
_gdk_macos_surface_reposition_children (GdkMacosSurface *self)
@@ -115,12 +183,6 @@ gdk_macos_surface_set_opaque_region (GdkSurface *surface,
g_assert (GDK_IS_MACOS_SURFACE (self));
- if (region != self->opaque_region)
- {
- g_clear_pointer (&self->opaque_region, cairo_region_destroy);
- self->opaque_region = cairo_region_copy (region);
- }
-
if ((nsview = _gdk_macos_surface_get_view (GDK_MACOS_SURFACE (surface))))
[(GdkMacosView *)nsview setOpaqueRegion:region];
}
@@ -137,8 +199,6 @@ gdk_macos_surface_hide (GdkSurface *surface)
self->show_on_next_swap = FALSE;
- _gdk_macos_display_remove_frame_callback (GDK_MACOS_DISPLAY (surface->display), self);
-
was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
was_key = [self->window isKeyWindow];
@@ -163,8 +223,12 @@ gdk_macos_surface_hide (GdkSurface *surface)
}
}
- if (was_mapped)
- gdk_surface_freeze_updates (GDK_SURFACE (self));
+ if (self->awaiting_frame)
+ {
+ self->awaiting_frame = FALSE;
+ _gdk_macos_monitor_remove_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self);
+ gdk_surface_freeze_updates (surface);
+ }
}
static int
@@ -208,6 +272,7 @@ gdk_macos_surface_begin_frame (GdkMacosSurface *self)
{
g_assert (GDK_IS_MACOS_SURFACE (self));
+ self->in_frame = TRUE;
}
static void
@@ -228,11 +293,9 @@ gdk_macos_surface_end_frame (GdkMacosSurface *self)
if ((timings = gdk_frame_clock_get_current_timings (frame_clock)))
self->pending_frame_counter = timings->frame_counter;
- if (GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self)))
- {
- _gdk_macos_display_add_frame_callback (GDK_MACOS_DISPLAY (display), self);
- gdk_surface_freeze_updates (GDK_SURFACE (self));
- }
+ self->in_frame = FALSE;
+
+ _gdk_macos_surface_request_frame (self);
}
static void
@@ -406,6 +469,17 @@ gdk_macos_surface_destroy (GdkSurface *surface,
GdkMacosWindow *window = g_steal_pointer (&self->window);
GdkFrameClock *frame_clock;
+ if (self->best_monitor)
+ {
+ if (self->awaiting_frame)
+ {
+ _gdk_macos_monitor_remove_frame_callback (GDK_MACOS_MONITOR (self->best_monitor), self);
+ self->awaiting_frame = FALSE;
+ }
+
+ g_clear_object (&self->best_monitor);
+ }
+
if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self))))
{
g_signal_handlers_disconnect_by_func (frame_clock,
@@ -417,7 +491,6 @@ gdk_macos_surface_destroy (GdkSurface *surface,
}
g_clear_pointer (&self->title, g_free);
- g_clear_pointer (&self->opaque_region, cairo_region_destroy);
if (window != NULL)
[window close];
@@ -563,10 +636,7 @@ _gdk_macos_surface_new (GdkMacosDisplay *display,
g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (display), NULL);
- if (parent != NULL)
- frame_clock = g_object_ref (gdk_surface_get_frame_clock (parent));
- else
- frame_clock = _gdk_frame_clock_idle_new ();
+ frame_clock = _gdk_frame_clock_idle_new ();
switch (surface_type)
{
@@ -624,14 +694,16 @@ _gdk_macos_surface_get_shadow (GdkMacosSurface *self,
gboolean
_gdk_macos_surface_is_opaque (GdkMacosSurface *self)
{
+ GdkSurface *surface = (GdkSurface *)self;
+
g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), FALSE);
- if (self->opaque_region != NULL &&
- cairo_region_num_rectangles (self->opaque_region) == 1)
+ if (surface->opaque_region != NULL &&
+ cairo_region_num_rectangles (surface->opaque_region) == 1)
{
cairo_rectangle_int_t extents;
- cairo_region_get_extents (self->opaque_region, &extents);
+ cairo_region_get_extents (surface->opaque_region, &extents);
return (extents.x == 0 &&
extents.y == 0 &&
@@ -819,41 +891,6 @@ _gdk_macos_surface_configure (GdkMacosSurface *self)
_gdk_macos_surface_reposition_children (self);
}
-void
-_gdk_macos_surface_publish_timings (GdkMacosSurface *self,
- gint64 presentation_time,
- gint64 refresh_interval)
-{
- GdkFrameTimings *timings;
- GdkFrameClock *frame_clock;
-
- g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
-
- if (!(frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self))))
- return;
-
- if (self->pending_frame_counter)
- {
- timings = gdk_frame_clock_get_timings (frame_clock, self->pending_frame_counter);
-
- if (timings != NULL)
- {
- timings->presentation_time = presentation_time - refresh_interval;
- timings->complete = TRUE;
- }
-
- self->pending_frame_counter = 0;
- }
-
- timings = gdk_frame_clock_get_current_timings (frame_clock);
-
- if (timings != NULL)
- {
- timings->refresh_interval = refresh_interval;
- timings->predicted_presentation_time = presentation_time;
- }
-}
-
void
_gdk_macos_surface_show (GdkMacosSurface *self)
{
@@ -864,22 +901,16 @@ _gdk_macos_surface_show (GdkMacosSurface *self)
if (GDK_SURFACE_DESTROYED (self))
return;
+ _gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display));
+ self->show_on_next_swap = TRUE;
+
was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
- if (!was_mapped)
- gdk_surface_set_is_mapped (GDK_SURFACE (self), TRUE);
-
- _gdk_macos_display_clear_sorting (GDK_MACOS_DISPLAY (GDK_SURFACE (self)->display));
-
- self->show_on_next_swap = TRUE;
-
if (!was_mapped)
{
- if (gdk_surface_get_mapped (GDK_SURFACE (self)))
- {
- _gdk_macos_surface_configure (self);
- gdk_surface_thaw_updates (GDK_SURFACE (self));
- }
+ gdk_surface_set_is_mapped (GDK_SURFACE (self), TRUE);
+ gdk_surface_request_layout (GDK_SURFACE (self));
+ gdk_surface_thaw_updates (GDK_SURFACE (self));
}
}
@@ -932,13 +963,17 @@ _gdk_macos_surface_move_resize (GdkMacosSurface *self,
GdkDisplay *display;
NSRect content_rect;
NSRect frame_rect;
+ gboolean ignore_move;
+ gboolean ignore_size;
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
- if ((x == -1 || (x == self->root_x)) &&
- (y == -1 || (y == self->root_y)) &&
- (width == -1 || (width == surface->width)) &&
- (height == -1 || (height == surface->height)))
+ ignore_move = (x == -1 || (x == self->root_x)) &&
+ (y == -1 || (y == self->root_y));
+ ignore_size = (width == -1 || (width == surface->width)) &&
+ (height == -1 || (height == surface->height));
+
+ if (ignore_move && ignore_size)
return;
display = gdk_surface_get_display (surface);
@@ -959,7 +994,14 @@ _gdk_macos_surface_move_resize (GdkMacosSurface *self,
x, y + height,
&x, &y);
- content_rect = NSMakeRect (x, y, width, height);
+ content_rect = [self->window contentRectForFrameRect:[self->window frame]];
+
+ if (!ignore_move)
+ content_rect.origin = NSMakePoint (x, y);
+
+ if (!ignore_size)
+ content_rect.size = NSMakeSize (width, height);
+
frame_rect = [self->window frameRectForContentRect:content_rect];
[self->window setFrame:frame_rect display:YES];
}
@@ -1016,14 +1058,18 @@ void
_gdk_macos_surface_monitor_changed (GdkMacosSurface *self)
{
GListModel *monitors;
+ GdkMonitor *best = NULL;
GdkRectangle rect;
GdkRectangle intersect;
GdkDisplay *display;
GdkMonitor *monitor;
guint n_monitors;
+ int best_area = 0;
g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+ _gdk_macos_surface_cancel_frame (self);
+
rect.x = self->root_x;
rect.y = self->root_y;
rect.width = GDK_SURFACE (self)->width;
@@ -1063,29 +1109,10 @@ _gdk_macos_surface_monitor_changed (GdkMacosSurface *self)
g_clear_object (&self->buffer);
g_clear_object (&self->front);
- _gdk_macos_surface_configure (self);
-
- gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
-}
-
-GdkMonitor *
-_gdk_macos_surface_get_best_monitor (GdkMacosSurface *self)
-{
- GdkMonitor *best = NULL;
- GdkRectangle rect;
- int best_area = 0;
-
- g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
-
- rect.x = self->root_x;
- rect.y = self->root_y;
- rect.width = GDK_SURFACE (self)->width;
- rect.height = GDK_SURFACE (self)->height;
-
+ /* Determine the best-fit monitor */
for (guint i = 0; i < self->monitors->len; i++)
{
- GdkMonitor *monitor = g_ptr_array_index (self->monitors, i);
- GdkRectangle intersect;
+ monitor = g_ptr_array_index (self->monitors, i);
if (gdk_rectangle_intersect (&monitor->geometry, &rect, &intersect))
{
@@ -1093,13 +1120,31 @@ _gdk_macos_surface_get_best_monitor (GdkMacosSurface *self)
if (area > best_area)
{
- best = monitor;
best_area = area;
+ best = monitor;
}
}
}
- return best;
+ if (g_set_object (&self->best_monitor, best))
+ {
+ GDK_NOTE (MISC,
+ g_message ("Surface \"%s\" moved to monitor \"%s\"",
+ self->title ? self->title : "unknown",
+ gdk_monitor_get_connector (best)));
+ }
+
+ _gdk_macos_surface_configure (self);
+ gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
+ _gdk_macos_surface_request_frame (self);
+}
+
+GdkMonitor *
+_gdk_macos_surface_get_best_monitor (GdkMacosSurface *self)
+{
+ g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
+
+ return self->best_monitor;
}
NSView *
diff --git a/gdk/macos/gdkmacostoplevelsurface.c b/gdk/macos/gdkmacostoplevelsurface.c
index c84ebb704b..d89434593b 100644
--- a/gdk/macos/gdkmacostoplevelsurface.c
+++ b/gdk/macos/gdkmacostoplevelsurface.c
@@ -174,6 +174,14 @@ _gdk_macos_toplevel_surface_present (GdkToplevel *toplevel,
_gdk_macos_surface_set_geometry_hints (GDK_MACOS_SURFACE (self), &geometry, mask);
gdk_surface_constrain_size (&geometry, mask, width, height, &width, &height);
+
+ GDK_NOTE (MISC,
+ g_message ("Resizing \"%s\" to %dx%d",
+ GDK_MACOS_SURFACE (self)->title ?
+ GDK_MACOS_SURFACE (self)->title :
+ "untitled",
+ width, height));
+
_gdk_macos_surface_resize (GDK_MACOS_SURFACE (self), width, height);
/* Maximized state */
@@ -202,6 +210,13 @@ _gdk_macos_toplevel_surface_present (GdkToplevel *toplevel,
GDK_MACOS_SURFACE (self),
&x, &y);
+ GDK_NOTE (MISC,
+ g_message ("Placing new toplevel \"%s\" at %d,%d",
+ GDK_MACOS_SURFACE (self)->title ?
+ GDK_MACOS_SURFACE (self)->title :
+ "untitled",
+ x, y));
+
_gdk_macos_surface_move (GDK_MACOS_SURFACE (self), x, y);
}
diff --git a/gdk/macos/meson.build b/gdk/macos/meson.build
index d17a60ac09..bd7bbb5324 100644
--- a/gdk/macos/meson.build
+++ b/gdk/macos/meson.build
@@ -8,6 +8,7 @@ gdk_macos_sources = files([
'gdkmacoscursor.c',
'gdkmacosdevice.c',
'gdkmacosdisplay.c',
+ 'gdkmacosdisplay-feedback.c',
'gdkmacosdisplay-settings.c',
'gdkmacosdisplay-translate.c',
'gdkmacosdisplay-wm.c',