Change the GtkClutter macro namespace
[clutter-gtk] / clutter-gtk / gtk-clutter-embed.c
index 87374e5..04519c5 100644 (file)
 
 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
@@ -87,10 +89,34 @@ gtk_clutter_embed_send_configure (GtkClutterEmbed *embed)
 }
 
 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);
@@ -206,6 +232,18 @@ gtk_clutter_embed_size_allocate (GtkWidget     *widget,
 }
 
 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)
 {
@@ -300,18 +338,6 @@ gtk_clutter_embed_key_event (GtkWidget   *widget,
 }
 
 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)
 {
@@ -376,6 +402,53 @@ gtk_clutter_embed_scroll_event (GtkWidget      *widget,
 }
 
 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);
@@ -385,10 +458,12 @@ gtk_clutter_embed_class_init (GtkClutterEmbedClass *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;
@@ -421,6 +496,15 @@ gtk_clutter_embed_init (GtkClutterEmbed *embed)
   /* 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;
@@ -480,7 +564,7 @@ gtk_clutter_init (int    *argc,
 GtkWidget *
 gtk_clutter_embed_new (void)
 {
-  return g_object_new (GTK_TYPE_CLUTTER_EMBED, NULL);
+  return g_object_new (GTK_CLUTTER_TYPE_EMBED, NULL);
 }
 
 /**
@@ -498,7 +582,7 @@ gtk_clutter_embed_new (void)
 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;
 }