X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gdk%2Fgdkframeclockidle.c;h=5901c7f6caf825dfd11a6f9dd216c4ebeef54810;hb=e54f8f4c623182b6870b27ef283cae2e71749662;hp=da05a9698acdb7ce0d3f4a892a86d13aa4f6816c;hpb=515e5f74aadcef7d1d55f593fa16d9e3c1f3fb4b;p=~andy%2Fgtk diff --git a/gdk/gdkframeclockidle.c b/gdk/gdkframeclockidle.c index da05a9698..5901c7f6c 100644 --- a/gdk/gdkframeclockidle.c +++ b/gdk/gdkframeclockidle.c @@ -31,39 +31,45 @@ #include "gdkframeclockidle.h" #include "gdk.h" -#define FRAME_INTERVAL 16667 // microseconds +#ifdef G_OS_WIN32 +#include +#endif + +#define FRAME_INTERVAL 16667 /* microseconds */ struct _GdkFrameClockIdlePrivate { GTimer *timer; /* timer_base is used to avoid ever going backward */ - guint64 timer_base; - guint64 frame_time; - guint64 min_next_frame_time; + gint64 timer_base; + gint64 frame_time; + gint64 min_next_frame_time; gint64 sleep_serial; guint flush_idle_id; guint paint_idle_id; guint freeze_count; + guint updating_count; GdkFrameClockPhase requested; GdkFrameClockPhase phase; guint in_paint_idle : 1; +#ifdef G_OS_WIN32 + guint begin_period : 1; +#endif }; static gboolean gdk_frame_clock_flush_idle (void *data); static gboolean gdk_frame_clock_paint_idle (void *data); -static void gdk_frame_clock_idle_finalize (GObject *object); - G_DEFINE_TYPE (GdkFrameClockIdle, gdk_frame_clock_idle, GDK_TYPE_FRAME_CLOCK) static gint64 sleep_serial; static gint64 sleep_source_prepare_time; static GSource *sleep_source; -gboolean +static gboolean sleep_source_prepare (GSource *source, gint *timeout) { @@ -72,7 +78,7 @@ sleep_source_prepare (GSource *source, return FALSE; } -gboolean +static gboolean sleep_source_check (GSource *source) { if (g_source_get_time (source) != sleep_source_prepare_time) @@ -81,7 +87,7 @@ sleep_source_check (GSource *source) return FALSE; } -gboolean +static gboolean sleep_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) @@ -121,26 +127,43 @@ gdk_frame_clock_idle_init (GdkFrameClockIdle *frame_clock_idle) GdkFrameClockIdlePrivate); priv = frame_clock_idle->priv; - priv->timer = g_timer_new (); priv->freeze_count = 0; } static void -gdk_frame_clock_idle_finalize (GObject *object) +gdk_frame_clock_idle_dispose (GObject *object) { GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (object)->priv; - g_timer_destroy (priv->timer); + if (priv->flush_idle_id != 0) + { + g_source_remove (priv->flush_idle_id); + priv->flush_idle_id = 0; + } + + if (priv->paint_idle_id != 0) + { + g_source_remove (priv->paint_idle_id); + priv->paint_idle_id = 0; + } - G_OBJECT_CLASS (gdk_frame_clock_idle_parent_class)->finalize (object); +#ifdef G_OS_WIN32 + if (priv->begin_period) + { + timeEndPeriod(1); + priv->begin_period = FALSE; + } +#endif + + G_OBJECT_CLASS (gdk_frame_clock_idle_parent_class)->dispose (object); } -static guint64 +static gint64 compute_frame_time (GdkFrameClockIdle *idle) { GdkFrameClockIdlePrivate *priv = idle->priv; - guint64 computed_frame_time; - guint64 elapsed; + gint64 computed_frame_time; + gint64 elapsed; elapsed = g_get_monotonic_time () + priv->timer_base; if (elapsed < priv->frame_time) @@ -160,11 +183,11 @@ compute_frame_time (GdkFrameClockIdle *idle) return computed_frame_time; } -static guint64 +static gint64 gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock) { GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv; - guint64 computed_frame_time; + gint64 computed_frame_time; /* can't change frame time during a paint */ if (priv->phase != GDK_FRAME_CLOCK_PHASE_NONE && @@ -185,24 +208,37 @@ gdk_frame_clock_idle_get_frame_time (GdkFrameClock *clock) return priv->frame_time; } +#define RUN_FLUSH_IDLE(priv) \ + ((priv)->freeze_count == 0 && \ + ((priv)->requested & GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0) + +/* The reason why we track updating_count separately here and don't + * just add GDK_FRAME_CLOCK_PHASE_UPDATE into ->request on every frame + * is so that we can avoid doing one more frame when an animation + * is cancelled. + */ +#define RUN_PAINT_IDLE(priv) \ + ((priv)->freeze_count == 0 && \ + (((priv)->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0 || \ + (priv)->updating_count > 0)) + static void maybe_start_idle (GdkFrameClockIdle *clock_idle) { GdkFrameClockIdlePrivate *priv = clock_idle->priv; - if (priv->freeze_count == 0 && priv->requested != 0) + if (RUN_FLUSH_IDLE (priv) || RUN_PAINT_IDLE (priv)) { guint min_interval = 0; if (priv->min_next_frame_time != 0) { - guint64 now = compute_frame_time (clock_idle); - guint64 min_interval_us = MAX (priv->min_next_frame_time, now) - now; + gint64 now = compute_frame_time (clock_idle); + gint64 min_interval_us = MAX (priv->min_next_frame_time, now) - now; min_interval = (min_interval_us + 500) / 1000; } - if (priv->flush_idle_id == 0 && - (priv->requested & GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0) + if (priv->flush_idle_id == 0 && RUN_FLUSH_IDLE (priv)) { priv->flush_idle_id = gdk_threads_add_timeout_full (GDK_PRIORITY_EVENTS + 1, min_interval, @@ -211,21 +247,36 @@ maybe_start_idle (GdkFrameClockIdle *clock_idle) (GDestroyNotify) g_object_unref); } - if (priv->paint_idle_id == 0 && - !priv->in_paint_idle && - (priv->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0) + if (!priv->in_paint_idle && + priv->paint_idle_id == 0 && RUN_PAINT_IDLE (priv)) { priv->paint_idle_id = gdk_threads_add_timeout_full (GDK_PRIORITY_REDRAW, min_interval, gdk_frame_clock_paint_idle, g_object_ref (clock_idle), (GDestroyNotify) g_object_unref); - - g_signal_emit_by_name (clock_idle, "frame-requested"); } } } +static void +maybe_stop_idle (GdkFrameClockIdle *clock_idle) +{ + GdkFrameClockIdlePrivate *priv = clock_idle->priv; + + if (priv->flush_idle_id != 0 && !RUN_FLUSH_IDLE (priv)) + { + g_source_remove (priv->flush_idle_id); + priv->flush_idle_id = 0; + } + + if (priv->paint_idle_id != 0 && !RUN_PAINT_IDLE (priv)) + { + g_source_remove (priv->paint_idle_id); + priv->paint_idle_id = 0; + } +} + static gint64 compute_min_next_frame_time (GdkFrameClockIdle *clock_idle, gint64 last_frame_time) @@ -260,7 +311,8 @@ gdk_frame_clock_flush_idle (void *data) g_signal_emit_by_name (G_OBJECT (clock), "flush-events"); - if ((priv->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0) + if ((priv->requested & ~GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS) != 0 || + priv->updating_count > 0) priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT; else priv->phase = GDK_FRAME_CLOCK_PHASE_NONE; @@ -282,11 +334,12 @@ gdk_frame_clock_paint_idle (void *data) priv->min_next_frame_time = 0; skip_to_resume_events = - (priv->requested & ~(GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS | GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS)) == 0; + (priv->requested & ~(GDK_FRAME_CLOCK_PHASE_FLUSH_EVENTS | GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS)) == 0 && + priv->updating_count == 0; if (priv->phase > GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT) { - timings = gdk_frame_clock_get_current_frame_timings (clock); + timings = gdk_frame_clock_get_current_timings (clock); } if (!skip_to_resume_events) @@ -302,19 +355,18 @@ gdk_frame_clock_paint_idle (void *data) priv->frame_time = compute_frame_time (clock_idle); _gdk_frame_clock_begin_frame (clock); - timings = gdk_frame_clock_get_current_frame_timings (clock); + timings = gdk_frame_clock_get_current_timings (clock); - gdk_frame_timings_set_frame_time (timings, priv->frame_time); - - gdk_frame_timings_set_slept_before (timings, - priv->sleep_serial != get_sleep_serial ()); + timings->frame_time = priv->frame_time; + timings->slept_before = priv->sleep_serial != get_sleep_serial (); priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT; /* We always emit ::before-paint and ::after-paint if * any of the intermediate phases are requested and * they don't get repeated if you freeze/thaw while - * in them. */ + * in them. + */ priv->requested &= ~GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT; g_signal_emit_by_name (G_OBJECT (clock), "before-paint"); priv->phase = GDK_FRAME_CLOCK_PHASE_UPDATE; @@ -322,7 +374,8 @@ gdk_frame_clock_paint_idle (void *data) case GDK_FRAME_CLOCK_PHASE_UPDATE: if (priv->freeze_count == 0) { - if (priv->requested & GDK_FRAME_CLOCK_PHASE_UPDATE) + if ((priv->requested & GDK_FRAME_CLOCK_PHASE_UPDATE) != 0 || + priv->updating_count > 0) { priv->requested &= ~GDK_FRAME_CLOCK_PHASE_UPDATE; g_signal_emit_by_name (G_OBJECT (clock), "update"); @@ -336,7 +389,7 @@ gdk_frame_clock_paint_idle (void *data) { if (priv->phase != GDK_FRAME_CLOCK_PHASE_LAYOUT && (priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT)) - _gdk_frame_timings_set_layout_start_time (timings, g_get_monotonic_time ()); + timings->layout_start_time = g_get_monotonic_time (); } #endif /* G_ENABLE_DEBUG */ @@ -355,7 +408,7 @@ gdk_frame_clock_paint_idle (void *data) { if (priv->phase != GDK_FRAME_CLOCK_PHASE_PAINT && (priv->requested & GDK_FRAME_CLOCK_PHASE_PAINT)) - _gdk_frame_timings_set_paint_start_time (timings, g_get_monotonic_time ()); + timings->paint_start_time = g_get_monotonic_time (); } #endif /* G_ENABLE_DEBUG */ @@ -377,7 +430,7 @@ gdk_frame_clock_paint_idle (void *data) #ifdef G_ENABLE_DEBUG if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0) - _gdk_frame_timings_set_frame_end_time (timings, g_get_monotonic_time ()); + timings->frame_end_time = g_get_monotonic_time (); #endif /* G_ENABLE_DEBUG */ } case GDK_FRAME_CLOCK_PHASE_RESUME_EVENTS: @@ -388,7 +441,7 @@ gdk_frame_clock_paint_idle (void *data) #ifdef G_ENABLE_DEBUG if ((_gdk_debug_flags & GDK_DEBUG_FRAMES) != 0) { - if (gdk_frame_timings_get_complete (timings)) + if (timings && timings->complete) _gdk_frame_clock_debug_print_timings (clock, timings); } #endif /* G_ENABLE_DEBUG */ @@ -432,34 +485,53 @@ gdk_frame_clock_idle_request_phase (GdkFrameClock *clock, maybe_start_idle (clock_idle); } -static GdkFrameClockPhase -gdk_frame_clock_idle_get_requested (GdkFrameClock *clock) +static void +gdk_frame_clock_idle_begin_updating (GdkFrameClock *clock) { - GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv; + GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock); + GdkFrameClockIdlePrivate *priv = clock_idle->priv; + +#ifdef G_OS_WIN32 + /* We need a higher resolution timer while doing animations */ + if (priv->updating_count == 0 && !priv->begin_period) + { + timeBeginPeriod(1); + priv->begin_period = TRUE; + } +#endif - return priv->requested; + priv->updating_count++; + maybe_start_idle (clock_idle); } static void -gdk_frame_clock_idle_freeze (GdkFrameClock *clock) +gdk_frame_clock_idle_end_updating (GdkFrameClock *clock) { - GdkFrameClockIdlePrivate *priv = GDK_FRAME_CLOCK_IDLE (clock)->priv; + GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock); + GdkFrameClockIdlePrivate *priv = clock_idle->priv; - priv->freeze_count++; + g_return_if_fail (priv->updating_count > 0); + + priv->updating_count--; + maybe_stop_idle (clock_idle); - if (priv->freeze_count == 1) +#ifdef G_OS_WIN32 + if (priv->updating_count == 0 && priv->begin_period) { - if (priv->flush_idle_id) - { - g_source_remove (priv->flush_idle_id); - priv->flush_idle_id = 0; - } - if (priv->paint_idle_id) - { - g_source_remove (priv->paint_idle_id); - priv->paint_idle_id = 0; - } + timeEndPeriod(1); + priv->begin_period = FALSE; } +#endif +} + +static void +gdk_frame_clock_idle_freeze (GdkFrameClock *clock) +{ + GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock); + GdkFrameClockIdlePrivate *priv = clock_idle->priv; + + priv->freeze_count++; + maybe_stop_idle (clock_idle); } static void @@ -476,7 +548,8 @@ gdk_frame_clock_idle_thaw (GdkFrameClock *clock) maybe_start_idle (clock_idle); /* If nothing is requested so we didn't start an idle, we need * to skip to the end of the state chain, since the idle won't - * run and do it for us. */ + * run and do it for us. + */ if (priv->paint_idle_id == 0) priv->phase = GDK_FRAME_CLOCK_PHASE_NONE; @@ -490,11 +563,12 @@ gdk_frame_clock_idle_class_init (GdkFrameClockIdleClass *klass) GObjectClass *gobject_class = (GObjectClass*) klass; GdkFrameClockClass *frame_clock_class = (GdkFrameClockClass *)klass; - gobject_class->finalize = gdk_frame_clock_idle_finalize; + gobject_class->dispose = gdk_frame_clock_idle_dispose; frame_clock_class->get_frame_time = gdk_frame_clock_idle_get_frame_time; frame_clock_class->request_phase = gdk_frame_clock_idle_request_phase; - frame_clock_class->get_requested = gdk_frame_clock_idle_get_requested; + frame_clock_class->begin_updating = gdk_frame_clock_idle_begin_updating; + frame_clock_class->end_updating = gdk_frame_clock_idle_end_updating; frame_clock_class->freeze = gdk_frame_clock_idle_freeze; frame_clock_class->thaw = gdk_frame_clock_idle_thaw;