[gtk/wip/chergert/quartz4u] macos: start on display link based frame clock



commit 676bac31bc195268ea56deab6fd3b8deb2acf60f
Author: Christian Hergert <chergert redhat com>
Date:   Mon May 4 18:00:57 2020 -0700

    macos: start on display link based frame clock

 gdk/macos/GdkMacosWindow.c          |   1 -
 gdk/macos/gdkdisplaylinksource.c    | 253 ++++++++++++++++++++++++++++++++++++
 gdk/macos/gdkdisplaylinksource.h    |  48 +++++++
 gdk/macos/gdkmacosdisplay-private.h |   4 +
 gdk/macos/gdkmacosdisplay.c         | 115 ++++++++++++----
 gdk/macos/gdkmacossurface-private.h |   6 +-
 gdk/macos/gdkmacossurface.c         | 108 +++++++++------
 gdk/macos/meson.build               |   2 +
 8 files changed, 475 insertions(+), 62 deletions(-)
---
diff --git a/gdk/macos/GdkMacosWindow.c b/gdk/macos/GdkMacosWindow.c
index 678990993d..6b3c0ecf0e 100644
--- a/gdk/macos/GdkMacosWindow.c
+++ b/gdk/macos/GdkMacosWindow.c
@@ -247,7 +247,6 @@
   event = gdk_configure_event_new (surface,
                                    content_rect.size.width,
                                    content_rect.size.height);
-
   _gdk_event_queue_append (display, event);
 
   [self checkSendEnterNotify];
diff --git a/gdk/macos/gdkdisplaylinksource.c b/gdk/macos/gdkdisplaylinksource.c
new file mode 100644
index 0000000000..2961042724
--- /dev/null
+++ b/gdk/macos/gdkdisplaylinksource.c
@@ -0,0 +1,253 @@
+/* gdkdisplaylinksource.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *   Christian Hergert <christian hergert me>
+ */
+
+#include "config.h"
+
+#include <AppKit/AppKit.h>
+#include <mach/mach_time.h>
+
+#include "gdkdisplaylinksource.h"
+
+#include "gdkmacoseventsource-private.h"
+
+static gint64 host_to_frame_clock_time (gint64 host_time);
+
+static gboolean
+gdk_display_link_source_prepare (GSource *source,
+                                 gint    *timeout_)
+{
+  GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
+  gint64 now;
+
+  now = g_source_get_time (source);
+
+  if (now < impl->presentation_time)
+    *timeout_ = (impl->presentation_time - now) / 1000L;
+  else
+    *timeout_ = -1;
+
+  return impl->needs_dispatch;
+}
+
+static gboolean
+gdk_display_link_source_check (GSource *source)
+{
+  GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
+  return impl->needs_dispatch;
+}
+
+static gboolean
+gdk_display_link_source_dispatch (GSource     *source,
+                                  GSourceFunc  callback,
+                                  gpointer     user_data)
+{
+  GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
+  gboolean ret = G_SOURCE_CONTINUE;
+
+  impl->needs_dispatch = FALSE;
+
+  if (callback != NULL)
+    ret = callback (user_data);
+
+  return ret;
+}
+
+static void
+gdk_display_link_source_finalize (GSource *source)
+{
+  GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source;
+
+  CVDisplayLinkStop (impl->display_link);
+  CVDisplayLinkRelease (impl->display_link);
+}
+
+static GSourceFuncs gdk_display_link_source_funcs = {
+  gdk_display_link_source_prepare,
+  gdk_display_link_source_check,
+  gdk_display_link_source_dispatch,
+  gdk_display_link_source_finalize
+};
+
+void
+gdk_display_link_source_pause (GdkDisplayLinkSource *source)
+{
+  CVDisplayLinkStop (source->display_link);
+}
+
+void
+gdk_display_link_source_unpause (GdkDisplayLinkSource *source)
+{
+  CVDisplayLinkStart (source->display_link);
+}
+
+static CVReturn
+gdk_display_link_source_frame_cb (CVDisplayLinkRef   display_link,
+                                  const CVTimeStamp *inNow,
+                                  const CVTimeStamp *inOutputTime,
+                                  CVOptionFlags      flagsIn,
+                                  CVOptionFlags     *flagsOut,
+                                  void              *user_data)
+{
+  GdkDisplayLinkSource *impl = user_data;
+  gint64 presentation_time;
+  gboolean needs_wakeup;
+
+  needs_wakeup = !g_atomic_int_get (&impl->needs_dispatch);
+
+  presentation_time = host_to_frame_clock_time (inOutputTime->hostTime);
+
+  impl->presentation_time = presentation_time;
+  impl->needs_dispatch = TRUE;
+
+  if (needs_wakeup)
+     {
+      NSEvent *event;
+
+      /* Post a message so we'll break out of the message loop.
+       *
+       * We don't use g_main_context_wakeup() here because that
+       * would result in sending a message to the pipe(2) fd in
+       * the select thread which would then send this message as
+       * well. Lots of extra work.
+       */
+      event = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
+                                 location: NSZeroPoint
+                            modifierFlags: 0
+                                timestamp: 0
+                             windowNumber: 0
+                                  context: nil
+                                  subtype: GDK_MACOS_EVENT_SUBTYPE_EVENTLOOP
+                                    data1: 0
+                                    data2: 0];
+
+      [NSApp postEvent:event atStart:YES];
+     }
+
+  return kCVReturnSuccess;
+}
+
+/**
+ * gdk_display_link_source_new:
+ *
+ * Creates a new #GSource that will activate the dispatch function upon
+ * notification from a CVDisplayLink that a new frame should be drawn.
+ *
+ * Effort is made to keep the transition from the high-priority
+ * CVDisplayLink thread into this GSource lightweight. However, this is
+ * somewhat non-ideal since the best case would be to do the drawing
+ * from the high-priority thread.
+ *
+ * Returns: (transfer full): A newly created #GSource.
+ */
+GSource *
+gdk_display_link_source_new (void)
+{
+  GdkDisplayLinkSource *impl;
+  GSource *source;
+  CVReturn ret;
+  double period;
+
+  source = g_source_new (&gdk_display_link_source_funcs, sizeof *impl);
+  impl = (GdkDisplayLinkSource *)source;
+
+  /*
+   * 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.
+   */
+  ret = CVDisplayLinkCreateWithActiveCGDisplays (&impl->display_link);
+  if (ret != kCVReturnSuccess)
+    {
+      g_warning ("Failed to initialize CVDisplayLink!");
+      return source;
+    }
+
+  /*
+   * 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;
+
+  /*
+   * Wire up our callback to be executed within the high-priority thread.
+   */
+  CVDisplayLinkSetOutputCallback (impl->display_link,
+                                  gdk_display_link_source_frame_cb,
+                                  source);
+
+  g_source_set_name (source, "[gdk] quartz frame clock");
+
+  return source;
+}
+
+static gint64
+host_to_frame_clock_time (gint64 host_time)
+{
+  static mach_timebase_info_data_t timebase_info;
+
+  /*
+   * NOTE:
+   *
+   * This code is taken from GLib to match g_get_monotonic_time().
+   */
+  if (G_UNLIKELY (timebase_info.denom == 0))
+    {
+      /* This is a fraction that we must use to scale
+       * mach_absolute_time() by in order to reach nanoseconds.
+       *
+       * We've only ever observed this to be 1/1, but maybe it could be
+       * 1000/1 if mach time is microseconds already, or 1/1000 if
+       * picoseconds.  Try to deal nicely with that.
+       */
+      mach_timebase_info (&timebase_info);
+
+      /* We actually want microseconds... */
+      if (timebase_info.numer % 1000 == 0)
+        timebase_info.numer /= 1000;
+      else
+        timebase_info.denom *= 1000;
+
+      /* We want to make the numer 1 to avoid having to multiply... */
+      if (timebase_info.denom % timebase_info.numer == 0)
+        {
+          timebase_info.denom /= timebase_info.numer;
+          timebase_info.numer = 1;
+        }
+      else
+        {
+          /* We could just multiply by timebase_info.numer below, but why
+           * bother for a case that may never actually exist...
+           *
+           * Plus -- performing the multiplication would risk integer
+           * overflow.  If we ever actually end up in this situation, we
+           * should more carefully evaluate the correct course of action.
+           */
+          mach_timebase_info (&timebase_info); /* Get a fresh copy for a better message */
+          g_error ("Got weird mach timebase info of %d/%d.  Please file a bug against GLib.",
+                   timebase_info.numer, timebase_info.denom);
+        }
+    }
+
+  return host_time / timebase_info.denom;
+}
diff --git a/gdk/macos/gdkdisplaylinksource.h b/gdk/macos/gdkdisplaylinksource.h
new file mode 100644
index 0000000000..7493b0c0d4
--- /dev/null
+++ b/gdk/macos/gdkdisplaylinksource.h
@@ -0,0 +1,48 @@
+/* gdkdisplaylinksource.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors:
+ *   Christian Hergert <christian hergert me>
+ */
+
+#ifndef GDK_DISPLAY_LINK_SOURCE_H
+#define GDK_DISPLAY_LINK_SOURCE_H
+
+#include <glib.h>
+
+#include <QuartzCore/QuartzCore.h>
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+  GSource          source;
+
+  CVDisplayLinkRef display_link;
+  gint64           refresh_interval;
+
+  volatile gint64  presentation_time;
+  volatile guint   needs_dispatch;
+} GdkDisplayLinkSource;
+
+GSource *gdk_display_link_source_new     (void);
+void     gdk_display_link_source_pause   (GdkDisplayLinkSource *source);
+void     gdk_display_link_source_unpause (GdkDisplayLinkSource *source);
+
+G_END_DECLS
+
+#endif /* GDK_DISPLAY_LINK_SOURCE_H */
diff --git a/gdk/macos/gdkmacosdisplay-private.h b/gdk/macos/gdkmacosdisplay-private.h
index d7b737fd5d..7184c920d1 100644
--- a/gdk/macos/gdkmacosdisplay-private.h
+++ b/gdk/macos/gdkmacosdisplay-private.h
@@ -57,6 +57,10 @@ GdkMacosSurface *_gdk_macos_display_get_surface_at_display_coords  (GdkMacosDisp
 void             _gdk_macos_display_stacking_changed               (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);
 
 G_END_DECLS
 
diff --git a/gdk/macos/gdkmacosdisplay.c b/gdk/macos/gdkmacosdisplay.c
index 587b3b5268..bfc00190e7 100644
--- a/gdk/macos/gdkmacosdisplay.c
+++ b/gdk/macos/gdkmacosdisplay.c
@@ -23,10 +23,11 @@
 
 #import "GdkMacosWindow.h"
 
+#include "gdkdisplayprivate.h"
 #include "gdkeventsprivate.h"
 
+#include "gdkdisplaylinksource.h"
 #include "gdkmacoscairocontext-private.h"
-#include "gdkdisplayprivate.h"
 #include "gdkmacoseventsource-private.h"
 #include "gdkmacosdisplay-private.h"
 #include "gdkmacoskeymap-private.h"
@@ -71,18 +72,22 @@
 
 struct _GdkMacosDisplay
 {
-  GdkDisplay           parent_instance;
+  GdkDisplay      parent_instance;
+
+  char           *name;
+  GdkMacosKeymap *keymap;
 
-  char                *name;
-  GdkMacosKeymap      *keymap;
+  GPtrArray      *monitors;
 
-  GPtrArray           *monitors;
-  GQueue               surfaces;
+  GQueue          surfaces;
 
-  int                  width;
-  int                  height;
-  int                  min_x;
-  int                  min_y;
+  GSource        *frame_source;
+  GQueue          awaiting_frames;
+
+  int             width;
+  int             height;
+  int             min_x;
+  int             min_y;
 };
 
 struct _GdkMacosDisplayClass
@@ -233,6 +238,52 @@ 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_display_remove_frame_callback (self, surface);
+      _gdk_macos_surface_thaw (surface,
+                               source->presentation_time,
+                               source->refresh_interval);
+    }
+
+  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 gchar *
 gdk_macos_display_get_name (GdkDisplay *display)
 {
@@ -318,17 +369,11 @@ void
 _gdk_macos_display_surface_removed (GdkMacosDisplay *self,
                                     GdkMacosSurface *surface)
 {
-  GList *stacking;
-
   g_return_if_fail (GDK_IS_MACOS_DISPLAY (self));
   g_return_if_fail (GDK_IS_MACOS_SURFACE (surface));
 
-  stacking = _gdk_macos_surface_get_stacking (surface);
-
-  g_queue_unlink (&self->surfaces, stacking);
-
-  stacking->prev = NULL;
-  stacking->next = NULL;
+  g_queue_unlink (&self->surfaces, &surface->stacking);
+  g_queue_unlink (&self->awaiting_frames, &surface->frame_link);
 }
 
 void
@@ -357,8 +402,8 @@ _gdk_macos_display_stacking_changed (GdkMacosDisplay *self)
         continue;
 
       surface = [(GdkMacosWindow *)nswindow getGdkSurface];
-      link = _gdk_macos_surface_get_stacking (surface);
 
+      link = &surface->stacking;
       link->prev = NULL;
       link->next = NULL;
 
@@ -389,9 +434,7 @@ gdk_macos_display_create_surface (GdkDisplay     *display,
 
   if (surface != NULL)
     {
-      GList *stacking = _gdk_macos_surface_get_stacking (surface);
-
-      g_queue_push_head_link (&self->surfaces, stacking);
+      g_queue_push_head_link (&self->surfaces, &surface->stacking);
       _gdk_macos_display_stacking_changed (self);
     }
 
@@ -413,6 +456,7 @@ gdk_macos_display_finalize (GObject *object)
 {
   GdkMacosDisplay *self = (GdkMacosDisplay *)object;
 
+  g_clear_pointer (&self->frame_source, g_source_unref);
   g_clear_pointer (&self->monitors, g_ptr_array_unref);
   g_clear_pointer (&self->name, g_free);
 
@@ -475,6 +519,7 @@ _gdk_macos_display_open (const gchar *display_name)
 
   gdk_macos_display_load_seat (self);
   gdk_macos_display_load_monitors (self);
+  gdk_macos_display_load_display_link (self);
 
   if (event_source == NULL)
     {
@@ -630,3 +675,29 @@ _gdk_macos_display_get_surface_at_display_coords (GdkMacosDisplay *self,
 
   return NULL;
 }
+
+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));
+
+  g_queue_push_tail_link (&self->awaiting_frames, &surface->frame_link);
+
+  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));
+
+  g_queue_unlink (&self->awaiting_frames, &surface->frame_link);
+
+  if (self->awaiting_frames.length == 0)
+    gdk_display_link_source_pause ((GdkDisplayLinkSource *)self->frame_source);
+}
diff --git a/gdk/macos/gdkmacossurface-private.h b/gdk/macos/gdkmacossurface-private.h
index 6ea572b9da..6a2f08183d 100644
--- a/gdk/macos/gdkmacossurface-private.h
+++ b/gdk/macos/gdkmacossurface-private.h
@@ -38,6 +38,8 @@ G_BEGIN_DECLS
 struct _GdkMacosSurface
 {
   GdkSurface parent_instance;
+  GList      stacking;
+  GList      frame_link;
 };
 
 struct _GdkMacosSurfaceClass
@@ -54,7 +56,6 @@ GdkMacosSurface   *_gdk_macos_surface_new                     (GdkMacosDisplay
                                                                int                 height);
 NSWindow          *_gdk_macos_surface_get_native              (GdkMacosSurface    *self);
 CGDirectDisplayID  _gdk_macos_surface_get_screen_id           (GdkMacosSurface    *self);
-GList             *_gdk_macos_surface_get_stacking            (GdkMacosSurface    *self);
 const char        *_gdk_macos_surface_get_title               (GdkMacosSurface    *self);
 void               _gdk_macos_surface_set_title               (GdkMacosSurface    *self,
                                                                const gchar        *title);
@@ -80,6 +81,9 @@ void               _gdk_macos_surface_damage_cairo            (GdkMacosSurface
                                                                cairo_region_t     *painted);
 void               _gdk_macos_surface_set_is_key              (GdkMacosSurface    *self,
                                                                gboolean            is_key);
+void               _gdk_macos_surface_thaw                    (GdkMacosSurface    *self,
+                                                               gint64              
predicted_presentation_time,
+                                                               gint64              refresh_interval);
 
 G_END_DECLS
 
diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c
index d789e55934..3e367c2d5f 100644
--- a/gdk/macos/gdkmacossurface.c
+++ b/gdk/macos/gdkmacossurface.c
@@ -40,8 +40,6 @@
 
 typedef struct
 {
-  GList stacking;
-
   GdkMacosWindow *window;
 
   char *title;
@@ -53,6 +51,8 @@ typedef struct
 
   int scale;
 
+  gint64 pending_frame_counter;
+
   guint modal_hint : 1;
   guint is_key : 1;
 } GdkMacosSurfacePrivate;
@@ -67,16 +67,6 @@ enum {
 
 static GParamSpec *properties [LAST_PROP];
 
-GList *
-_gdk_macos_surface_get_stacking (GdkMacosSurface *self)
-{
-  GdkMacosSurfacePrivate *priv = gdk_macos_surface_get_instance_private (self);
-
-  g_return_val_if_fail (GDK_IS_MACOS_SURFACE (self), NULL);
-
-  return &priv->stacking;
-}
-
 static gboolean
 window_is_fullscreen (GdkMacosSurface *self)
 {
@@ -118,6 +108,8 @@ gdk_macos_surface_hide (GdkSurface *surface)
   gdk_seat_ungrab (seat);
 
   [priv->window hide];
+
+  _gdk_surface_clear_update_area (surface);
 }
 
 static gint
@@ -191,13 +183,6 @@ gdk_macos_surface_begin_move_drag (GdkSurface     *surface,
   [priv->window beginManualMove];
 }
 
-static void
-gdk_macos_surface_predict_presentation_time (GdkMacosSurface *self)
-{
-  g_assert (GDK_IS_MACOS_SURFACE (self));
-
-}
-
 static void
 gdk_macos_surface_begin_frame (GdkMacosSurface *self)
 {
@@ -208,8 +193,22 @@ gdk_macos_surface_begin_frame (GdkMacosSurface *self)
 static void
 gdk_macos_surface_end_frame (GdkMacosSurface *self)
 {
+  GdkMacosSurfacePrivate *priv = gdk_macos_surface_get_instance_private (self);
+  GdkFrameTimings *timings;
+  GdkFrameClock *frame_clock;
+  GdkDisplay *display;
+
   g_assert (GDK_IS_MACOS_SURFACE (self));
 
+  display = gdk_surface_get_display (GDK_SURFACE (self));
+  frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
+
+  if ((timings = gdk_frame_clock_get_current_timings (frame_clock)))
+    priv->pending_frame_counter = timings->frame_counter;
+
+  _gdk_macos_display_add_frame_callback (GDK_MACOS_DISPLAY (display), self);
+
+  gdk_surface_freeze_updates (GDK_SURFACE (self));
 }
 
 static void
@@ -224,7 +223,6 @@ gdk_macos_surface_before_paint (GdkMacosSurface *self,
   if (surface->update_freeze_count > 0)
     return;
 
-  gdk_macos_surface_predict_presentation_time (self);
   gdk_macos_surface_begin_frame (self);
 }
 
@@ -337,8 +335,8 @@ gdk_macos_surface_destroy (GdkSurface *surface,
 
   _gdk_macos_display_surface_removed (GDK_MACOS_DISPLAY (surface->display), self);
 
-  g_assert (priv->stacking.prev == NULL);
-  g_assert (priv->stacking.next == NULL);
+  g_assert (self->stacking.prev == NULL);
+  g_assert (self->stacking.next == NULL);
 
   GDK_END_MACOS_ALLOC_POOL;
 }
@@ -353,18 +351,19 @@ gdk_macos_surface_constructed (GObject *object)
 
   G_OBJECT_CLASS (gdk_macos_surface_parent_class)->constructed (object);
 
-  frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
-
-  g_signal_connect_object (frame_clock,
-                           "before-paint",
-                           G_CALLBACK (gdk_macos_surface_before_paint),
-                           self,
-                           G_CONNECT_SWAPPED);
-  g_signal_connect_object (frame_clock,
-                           "after-paint",
-                           G_CALLBACK (gdk_macos_surface_after_paint),
-                           self,
-                           G_CONNECT_SWAPPED);
+  if ((frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self))))
+    {
+      g_signal_connect_object (frame_clock,
+                               "before-paint",
+                               G_CALLBACK (gdk_macos_surface_before_paint),
+                               self,
+                               G_CONNECT_SWAPPED);
+      g_signal_connect_object (frame_clock,
+                               "after-paint",
+                               G_CALLBACK (gdk_macos_surface_after_paint),
+                               self,
+                               G_CONNECT_SWAPPED);
+    }
 }
 
 static void
@@ -441,9 +440,8 @@ gdk_macos_surface_class_init (GdkMacosSurfaceClass *klass)
 static void
 gdk_macos_surface_init (GdkMacosSurface *self)
 {
-  GdkMacosSurfacePrivate *priv = gdk_macos_surface_get_instance_private (self);
-
-  priv->stacking.data = self;
+  self->stacking.data = self;
+  self->frame_link.data = self;
 }
 
 GdkMacosSurface *
@@ -727,6 +725,40 @@ _gdk_macos_surface_set_is_key (GdkMacosSurface *self,
         gdk_synthesize_surface_state (GDK_SURFACE (self), GDK_SURFACE_STATE_FOCUSED, 0);
 
       event = gdk_focus_event_new (GDK_SURFACE (self), keyboard, NULL, is_key);
-      _gdk_event_queue_append (display, event);
+      _gdk_event_queue_append (GDK_DISPLAY (display), event);
+    }
+}
+
+void
+_gdk_macos_surface_thaw (GdkMacosSurface *self,
+                         gint64           presentation_time,
+                         gint64           refresh_interval)
+{
+  GdkMacosSurfacePrivate *priv = gdk_macos_surface_get_instance_private (self);
+  GdkFrameTimings *timings;
+  GdkFrameClock *frame_clock;
+
+  g_return_if_fail (GDK_IS_MACOS_SURFACE (self));
+
+  gdk_surface_thaw_updates (GDK_SURFACE (self));
+
+  frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self));
+
+  if (priv->pending_frame_counter)
+    {
+      timings = gdk_frame_clock_get_timings (frame_clock, priv->pending_frame_counter);
+
+      if (timings != NULL)
+        timings->presentation_time = presentation_time - refresh_interval;
+
+      priv->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;
     }
 }
diff --git a/gdk/macos/meson.build b/gdk/macos/meson.build
index 03fae86055..0ee0e11e1f 100644
--- a/gdk/macos/meson.build
+++ b/gdk/macos/meson.build
@@ -1,4 +1,5 @@
 gdk_macos_sources = files([
+  'gdkdisplaylinksource.c',
   'GdkMacosWindow.c',
   'gdkmacoscairocontext.c',
   'gdkmacoscursor.c',
@@ -32,6 +33,7 @@ install_headers(gdk_macos_public_headers, 'gdkmacos.h', subdir: 'gtk-4.0/gdk/mac
 gdk_macos_frameworks = [
   'AppKit',
   'Carbon',
+  'CoreVideo',
   'CoreServices',
 ]
 


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