gdkdisplaymanager.h \
gdkdnd.h \
gdkevents.h \
+ gdkframehistory.h \
+ gdkframetimings.h \
gdkkeys.h \
gdkkeysyms.h \
gdkkeysyms-compat.h \
gdkdisplaymanager.c \
gdkdnd.c \
gdkevents.c \
+ gdkframehistory.c \
+ gdkframetimings.c \
gdkglobals.c \
gdkkeys.c \
gdkkeyuni.c \
GDK_FRAME_CLOCK_GET_IFACE (clock)->thaw (clock);
}
+/**
+ * gdk_frame_clock_get_history:
+ * @clock: the clock
+ *
+ * Gets the #GdkFrameHistory for the frame clock.
+ *
+ * Since: 3.8
+ * Return value: (transfer none): the frame history object
+ */
+GdkFrameHistory *
+gdk_frame_clock_get_history (GdkFrameClock *clock)
+{
+ g_return_val_if_fail (GDK_IS_FRAME_CLOCK (clock), NULL);
+
+ return GDK_FRAME_CLOCK_GET_IFACE (clock)->get_history (clock);
+}
+
/**
* gdk_frame_clock_get_requested:
* @clock: the clock
#ifndef __GDK_FRAME_CLOCK_H__
#define __GDK_FRAME_CLOCK_H__
-#include <glib-object.h>
+#include <gdk/gdkframehistory.h>
G_BEGIN_DECLS
void (* freeze) (GdkFrameClock *clock);
void (* thaw) (GdkFrameClock *clock);
+ GdkFrameHistory * (* get_history) (GdkFrameClock *clock);
+
/* signals */
/* void (* frame_requested) (GdkFrameClock *clock); */
/* void (* flush_events) (GdkFrameClock *clock); */
void gdk_frame_clock_freeze (GdkFrameClock *clock);
void gdk_frame_clock_thaw (GdkFrameClock *clock);
+GdkFrameHistory *gdk_frame_clock_get_history (GdkFrameClock *clock);
+
/* Convenience API */
void gdk_frame_clock_get_frame_time_val (GdkFrameClock *clock,
GTimeVal *timeval);
struct _GdkFrameClockIdlePrivate
{
+ GdkFrameHistory *history;
GTimer *timer;
/* timer_base is used to avoid ever going backward */
guint64 timer_base;
GdkFrameClockIdlePrivate);
priv = frame_clock_idle->priv;
+ priv->history = gdk_frame_history_new ();
priv->timer = g_timer_new ();
priv->freeze_count = 0;
}
case GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT:
if (priv->freeze_count == 0)
{
+ GdkFrameTimings *timings;
+ gint64 frame_counter;
+
priv->frame_time = compute_frame_time (clock_idle);
+ gdk_frame_history_begin_frame (priv->history);
+ frame_counter = gdk_frame_history_get_frame_counter (priv->history);
+ timings = gdk_frame_history_get_timings (priv->history, frame_counter);
+ gdk_frame_timings_set_frame_time (timings, priv->frame_time);
priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
}
}
+static GdkFrameHistory *
+gdk_frame_clock_idle_get_history (GdkFrameClock *clock)
+{
+ GdkFrameClockIdle *clock_idle = GDK_FRAME_CLOCK_IDLE (clock);
+ GdkFrameClockIdlePrivate *priv = clock_idle->priv;
+
+ return priv->history;
+}
+
static void
gdk_frame_clock_idle_interface_init (GdkFrameClockInterface *iface)
{
iface->get_requested = gdk_frame_clock_idle_get_requested;
iface->freeze = gdk_frame_clock_idle_freeze;
iface->thaw = gdk_frame_clock_idle_thaw;
+ iface->get_history = gdk_frame_clock_idle_get_history;
}
GdkFrameClock *
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2012 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 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/>.
+ */
+
+#include "config.h"
+
+#include "gdkframehistory.h"
+
+#define FRAME_HISTORY_MAX_LENGTH 16
+
+struct _GdkFrameHistory
+{
+ GObject parent_instance;
+
+ gint64 frame_counter;
+ gint n_timings;
+ gint current;
+ GdkFrameTimings *timings[FRAME_HISTORY_MAX_LENGTH];
+};
+
+struct _GdkFrameHistoryClass
+{
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE (GdkFrameHistory, gdk_frame_history, G_TYPE_OBJECT)
+
+static void
+gdk_frame_history_finalize (GObject *object)
+{
+ GdkFrameHistory *history = GDK_FRAME_HISTORY (object);
+ int i;
+
+ for (i = 0; i < FRAME_HISTORY_MAX_LENGTH; i++)
+ if (history->timings[i] != 0)
+ gdk_frame_timings_unref (history->timings[i]);
+
+ G_OBJECT_CLASS (gdk_frame_history_parent_class)->finalize (object);
+}
+
+static void
+gdk_frame_history_class_init (GdkFrameHistoryClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdk_frame_history_finalize;
+}
+
+static void
+gdk_frame_history_init (GdkFrameHistory *history)
+{
+ history->frame_counter = -1;
+ history->current = FRAME_HISTORY_MAX_LENGTH - 1;
+}
+
+GdkFrameHistory *
+gdk_frame_history_new (void)
+{
+ return g_object_new (GDK_TYPE_FRAME_HISTORY, NULL);
+}
+
+gint64
+gdk_frame_history_get_frame_counter (GdkFrameHistory *history)
+{
+ g_return_val_if_fail (GDK_IS_FRAME_HISTORY (history), 0);
+
+ return history->frame_counter;
+}
+
+gint64
+gdk_frame_history_get_start (GdkFrameHistory *history)
+{
+ g_return_val_if_fail (GDK_IS_FRAME_HISTORY (history), 0);
+
+ return history->frame_counter + 1 - history->n_timings;
+}
+
+void
+gdk_frame_history_begin_frame (GdkFrameHistory *history)
+{
+ g_return_if_fail (GDK_IS_FRAME_HISTORY (history));
+
+ history->frame_counter++;
+ history->current = (history->current + 1) % FRAME_HISTORY_MAX_LENGTH;
+
+ if (history->n_timings < FRAME_HISTORY_MAX_LENGTH)
+ history->n_timings++;
+ else
+ {
+ gdk_frame_timings_unref(history->timings[history->current]);
+ }
+
+ history->timings[history->current] = gdk_frame_timings_new (history->frame_counter);
+}
+
+GdkFrameTimings *
+gdk_frame_history_get_timings (GdkFrameHistory *history,
+ gint64 frame_counter)
+{
+ gint pos;
+
+ g_return_val_if_fail (GDK_IS_FRAME_HISTORY (history), NULL);
+
+ if (frame_counter > history->frame_counter)
+ return NULL;
+
+ if (frame_counter <= history->frame_counter - history->n_timings)
+ return NULL;
+
+ pos = (history->current - (history->frame_counter - frame_counter) + FRAME_HISTORY_MAX_LENGTH) % FRAME_HISTORY_MAX_LENGTH;
+
+ return history->timings[pos];
+}
+
+GdkFrameTimings *
+gdk_frame_history_get_last_complete (GdkFrameHistory *history)
+{
+ gint i;
+
+ g_return_val_if_fail (GDK_IS_FRAME_HISTORY (history), NULL);
+
+ for (i = 0; i < history->n_timings; i++)
+ {
+ gint pos = ((history->current - i) + FRAME_HISTORY_MAX_LENGTH) % FRAME_HISTORY_MAX_LENGTH;
+ if (gdk_frame_timings_get_complete (history->timings[pos]))
+ return history->timings[pos];
+ }
+
+ return NULL;
+}
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2012 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 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/>.
+ */
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#ifndef __GDK_FRAME_HISTORY_H__
+#define __GDK_FRAME_HISTORY_H__
+
+#include <gdk/gdkframetimings.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkFrameHistory GdkFrameHistory;
+typedef struct _GdkFrameHistoryClass GdkFrameHistoryClass;
+
+#define GDK_TYPE_FRAME_HISTORY (gdk_frame_history_get_type ())
+#define GDK_FRAME_HISTORY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDK_TYPE_FRAME_HISTORY, GdkFrameHistory))
+#define GDK_IS_FRAME_HISTORY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDK_TYPE_FRAME_HISTORY))
+
+GType gdk_frame_history_get_type (void) G_GNUC_CONST;
+
+GdkFrameHistory *gdk_frame_history_new (void);
+
+gint64 gdk_frame_history_get_frame_counter (GdkFrameHistory *history);
+gint64 gdk_frame_history_get_start (GdkFrameHistory *history);
+void gdk_frame_history_begin_frame (GdkFrameHistory *history);
+GdkFrameTimings *gdk_frame_history_get_timings (GdkFrameHistory *history,
+ gint64 frame_counter);
+GdkFrameTimings *gdk_frame_history_get_last_complete (GdkFrameHistory *history);
+
+G_END_DECLS
+
+#endif /* __GDK_FRAME_HISTORY_H__ */
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2012 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 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/>.
+ */
+
+#include "config.h"
+
+#include "gdkframetimings.h"
+
+struct _GdkFrameTimings
+{
+ guint ref_count;
+
+ gboolean complete;
+ gint64 frame_counter;
+ guint64 cookie;
+ gint64 frame_time;
+ gint64 drawn_time;
+ gint64 presentation_time;
+ gint64 refresh_interval;
+};
+
+G_DEFINE_BOXED_TYPE (GdkFrameTimings, gdk_frame_timings,
+ gdk_frame_timings_ref,
+ gdk_frame_timings_unref)
+
+GdkFrameTimings *
+gdk_frame_timings_new (gint64 frame_counter)
+{
+ GdkFrameTimings *timings;
+
+ timings = g_slice_new0 (GdkFrameTimings);
+ timings->ref_count = 1;
+ timings->frame_counter = frame_counter;
+
+ return timings;
+}
+
+GdkFrameTimings *
+gdk_frame_timings_ref (GdkFrameTimings *timings)
+{
+ g_return_val_if_fail (timings != NULL, NULL);
+
+ timings->ref_count++;
+
+ return timings;
+}
+
+void
+gdk_frame_timings_unref (GdkFrameTimings *timings)
+{
+ g_return_if_fail (timings != NULL);
+ g_return_if_fail (timings->ref_count > 0);
+
+ timings->ref_count--;
+ if (timings->ref_count == 0)
+ {
+ g_slice_free (GdkFrameTimings, timings);
+ }
+}
+
+gint64
+gdk_frame_timings_get_frame_counter (GdkFrameTimings *timings)
+{
+ return timings->frame_counter;
+}
+
+guint64
+gdk_frame_timings_get_cookie (GdkFrameTimings *timings)
+{
+ g_return_val_if_fail (timings != NULL, 0);
+
+ return timings->cookie;
+}
+
+void
+gdk_frame_timings_set_cookie (GdkFrameTimings *timings,
+ guint64 cookie)
+{
+ g_return_if_fail (timings != NULL);
+
+ timings->cookie = cookie;
+}
+
+gboolean
+gdk_frame_timings_get_complete (GdkFrameTimings *timings)
+{
+ g_return_val_if_fail (timings != NULL, FALSE);
+
+ return timings->complete;
+}
+
+void
+gdk_frame_timings_set_complete (GdkFrameTimings *timings,
+ gboolean complete)
+{
+ g_return_if_fail (timings != NULL);
+
+ timings->complete = complete;
+}
+
+gint64
+gdk_frame_timings_get_frame_time (GdkFrameTimings *timings)
+{
+ g_return_val_if_fail (timings != NULL, 0);
+
+ return timings->frame_time;
+}
+
+void
+gdk_frame_timings_set_frame_time (GdkFrameTimings *timings,
+ gint64 frame_time)
+{
+ g_return_if_fail (timings != NULL);
+
+ timings->frame_time = frame_time;
+}
+
+gint64
+gdk_frame_timings_get_drawn_time (GdkFrameTimings *timings)
+{
+ g_return_val_if_fail (timings != NULL, 0);
+
+ return timings->drawn_time;
+}
+
+void
+gdk_frame_timings_set_drawn_time (GdkFrameTimings *timings,
+ gint64 drawn_time)
+{
+ g_return_if_fail (timings != NULL);
+
+ timings->drawn_time = drawn_time;
+}
+
+gint64
+gdk_frame_timings_get_presentation_time (GdkFrameTimings *timings)
+{
+ g_return_val_if_fail (timings != NULL, 0);
+
+ return timings->presentation_time;
+}
+
+void
+gdk_frame_timings_set_presentation_time (GdkFrameTimings *timings,
+ gint64 presentation_time)
+{
+ g_return_if_fail (timings != NULL);
+
+ timings->presentation_time = presentation_time;
+}
+
+gint64
+gdk_frame_timings_get_refresh_interval (GdkFrameTimings *timings)
+{
+ g_return_val_if_fail (timings != NULL, 0);
+
+ return timings->refresh_interval;
+}
+
+void
+gdk_frame_timings_set_refresh_interval (GdkFrameTimings *timings,
+ gint64 refresh_interval)
+{
+ g_return_if_fail (timings != NULL);
+
+ timings->refresh_interval = refresh_interval;
+}
--- /dev/null
+/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 2012 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 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/>.
+ */
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#ifndef __GDK_FRAME_TIMINGS_H__
+#define __GDK_FRAME_TIMINGS_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GdkFrameTimings GdkFrameTimings;
+
+GType gdk_frame_timings_get_type (void) G_GNUC_CONST;
+
+GdkFrameTimings *gdk_frame_timings_new (gint64 frame_counter);
+
+GdkFrameTimings *gdk_frame_timings_ref (GdkFrameTimings *timings);
+void gdk_frame_timings_unref (GdkFrameTimings *timings);
+
+gint64 gdk_frame_timings_get_frame_counter (GdkFrameTimings *timings);
+
+guint64 gdk_frame_timings_get_cookie (GdkFrameTimings *timings);
+void gdk_frame_timings_set_cookie (GdkFrameTimings *timings,
+ guint64 cookie);
+
+gboolean gdk_frame_timings_get_complete (GdkFrameTimings *timings);
+void gdk_frame_timings_set_complete (GdkFrameTimings *timings,
+ gboolean complete);
+
+gint64 gdk_frame_timings_get_frame_time (GdkFrameTimings *timings);
+void gdk_frame_timings_set_frame_time (GdkFrameTimings *timings,
+ gint64 frame_time);
+gint64 gdk_frame_timings_get_drawn_time (GdkFrameTimings *timings);
+void gdk_frame_timings_set_drawn_time (GdkFrameTimings *timings,
+ gint64 frame_time);
+gint64 gdk_frame_timings_get_presentation_time (GdkFrameTimings *timings);
+void gdk_frame_timings_set_presentation_time (GdkFrameTimings *timings,
+ gint64 presentation_time);
+gint64 gdk_frame_timings_get_refresh_interval (GdkFrameTimings *timings);
+void gdk_frame_timings_set_refresh_interval (GdkFrameTimings *timings,
+ gint64 refresh_interval);
+
+G_END_DECLS
+
+#endif /* __GDK_FRAME_TIMINGS_H__ */
return return_val;
}
+static GdkFrameTimings *
+find_frame_timings (GdkFrameClock *clock,
+ guint64 serial)
+{
+ GdkFrameHistory *history = gdk_frame_clock_get_history (clock);
+ gint64 start_frame, end_frame, i;
+
+ start_frame = gdk_frame_history_get_start (history);
+ end_frame = gdk_frame_history_get_frame_counter (history);
+ for (i = end_frame; i >= start_frame; i--)
+ {
+ GdkFrameTimings *timings = gdk_frame_history_get_timings (history, i);
+
+ if (gdk_frame_timings_get_cookie (timings) == serial)
+ return timings;
+ }
+
+ return NULL;
+}
+
GdkFilterReturn
_gdk_wm_protocols_filter (GdkXEvent *xev,
GdkEvent *event,
display = GDK_WINDOW_DISPLAY (win);
+ /* This isn't actually WM_PROTOCOLS because that wouldn't leave enough space
+ * in the message for everything that gets stuffed in */
+ if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_DRAWN"))
+ {
+ GdkWindowImplX11 *window_impl;
+ window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl);
+ if (window_impl->toplevel)
+ {
+ guint32 d0 = xevent->xclient.data.l[0];
+ guint32 d1 = xevent->xclient.data.l[1];
+ guint32 d2 = xevent->xclient.data.l[2];
+ guint32 d3 = xevent->xclient.data.l[3];
+
+ guint64 serial = ((guint64)d0 << 32) | d1;
+
+ GdkFrameClock *clock = gdk_window_get_frame_clock (event->any.window);
+ GdkFrameTimings *timings = find_frame_timings (clock, serial);
+
+ if (timings)
+ gdk_frame_timings_set_drawn_time (timings, ((guint64)d2 << 32) | d3);
+
+ if (window_impl->toplevel->frame_pending)
+ {
+ window_impl->toplevel->frame_pending = FALSE;
+ gdk_frame_clock_thaw (clock);
+ }
+ }
+
+ return GDK_FILTER_REMOVE;
+ }
+
+ if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_TIMINGS"))
+ {
+ GdkWindowImplX11 *window_impl;
+ window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl);
+ if (window_impl->toplevel)
+ {
+ guint32 d0 = xevent->xclient.data.l[0];
+ guint32 d1 = xevent->xclient.data.l[1];
+ guint32 d2 = xevent->xclient.data.l[2];
+ guint32 d3 = xevent->xclient.data.l[3];
+
+ guint64 serial = ((guint64)d0 << 32) | d1;
+
+ GdkFrameClock *clock = gdk_window_get_frame_clock (event->any.window);
+ GdkFrameTimings *timings = find_frame_timings (clock, serial);
+
+ if (timings)
+ {
+ gint64 drawn_time = gdk_frame_timings_get_drawn_time (timings);
+ gint32 presentation_time_offset = (gint32)d2;
+ gint32 refresh_interval = d3;
+
+ if (drawn_time && presentation_time_offset)
+ gdk_frame_timings_set_presentation_time (timings,
+ drawn_time + presentation_time_offset);
+
+ if (refresh_interval)
+ gdk_frame_timings_set_refresh_interval (timings, refresh_interval);
+
+ gdk_frame_timings_set_complete (timings, TRUE);
+ }
+ }
+ }
+
if (xevent->xclient.message_type != gdk_x11_get_xatom_by_name_for_display (display, "WM_PROTOCOLS"))
return GDK_FILTER_CONTINUE;
return GDK_FILTER_REMOVE;
}
- else if (atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_FRAME_DRAWN"))
- {
- GdkWindowImplX11 *window_impl;
-
- window_impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl);
- if (window_impl->toplevel &&
- window_impl->toplevel->frame_pending)
- {
- window_impl->toplevel->frame_pending = FALSE;
- gdk_frame_clock_thaw (gdk_window_get_frame_clock (event->any.window));
- }
-
- return GDK_FILTER_REMOVE;
- }
-
return GDK_FILTER_CONTINUE;
}
on_frame_clock_after_paint (GdkFrameClock *clock,
GdkWindow *window)
{
+ GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+ GdkFrameHistory *history = gdk_frame_clock_get_history (clock);
+ gint64 frame_counter = gdk_frame_history_get_frame_counter (history);
+ GdkFrameTimings *timings = gdk_frame_history_get_timings (history, frame_counter);
+
gdk_x11_window_end_frame (window);
+
+ if (toplevel->frame_pending)
+ gdk_frame_timings_set_cookie (timings, toplevel->current_counter_value);
+ else
+ gdk_frame_timings_set_complete (timings, TRUE);
}
void