G_DEFINE_TYPE (GtkClutterEmbed, gtk_clutter_embed, GTK_TYPE_WIDGET);
-#define GTK_CLUTTER_EMBED_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_CLUTTER_EMBED, GtkClutterEmbedPrivate))
+#define GTK_CLUTTER_EMBED_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_CLUTTER_TYPE_EMBED, GtkClutterEmbedPrivate))
struct _GtkClutterEmbedPrivate
{
ClutterActor *stage;
+
+ guint queue_redraw_id;
};
static void
}
static void
+on_stage_queue_redraw (ClutterStage *stage,
+ gboolean queue_origin,
+ gpointer user_data)
+{
+ GtkWidget *embed = user_data;
+
+ /* we stop the emission of the Stage::queue-redraw signal to prevent
+ * the default handler from running; then we queue a redraw on the
+ * GtkClutterEmbed widget which will cause an expose event to be
+ * emitted. the Stage is redrawn in the expose event handler, thus
+ * "slaving" the Clutter redraw cycle to GTK+'s own
+ */
+ g_signal_stop_emission_by_name (stage, "queue-redraw");
+
+ gtk_widget_queue_draw (embed);
+}
+
+static void
gtk_clutter_embed_dispose (GObject *gobject)
{
GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (gobject)->priv;
+ if (priv->queue_redraw_id)
+ {
+ g_signal_handler_disconnect (priv->stage, priv->queue_redraw_id);
+ priv->queue_redraw_id = 0;
+ }
+
if (priv->stage)
{
clutter_actor_destroy (priv->stage);
}
static gboolean
+gtk_clutter_embed_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
+
+ /* force a redraw on expose */
+ clutter_redraw (CLUTTER_STAGE (priv->stage));
+
+ return FALSE;
+}
+
+static gboolean
gtk_clutter_embed_motion_notify_event (GtkWidget *widget,
GdkEventMotion *event)
{
}
static gboolean
-gtk_clutter_embed_expose_event (GtkWidget *widget,
- GdkEventExpose *event)
-{
- GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
-
- if (CLUTTER_ACTOR_IS_VISIBLE (priv->stage))
- clutter_actor_queue_redraw (priv->stage);
-
- return FALSE;
-}
-
-static gboolean
gtk_clutter_embed_map_event (GtkWidget *widget,
GdkEventAny *event)
{
}
static void
+gtk_clutter_embed_style_set (GtkWidget *widget,
+ GtkStyle *old_style)
+{
+ GdkScreen *screen;
+ GtkSettings *settings;
+ gdouble dpi;
+ gchar *font_name;
+ const cairo_font_options_t *font_options;
+ gint double_click_time, double_click_distance;
+ ClutterBackend *backend;
+
+ GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->style_set (widget,
+ old_style);
+
+ if (gtk_widget_has_screen (widget))
+ screen = gtk_widget_get_screen (widget);
+ else
+ screen = gdk_screen_get_default ();
+
+ dpi = gdk_screen_get_resolution (screen);
+ if (dpi < 0)
+ dpi = 96.0;
+
+ font_options = gdk_screen_get_font_options (screen);
+
+ settings = gtk_settings_get_for_screen (screen);
+ g_object_get (G_OBJECT (settings),
+ "gtk-font-name", &font_name,
+ "gtk-double-click-time", &double_click_time,
+ "gtk-double-click-distance", &double_click_distance,
+ NULL);
+
+ /* copy all settings and values coming from GTK+ into
+ * the ClutterBackend; this way, a scene embedded into
+ * a GtkClutterEmbed will not look completely alien
+ */
+ backend = clutter_get_default_backend ();
+ clutter_backend_set_resolution (backend, dpi);
+ clutter_backend_set_font_options (backend, font_options);
+ clutter_backend_set_font_name (backend, font_name);
+ clutter_backend_set_double_click_time (backend, double_click_time);
+ clutter_backend_set_double_click_distance (backend, double_click_distance);
+
+ g_free (font_name);
+}
+
+static void
gtk_clutter_embed_class_init (GtkClutterEmbedClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = gtk_clutter_embed_dispose;
+ widget_class->style_set = gtk_clutter_embed_style_set;
widget_class->size_allocate = gtk_clutter_embed_size_allocate;
widget_class->realize = gtk_clutter_embed_realize;
widget_class->show = gtk_clutter_embed_show;
widget_class->hide = gtk_clutter_embed_hide;
+ widget_class->expose_event = gtk_clutter_embed_expose_event;
widget_class->button_press_event = gtk_clutter_embed_button_event;
widget_class->button_release_event = gtk_clutter_embed_button_event;
widget_class->key_press_event = gtk_clutter_embed_key_event;
/* we must realize the stage to get it ready for embedding */
clutter_actor_realize (priv->stage);
+ /* intercept the queue-redraw signal of the stage to know when
+ * Clutter-side requests a redraw; this way we can also request
+ * a redraw GTK-side
+ */
+ priv->queue_redraw_id =
+ g_signal_connect (priv->stage,
+ "queue-redraw", G_CALLBACK (on_stage_queue_redraw),
+ embed);
+
#ifdef HAVE_CLUTTER_GTK_X11
{
const XVisualInfo *xvinfo;
GtkWidget *
gtk_clutter_embed_new (void)
{
- return g_object_new (GTK_TYPE_CLUTTER_EMBED, NULL);
+ return g_object_new (GTK_CLUTTER_TYPE_EMBED, NULL);
}
/**
ClutterActor *
gtk_clutter_embed_get_stage (GtkClutterEmbed *embed)
{
- g_return_val_if_fail (GTK_IS_CLUTTER_EMBED (embed), NULL);
+ g_return_val_if_fail (GTK_CLUTTER_IS_EMBED (embed), NULL);
return embed->priv->stage;
}