*/
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;
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);
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,
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 (CGMainDisplayID ());
- 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)
{
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);
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);
}
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);
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);
/* Initialize feedback from display server */
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,
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)
{
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);
+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
#include <gdk/gdk.h>
#include <math.h>
+#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
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
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)
{
* 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);
*/
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);
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);
+ }
+}
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
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,
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)
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];
}
}
- 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
{
g_assert (GDK_IS_MACOS_SURFACE (self));
+ self->in_frame = TRUE;
}
static void
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
GdkMacosWindow *window = g_steal_pointer (&self->window);
GdkFrameClock *frame_clock;
- g_clear_object (&self->best_monitor);
+ 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))))
{
_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)
{
if (GDK_SURFACE_DESTROYED (self))
return;
- 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;
+ was_mapped = GDK_SURFACE_IS_MAPPED (GDK_SURFACE (self));
+
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_thaw_updates (GDK_SURFACE (self));
}
}
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;
}
_gdk_macos_surface_configure (self);
-
gdk_surface_invalidate_rect (GDK_SURFACE (self), NULL);
+ _gdk_macos_surface_request_frame (self);
}
GdkMonitor *