Blame clutter-gtk/gtk-clutter-embed.c

Packit 1069cd
/* gtk-clutter-embed.c: Embeddable ClutterStage
Packit 1069cd
 *
Packit 1069cd
 * Copyright (C) 2007 OpenedHand
Packit 1069cd
 *
Packit 1069cd
 * This library is free software; you can redistribute it and/or
Packit 1069cd
 * modify it under the terms of the GNU Lesser General Public
Packit 1069cd
 * License as published by the Free Software Foundation; either
Packit 1069cd
 * version 2 of the License, or (at your option) any later version.
Packit 1069cd
 *
Packit 1069cd
 * This library is distributed in the hope that it will be useful,
Packit 1069cd
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 1069cd
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 1069cd
 * Lesser General Public License for more details.
Packit 1069cd
 *
Packit 1069cd
 * You should have received a copy of the GNU Lesser General Public
Packit 1069cd
 * License along with this library. If not see <http://www.fsf.org/licensing>.
Packit 1069cd
 *
Packit 1069cd
 * Authors:
Packit 1069cd
 *   Iain Holmes  <iain@openedhand.com>
Packit 1069cd
 *   Emmanuele Bassi  <ebassi@openedhand.com>
Packit 1069cd
 */
Packit 1069cd
Packit 1069cd
/**
Packit 1069cd
 * SECTION:gtk-clutter-embed
Packit 1069cd
 * @Title: GtkClutterEmbed
Packit 1069cd
 * @short_description: Widget for embedding a Clutter scene
Packit 1069cd
 * @See_Also: #ClutterStage
Packit 1069cd
 *
Packit 1069cd
 * #GtkClutterEmbed is a GTK+ widget embedding a #ClutterStage inside
Packit 1069cd
 * a GTK+ application.
Packit 1069cd
 *
Packit 1069cd
 * By using a #GtkClutterEmbed widget is possible to build, show and
Packit 1069cd
 * interact with a scene built using Clutter inside a GTK+ application.
Packit 1069cd
 *
Packit 1069cd
 * ## Event handling with GtkClutterEmbed
Packit 1069cd
 *
Packit 1069cd
 * Due to re-entrancy concerns, you should not use GTK event-related
Packit 1069cd
 * API from within event handling signals emitted by Clutter actors
Packit 1069cd
 * inside a #GtkClutterEmbed.
Packit 1069cd
 *
Packit 1069cd
 * Event-related API, like the GTK drag and drop functions, or the
Packit 1069cd
 * GTK grab ones, cause events to be processed inside the GDK event
Packit 1069cd
 * loop; #GtkClutterEmbed and the Clutter event loop may use those
Packit 1069cd
 * events to generate Clutter events, and thus emit signals on
Packit 1069cd
 * #ClutterActors. If you use the event-related signals of a
Packit 1069cd
 * #ClutterActor to call the GTK API, one of the two event loops
Packit 1069cd
 * will try to re-enter into each other, and either cause a crash
Packit 1069cd
 * or simply block your application.
Packit 1069cd
 *
Packit 1069cd
 * To avoid this behavior, you can either:
Packit 1069cd
 *
Packit 1069cd
 *  - only use GTK+ event handling signals to call event-related
Packit 1069cd
 *    GTK functions
Packit 1069cd
 *  - let the main loop re-enter, by calling event-related GTK
Packit 1069cd
 *    functions from within an idle or a timeout callback
Packit 1069cd
 *
Packit 1069cd
 * You should also make sure you're not using GTK widgets that call
Packit 1069cd
 * event-related GTK API, like the grab functions in a #GtkMenu, in
Packit 1069cd
 * response to Clutter actor events.
Packit 1069cd
 *
Packit 1069cd
 * ## Using GtkClutterEmbed as a container
Packit 1069cd
 *
Packit 1069cd
 * Though #GtkClutterEmbed is a #GtkContainer subclass, it is not a
Packit 1069cd
 * real GTK+ container; #GtkClutterEmbed is required to implement the
Packit 1069cd
 * #GtkContainer virtual functions in order to embed a #GtkWidget
Packit 1069cd
 * through the #GtkClutterActor class. Calling gtk_container_add()
Packit 1069cd
 * on a #GtkClutterEmbed will trigger an assertion. It is strongly
Packit 1069cd
 * advised not to override the #GtkContainer implementation when
Packit 1069cd
 * subclassing #GtkClutterEmbed, to avoid breaking internal state.
Packit 1069cd
 */
Packit 1069cd
Packit 1069cd
#include "config.h"
Packit 1069cd
Packit 1069cd
#include <math.h>
Packit 1069cd
#include <string.h>
Packit 1069cd
#include "gtk-clutter-embed.h"
Packit 1069cd
#include "gtk-clutter-offscreen.h"
Packit 1069cd
#include "gtk-clutter-actor.h"
Packit 1069cd
Packit 1069cd
#include <glib-object.h>
Packit 1069cd
Packit 1069cd
#include <gdk/gdk.h>
Packit 1069cd
Packit 1069cd
#if defined(CLUTTER_WINDOWING_X11)
Packit 1069cd
#include <clutter/x11/clutter-x11.h>
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
#if defined(CLUTTER_WINDOWING_GDK)
Packit 1069cd
#include <clutter/gdk/clutter-gdk.h>
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
#if defined(CLUTTER_WINDOWING_WIN32)
Packit 1069cd
#include <clutter/win32/clutter-win32.h>
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
#if defined(CLUTTER_WINDOWING_WAYLAND)
Packit 1069cd
#include <clutter/wayland/clutter-wayland.h>
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_X11)
Packit 1069cd
#include <gdk/gdkx.h>
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_WIN32)
Packit 1069cd
#include <gdk/gdkwin32.h>
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_WAYLAND)
Packit 1069cd
#include <gdk/gdkwayland.h>
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
struct _GtkClutterEmbedPrivate
Packit 1069cd
{
Packit 1069cd
  ClutterActor *stage;
Packit 1069cd
Packit 1069cd
  GList *children;
Packit 1069cd
  int n_active_children;
Packit 1069cd
Packit 1069cd
  guint queue_redraw_id;
Packit 1069cd
  guint queue_relayout_id;
Packit 1069cd
Packit 1069cd
  guint geometry_changed : 1;
Packit 1069cd
  guint use_layout_size : 1;
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
Packit 1069cd
  struct wl_subcompositor *subcompositor;
Packit 1069cd
  struct wl_surface *clutter_surface;
Packit 1069cd
  struct wl_subsurface *subsurface;
Packit 1069cd
#endif
Packit 1069cd
};
Packit 1069cd
Packit 1069cd
static gint num_filter = 0;
Packit 1069cd
Packit 1069cd
enum
Packit 1069cd
{
Packit 1069cd
  PROP_0,
Packit 1069cd
Packit 1069cd
  PROP_USE_LAYOUT_SIZE
Packit 1069cd
};
Packit 1069cd
Packit 1069cd
G_DEFINE_TYPE_WITH_PRIVATE (GtkClutterEmbed, gtk_clutter_embed, GTK_TYPE_CONTAINER)
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_send_configure (GtkClutterEmbed *embed)
Packit 1069cd
{
Packit 1069cd
  GtkWidget *widget;
Packit 1069cd
  GtkAllocation allocation;
Packit 1069cd
  GdkEvent *event = gdk_event_new (GDK_CONFIGURE);
Packit 1069cd
Packit 1069cd
  widget = GTK_WIDGET (embed);
Packit 1069cd
  gtk_widget_get_allocation (widget, &allocation);
Packit 1069cd
Packit 1069cd
  event->configure.window = g_object_ref (gtk_widget_get_window (widget));
Packit 1069cd
  event->configure.send_event = TRUE;
Packit 1069cd
  event->configure.x = allocation.x;
Packit 1069cd
  event->configure.y = allocation.y;
Packit 1069cd
  event->configure.width = allocation.width;
Packit 1069cd
  event->configure.height = allocation.height;
Packit 1069cd
Packit 1069cd
  gtk_widget_event (widget, event);
Packit 1069cd
  gdk_event_free (event);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_ensure_surface (GtkClutterEmbed *embed)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = embed->priv;
Packit 1069cd
Packit 1069cd
  if (priv->subcompositor && !priv->clutter_surface)
Packit 1069cd
    {
Packit 1069cd
      GdkDisplay *display;
Packit 1069cd
      struct wl_compositor *compositor;
Packit 1069cd
Packit 1069cd
      display = gtk_widget_get_display (GTK_WIDGET (embed));
Packit 1069cd
      compositor = gdk_wayland_display_get_wl_compositor (display);
Packit 1069cd
      priv->clutter_surface = wl_compositor_create_surface (compositor);
Packit 1069cd
    }
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_ensure_subsurface (GtkClutterEmbed *embed)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv;
Packit 1069cd
  GtkWidget *widget;
Packit 1069cd
  struct wl_surface *gtk_surface;
Packit 1069cd
  GdkWindow *window;
Packit 1069cd
  gint x, y;
Packit 1069cd
Packit 1069cd
  widget = GTK_WIDGET (embed);
Packit 1069cd
  priv = embed->priv;
Packit 1069cd
Packit 1069cd
  if (priv->subsurface)
Packit 1069cd
    return;
Packit 1069cd
Packit 1069cd
  window = gtk_widget_get_window (widget);
Packit 1069cd
  gtk_surface = gdk_wayland_window_get_wl_surface (gdk_window_get_toplevel (window));
Packit 1069cd
  priv->subsurface =
Packit 1069cd
    wl_subcompositor_get_subsurface (priv->subcompositor,
Packit 1069cd
                                     priv->clutter_surface,
Packit 1069cd
                                     gtk_surface);
Packit 1069cd
Packit 1069cd
  gdk_window_get_origin (window, &x, &y);
Packit 1069cd
  wl_subsurface_set_position (priv->subsurface, x, y);
Packit 1069cd
  wl_subsurface_set_desync (priv->subsurface);
Packit 1069cd
}
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_ensure_stage_realized (GtkClutterEmbed *embed)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (embed)->priv;
Packit 1069cd
Packit 1069cd
  if (!gtk_widget_get_realized (GTK_WIDGET (embed)))
Packit 1069cd
    return;
Packit 1069cd
Packit 1069cd
  if (!clutter_actor_is_realized (priv->stage))
Packit 1069cd
    {
Packit 1069cd
      GdkWindow *window = gtk_widget_get_window (GTK_WIDGET (embed));
Packit 1069cd
Packit 1069cd
#if defined(CLUTTER_WINDOWING_GDK)
Packit 1069cd
      if (clutter_check_windowing_backend (CLUTTER_WINDOWING_GDK))
Packit 1069cd
        {
Packit 1069cd
          clutter_gdk_set_stage_foreign (CLUTTER_STAGE (priv->stage), window);
Packit 1069cd
        }
Packit 1069cd
      else
Packit 1069cd
#endif
Packit 1069cd
#if defined(GDK_WINDOWING_X11) && defined(CLUTTER_WINDOWING_X11)
Packit 1069cd
      if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11) &&
Packit 1069cd
          GDK_IS_X11_WINDOW (window))
Packit 1069cd
        {
Packit 1069cd
          clutter_x11_set_stage_foreign (CLUTTER_STAGE (priv->stage),
Packit 1069cd
                                         GDK_WINDOW_XID (window));
Packit 1069cd
        }
Packit 1069cd
      else
Packit 1069cd
#endif
Packit 1069cd
#if defined(GDK_WINDOWING_WIN32) && defined(CLUTTER_WINDOWING_WIN32)
Packit 1069cd
      if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WIN32) &&
Packit 1069cd
          GDK_IS_WIN32_WINDOW (window))
Packit 1069cd
        {
Packit 1069cd
          clutter_win32_set_stage_foreign (CLUTTER_STAGE (priv->stage),
Packit 1069cd
                                           GDK_WINDOW_HWND (window));
Packit 1069cd
        }
Packit 1069cd
      else
Packit 1069cd
#endif
Packit 1069cd
#if defined(GDK_WINDOWING_WAYLAND) && defined (CLUTTER_WINDOWING_WAYLAND)
Packit 1069cd
      if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND) &&
Packit 1069cd
          GDK_IS_WAYLAND_WINDOW (window))
Packit 1069cd
        {
Packit 1069cd
          gtk_clutter_embed_ensure_surface (embed);
Packit 1069cd
          clutter_wayland_stage_set_wl_surface (CLUTTER_STAGE (priv->stage),
Packit 1069cd
                                                priv->clutter_surface);
Packit 1069cd
        }
Packit 1069cd
      else
Packit 1069cd
#endif
Packit 1069cd
        {
Packit 1069cd
          g_warning ("No backend found!");
Packit 1069cd
        }
Packit 1069cd
Packit 1069cd
      clutter_actor_realize (priv->stage);
Packit 1069cd
    }
Packit 1069cd
Packit 1069cd
  /* A stage cannot really be unmapped because it is the top of
Packit 1069cd
   * Clutter's scene tree. So if the Gtk embedder is mapped, we
Packit 1069cd
   * translate this as visible for the ClutterStage. */
Packit 1069cd
  if (gtk_widget_get_mapped (GTK_WIDGET (embed)))
Packit 1069cd
    clutter_actor_show (priv->stage);
Packit 1069cd
Packit 1069cd
  clutter_actor_queue_relayout (priv->stage);
Packit 1069cd
Packit 1069cd
  gtk_clutter_embed_send_configure (embed);
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_WAYLAND) && defined (CLUTTER_WINDOWING_WAYLAND)
Packit 1069cd
  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND))
Packit 1069cd
    gtk_clutter_embed_ensure_subsurface (embed);
Packit 1069cd
#endif
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_stage_unrealize (GtkClutterEmbed *embed)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = embed->priv;
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
Packit 1069cd
  g_clear_pointer (&priv->subsurface, wl_subsurface_destroy);
Packit 1069cd
  g_clear_pointer (&priv->clutter_surface, wl_surface_destroy);
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
  /* gtk may emit an unmap signal after dispose, so it's possible we
Packit 1069cd
   * may have already disposed priv->stage. */
Packit 1069cd
  if (priv->stage != NULL)
Packit 1069cd
    {
Packit 1069cd
      clutter_actor_hide (priv->stage);
Packit 1069cd
      clutter_actor_unrealize (priv->stage);
Packit 1069cd
    }
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
on_stage_queue_redraw (ClutterStage *stage,
Packit 1069cd
                       ClutterActor *origin,
Packit 1069cd
                       gpointer      user_data)
Packit 1069cd
{
Packit 1069cd
  GtkWidget *embed = user_data;
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (embed)->priv;
Packit 1069cd
Packit 1069cd
  if (priv->n_active_children > 0)
Packit 1069cd
    priv->geometry_changed = TRUE;
Packit 1069cd
Packit 1069cd
  gtk_widget_queue_draw (embed);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
on_stage_queue_relayout (ClutterStage *stage,
Packit 1069cd
			 gpointer      user_data)
Packit 1069cd
{
Packit 1069cd
  GtkWidget *embed = user_data;
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (embed)->priv;
Packit 1069cd
Packit 1069cd
  if (priv->use_layout_size)
Packit 1069cd
    gtk_widget_queue_resize (embed);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_dispose (GObject *gobject)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (gobject)->priv;
Packit 1069cd
Packit 1069cd
Packit 1069cd
  if (priv->stage)
Packit 1069cd
    {
Packit 1069cd
      if (priv->queue_redraw_id)
Packit 1069cd
        g_signal_handler_disconnect (priv->stage, priv->queue_redraw_id);
Packit 1069cd
Packit 1069cd
      if (priv->queue_relayout_id)
Packit 1069cd
        g_signal_handler_disconnect (priv->stage, priv->queue_relayout_id);
Packit 1069cd
Packit 1069cd
      priv->queue_redraw_id = 0;
Packit 1069cd
      priv->queue_relayout_id = 0;
Packit 1069cd
Packit 1069cd
      clutter_actor_destroy (priv->stage);
Packit 1069cd
      priv->stage = NULL;
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
Packit 1069cd
      g_clear_pointer (&priv->subsurface, wl_subsurface_destroy);
Packit 1069cd
#endif
Packit 1069cd
    }
Packit 1069cd
Packit 1069cd
  G_OBJECT_CLASS (gtk_clutter_embed_parent_class)->dispose (gobject);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_show (GtkWidget *widget)
Packit 1069cd
{
Packit 1069cd
  GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->show (widget);
Packit 1069cd
Packit 1069cd
  gtk_clutter_embed_ensure_stage_realized (GTK_CLUTTER_EMBED (widget));
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static GdkWindow *
Packit 1069cd
pick_embedded_child (GdkWindow       *offscreen_window,
Packit 1069cd
                     double           widget_x,
Packit 1069cd
                     double           widget_y,
Packit 1069cd
                     GtkClutterEmbed *embed)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = embed->priv;
Packit 1069cd
  ClutterActor *a;
Packit 1069cd
  GtkWidget *widget;
Packit 1069cd
Packit 1069cd
  a = clutter_stage_get_actor_at_pos (CLUTTER_STAGE (priv->stage),
Packit 1069cd
				      CLUTTER_PICK_REACTIVE,
Packit 1069cd
				      widget_x, widget_y);
Packit 1069cd
  if (GTK_CLUTTER_IS_ACTOR (a))
Packit 1069cd
    {
Packit 1069cd
      widget = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (a));
Packit 1069cd
Packit 1069cd
      if (GTK_CLUTTER_OFFSCREEN (widget)->active)
Packit 1069cd
	return gtk_widget_get_window (widget);
Packit 1069cd
    }
Packit 1069cd
Packit 1069cd
  return NULL;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static GdkFilterReturn
Packit 1069cd
gtk_clutter_filter_func (GdkXEvent *native_event,
Packit 1069cd
                         GdkEvent  *event         G_GNUC_UNUSED,
Packit 1069cd
                         gpointer   user_data     G_GNUC_UNUSED)
Packit 1069cd
{
Packit 1069cd
#if defined(CLUTTER_WINDOWING_X11)
Packit 1069cd
  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
Packit 1069cd
    {
Packit 1069cd
      XEvent *xevent = native_event;
Packit 1069cd
Packit 1069cd
      /* let Clutter handle all events coming from the windowing system */
Packit 1069cd
      clutter_x11_handle_event (xevent);
Packit 1069cd
    }
Packit 1069cd
  else
Packit 1069cd
#endif
Packit 1069cd
#if defined(CLUTTER_WINDOWING_WIN32)
Packit 1069cd
  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WIN32))
Packit 1069cd
    {
Packit 1069cd
      MSG *msg = native_event;
Packit 1069cd
Packit 1069cd
      clutter_win32_handle_event (msg);
Packit 1069cd
    }
Packit 1069cd
  else
Packit 1069cd
#endif
Packit 1069cd
    g_critical ("Unsuppored Clutter backend");
Packit 1069cd
Packit 1069cd
  /* we don't care if Clutter handled the event: we want GDK to continue
Packit 1069cd
   * the event processing as usual
Packit 1069cd
   */
Packit 1069cd
  return GDK_FILTER_CONTINUE;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static gboolean
Packit 1069cd
gtk_clutter_embed_draw (GtkWidget *widget, cairo_t *cr)
Packit 1069cd
{
Packit 1069cd
#if defined(CLUTTER_WINDOWING_GDK)
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
Packit 1069cd
Packit 1069cd
  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_GDK))
Packit 1069cd
    clutter_stage_ensure_redraw (CLUTTER_STAGE (priv->stage));
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
  return GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->draw (widget, cr);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_realize (GtkWidget *widget)
Packit 1069cd
{
Packit 1069cd
  GtkAllocation allocation;
Packit 1069cd
  GtkStyleContext *style_context;
Packit 1069cd
  GdkWindow *window;
Packit 1069cd
  GdkWindowAttr attributes;
Packit 1069cd
  gint attributes_mask;
Packit 1069cd
  gint border_width;
Packit 1069cd
Packit 1069cd
#if defined(CLUTTER_WINDOWING_GDK)
Packit 1069cd
  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_GDK))
Packit 1069cd
    {
Packit 1069cd
      GdkVisual *visual = clutter_gdk_get_visual ();
Packit 1069cd
      gtk_widget_set_visual (widget, visual);
Packit 1069cd
    }
Packit 1069cd
#endif
Packit 1069cd
#if defined(GDK_WINDOWING_X11) && defined(CLUTTER_WINDOWING_X11)
Packit 1069cd
  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
Packit 1069cd
    {
Packit 1069cd
      const XVisualInfo *xvinfo;
Packit 1069cd
      GdkVisual *visual;
Packit 1069cd
Packit 1069cd
      /* We need to use the colormap from the Clutter visual, since
Packit 1069cd
       * the visual is tied to the GLX context
Packit 1069cd
       */
Packit 1069cd
      xvinfo = clutter_x11_get_visual_info ();
Packit 1069cd
      if (xvinfo == None)
Packit 1069cd
        {
Packit 1069cd
          g_critical ("Unable to retrieve the XVisualInfo from Clutter");
Packit 1069cd
          return;
Packit 1069cd
        }
Packit 1069cd
Packit 1069cd
      visual = gdk_x11_screen_lookup_visual (gtk_widget_get_screen (widget),
Packit 1069cd
                                             xvinfo->visualid);
Packit 1069cd
      gtk_widget_set_visual (widget, visual);
Packit 1069cd
    }
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
  gtk_widget_set_realized (widget, TRUE);
Packit 1069cd
Packit 1069cd
  gtk_widget_get_allocation (widget, &allocation);
Packit 1069cd
  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
Packit 1069cd
Packit 1069cd
  attributes.window_type = GDK_WINDOW_CHILD;
Packit 1069cd
  attributes.x = allocation.x + border_width;
Packit 1069cd
  attributes.y = allocation.y + border_width;
Packit 1069cd
  attributes.width = allocation.width - 2 * border_width;
Packit 1069cd
  attributes.height = allocation.height - 2 * border_width;
Packit 1069cd
  attributes.wclass = GDK_INPUT_OUTPUT;
Packit 1069cd
  attributes.visual = gtk_widget_get_visual (widget);
Packit 1069cd
Packit 1069cd
  /* NOTE: GDK_MOTION_NOTIFY above should be safe as Clutter does its own
Packit 1069cd
   *       throttling.
Packit 1069cd
   */
Packit 1069cd
  attributes.event_mask = gtk_widget_get_events (widget)
Packit 1069cd
                        | GDK_EXPOSURE_MASK
Packit 1069cd
                        | GDK_SCROLL_MASK
Packit 1069cd
                        | GDK_BUTTON_PRESS_MASK
Packit 1069cd
                        | GDK_BUTTON_RELEASE_MASK
Packit 1069cd
                        | GDK_KEY_PRESS_MASK
Packit 1069cd
                        | GDK_KEY_RELEASE_MASK
Packit 1069cd
                        | GDK_POINTER_MOTION_MASK
Packit 1069cd
                        | GDK_ENTER_NOTIFY_MASK
Packit 1069cd
                        | GDK_LEAVE_NOTIFY_MASK
Packit 1069cd
                        | GDK_TOUCH_MASK
Packit 1069cd
                        | GDK_SMOOTH_SCROLL_MASK
Packit 1069cd
                        | GDK_STRUCTURE_MASK;
Packit 1069cd
Packit 1069cd
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
Packit 1069cd
Packit 1069cd
  window = gdk_window_new (gtk_widget_get_parent_window (widget),
Packit 1069cd
                           &attributes,
Packit 1069cd
                           attributes_mask);
Packit 1069cd
Packit 1069cd
  gtk_widget_set_window (widget, window);
Packit 1069cd
  gdk_window_set_user_data (window, widget);
Packit 1069cd
Packit 1069cd
  /* this does the translation of the event from Clutter to GDK
Packit 1069cd
   * we embedding a GtkWidget inside a GtkClutterActor
Packit 1069cd
   */
Packit 1069cd
  g_signal_connect (window, "pick-embedded-child",
Packit 1069cd
		    G_CALLBACK (pick_embedded_child),
Packit 1069cd
                    widget);
Packit 1069cd
Packit 1069cd
  style_context = gtk_widget_get_style_context (widget);
Packit 1069cd
  gtk_style_context_set_background (style_context, window);
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_X11) && defined(CLUTTER_WINDOWING_X11)
Packit 1069cd
  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11) &&
Packit 1069cd
      GDK_IS_X11_WINDOW (window))
Packit 1069cd
    {
Packit 1069cd
      if (num_filter == 0)
Packit 1069cd
        gdk_window_add_filter (NULL, gtk_clutter_filter_func, widget);
Packit 1069cd
      num_filter++;
Packit 1069cd
    }
Packit 1069cd
  else
Packit 1069cd
#endif
Packit 1069cd
#if defined(GDK_WINDOWING_WIN32) && defined(CLUTTER_WINDOWING_WIN32)
Packit 1069cd
  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WIN32) &&
Packit 1069cd
      GDK_IS_WIN32_WINDOW (window))
Packit 1069cd
    {
Packit 1069cd
      if (num_filter == 0)
Packit 1069cd
        gdk_window_add_filter (NULL, gtk_clutter_filter_func, widget);
Packit 1069cd
      num_filter++;
Packit 1069cd
    }
Packit 1069cd
  else
Packit 1069cd
#endif
Packit 1069cd
    {
Packit 1069cd
      /* Nothing to do. */
Packit 1069cd
    }
Packit 1069cd
Packit 1069cd
  gtk_clutter_embed_ensure_stage_realized (GTK_CLUTTER_EMBED (widget));
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_unrealize (GtkWidget *widget)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbed *embed = GTK_CLUTTER_EMBED (widget);
Packit 1069cd
Packit 1069cd
  if (num_filter > 0)
Packit 1069cd
    {
Packit 1069cd
      num_filter--;
Packit 1069cd
      if (num_filter == 0)
Packit 1069cd
        gdk_window_remove_filter (NULL, gtk_clutter_filter_func, widget);
Packit 1069cd
    }
Packit 1069cd
Packit 1069cd
  gtk_clutter_embed_stage_unrealize (embed);
Packit 1069cd
Packit 1069cd
  GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->unrealize (widget);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static GtkSizeRequestMode
Packit 1069cd
gtk_clutter_embed_get_request_mode (GtkWidget *widget)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
Packit 1069cd
  GtkSizeRequestMode mode;
Packit 1069cd
Packit 1069cd
  mode = GTK_SIZE_REQUEST_CONSTANT_SIZE;
Packit 1069cd
  if (priv->stage != NULL &&
Packit 1069cd
      priv->use_layout_size &&
Packit 1069cd
      clutter_actor_get_layout_manager (priv->stage) != NULL)
Packit 1069cd
    {
Packit 1069cd
      switch (clutter_actor_get_request_mode (priv->stage))
Packit 1069cd
	{
Packit 1069cd
	case CLUTTER_REQUEST_HEIGHT_FOR_WIDTH:
Packit 1069cd
	  mode = GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
Packit 1069cd
	  break;
Packit 1069cd
	case CLUTTER_REQUEST_WIDTH_FOR_HEIGHT:
Packit 1069cd
	  mode = GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT;
Packit 1069cd
	  break;
Packit 1069cd
        case CLUTTER_REQUEST_CONTENT_SIZE:
Packit 1069cd
          mode = GTK_SIZE_REQUEST_CONSTANT_SIZE;
Packit 1069cd
          break;
Packit 1069cd
	}
Packit 1069cd
    }
Packit 1069cd
Packit 1069cd
  return mode;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_get_preferred_width_for_height (GtkWidget *widget,
Packit 1069cd
						  gint       height,
Packit 1069cd
						  gint      *minimum,
Packit 1069cd
						  gint      *natural)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
Packit 1069cd
  float min, nat;
Packit 1069cd
Packit 1069cd
  min = 0;
Packit 1069cd
  nat = 0;
Packit 1069cd
Packit 1069cd
  if (priv->stage != NULL &&
Packit 1069cd
      priv->use_layout_size)
Packit 1069cd
    {
Packit 1069cd
      ClutterLayoutManager *manager = clutter_actor_get_layout_manager (priv->stage);
Packit 1069cd
      if (manager)
Packit 1069cd
	clutter_layout_manager_get_preferred_width (manager,
Packit 1069cd
						    CLUTTER_CONTAINER (priv->stage),
Packit 1069cd
						    (float)height, &min, &nat);
Packit 1069cd
    }
Packit 1069cd
Packit 1069cd
  min = ceilf (min);
Packit 1069cd
  nat = ceilf (nat);
Packit 1069cd
Packit 1069cd
  if (minimum)
Packit 1069cd
    *minimum = min;
Packit 1069cd
Packit 1069cd
  if (natural)
Packit 1069cd
    *natural = nat;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_get_preferred_height_for_width (GtkWidget *widget,
Packit 1069cd
						  gint       width,
Packit 1069cd
						  gint      *minimum,
Packit 1069cd
						  gint      *natural)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
Packit 1069cd
  float min, nat;
Packit 1069cd
Packit 1069cd
  min = 0;
Packit 1069cd
  nat = 0;
Packit 1069cd
Packit 1069cd
  if (priv->stage != NULL &&
Packit 1069cd
      priv->use_layout_size)
Packit 1069cd
    {
Packit 1069cd
      ClutterLayoutManager *manager = clutter_actor_get_layout_manager (priv->stage);
Packit 1069cd
      if (manager)
Packit 1069cd
	clutter_layout_manager_get_preferred_height (manager,
Packit 1069cd
						     CLUTTER_CONTAINER (priv->stage),
Packit 1069cd
						     (float)width, &min, &nat);
Packit 1069cd
    }
Packit 1069cd
Packit 1069cd
  min = ceilf (min);
Packit 1069cd
  nat = ceilf (nat);
Packit 1069cd
Packit 1069cd
  if (minimum)
Packit 1069cd
    *minimum = min;
Packit 1069cd
Packit 1069cd
  if (natural)
Packit 1069cd
    *natural = nat;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_get_preferred_width (GtkWidget *widget,
Packit 1069cd
				       gint      *minimum,
Packit 1069cd
				       gint      *natural)
Packit 1069cd
{
Packit 1069cd
  gtk_clutter_embed_get_preferred_width_for_height (widget, -1, minimum, natural);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_get_preferred_height (GtkWidget *widget,
Packit 1069cd
					gint      *minimum,
Packit 1069cd
					gint      *natural)
Packit 1069cd
{
Packit 1069cd
  gtk_clutter_embed_get_preferred_height_for_width (widget, -1, minimum, natural);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_size_allocate (GtkWidget     *widget,
Packit 1069cd
                                 GtkAllocation *allocation)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
Packit 1069cd
  int scale_factor = gtk_widget_get_scale_factor (widget);
Packit 1069cd
Packit 1069cd
  gtk_widget_set_allocation (widget, allocation);
Packit 1069cd
Packit 1069cd
  /* change the size of the stage and ensure that the viewport
Packit 1069cd
   * has been updated as well
Packit 1069cd
   */
Packit 1069cd
  clutter_actor_set_size (priv->stage, allocation->width, allocation->height);
Packit 1069cd
Packit 1069cd
  if (gtk_widget_get_realized (widget))
Packit 1069cd
    {
Packit 1069cd
      gdk_window_move_resize (gtk_widget_get_window (widget),
Packit 1069cd
                              allocation->x,
Packit 1069cd
                              allocation->y,
Packit 1069cd
                              allocation->width,
Packit 1069cd
                              allocation->height);
Packit 1069cd
Packit 1069cd
      clutter_stage_ensure_viewport (CLUTTER_STAGE (priv->stage));
Packit 1069cd
Packit 1069cd
      gtk_clutter_embed_send_configure (GTK_CLUTTER_EMBED (widget));
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_X11) && defined(CLUTTER_WINDOWING_X11)
Packit 1069cd
      if (clutter_check_windowing_backend (CLUTTER_WINDOWING_X11) &&
Packit 1069cd
	  GDK_IS_X11_WINDOW (gtk_widget_get_window (widget)))
Packit 1069cd
	{
Packit 1069cd
	  XConfigureEvent xevent = { ConfigureNotify };
Packit 1069cd
	  xevent.window = GDK_WINDOW_XID (gtk_widget_get_window (widget));
Packit 1069cd
	  xevent.width = allocation->width * scale_factor;
Packit 1069cd
	  xevent.height = allocation->height * scale_factor;
Packit 1069cd
Packit 1069cd
	  /* Ensure cogl knows about the new size immediately, as we will
Packit 1069cd
	     draw before we get the ConfigureNotify response. */
Packit 1069cd
	  clutter_x11_handle_event ((XEvent *)&xevent);
Packit 1069cd
	}
Packit 1069cd
#endif
Packit 1069cd
#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
Packit 1069cd
      if (priv->subsurface)
Packit 1069cd
        {
Packit 1069cd
          gint x, y;
Packit 1069cd
          gdk_window_get_origin (gtk_widget_get_window (widget), &x, &y);
Packit 1069cd
          wl_subsurface_set_position (priv->subsurface, x, y);
Packit 1069cd
        }
Packit 1069cd
#endif
Packit 1069cd
    }
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static gboolean
Packit 1069cd
gtk_clutter_embed_map_event (GtkWidget	 *widget,
Packit 1069cd
                             GdkEventAny *event)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbed *embed = GTK_CLUTTER_EMBED (widget);
Packit 1069cd
  GtkClutterEmbedPrivate *priv = embed->priv;
Packit 1069cd
  GtkWidgetClass *parent_class;
Packit 1069cd
  gboolean res = FALSE;
Packit 1069cd
Packit 1069cd
  parent_class = GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class);
Packit 1069cd
  if (parent_class->map_event)
Packit 1069cd
    res = parent_class->map_event (widget, event);
Packit 1069cd
Packit 1069cd
  gtk_clutter_embed_ensure_stage_realized (embed);
Packit 1069cd
Packit 1069cd
  clutter_actor_queue_redraw (priv->stage);
Packit 1069cd
Packit 1069cd
  return res;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static gboolean
Packit 1069cd
gtk_clutter_embed_unmap_event (GtkWidget   *widget,
Packit 1069cd
                               GdkEventAny *event)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbed *embed = GTK_CLUTTER_EMBED (widget);
Packit 1069cd
  GtkWidgetClass *parent_class;
Packit 1069cd
  gboolean res = FALSE;
Packit 1069cd
Packit 1069cd
  parent_class = GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class);
Packit 1069cd
  if (parent_class->unmap_event)
Packit 1069cd
    res = parent_class->unmap_event (widget, event);
Packit 1069cd
Packit 1069cd
  gtk_clutter_embed_stage_unrealize (embed);
Packit 1069cd
Packit 1069cd
  return res;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static gboolean
Packit 1069cd
gtk_clutter_embed_focus_in (GtkWidget     *widget,
Packit 1069cd
                            GdkEventFocus *event)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
Packit 1069cd
Packit 1069cd
  g_signal_emit_by_name (priv->stage, "activate");
Packit 1069cd
Packit 1069cd
  clutter_stage_set_key_focus (CLUTTER_STAGE (priv->stage), NULL);
Packit 1069cd
Packit 1069cd
  return FALSE;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static gboolean
Packit 1069cd
gtk_clutter_embed_focus_out (GtkWidget     *widget,
Packit 1069cd
                             GdkEventFocus *event)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
Packit 1069cd
Packit 1069cd
  g_signal_emit_by_name (priv->stage, "deactivate");
Packit 1069cd
Packit 1069cd
  /* give back key focus to the stage */
Packit 1069cd
  clutter_stage_set_key_focus (CLUTTER_STAGE (priv->stage), NULL);
Packit 1069cd
Packit 1069cd
  return FALSE;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static gboolean
Packit 1069cd
gtk_clutter_embed_key_event (GtkWidget   *widget,
Packit 1069cd
                             GdkEventKey *event)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
Packit 1069cd
  ClutterDeviceManager *manager;
Packit 1069cd
  ClutterInputDevice *device;
Packit 1069cd
  ClutterEvent cevent = { 0, };
Packit 1069cd
Packit 1069cd
  if (event->type == GDK_KEY_PRESS)
Packit 1069cd
    cevent.key.type = CLUTTER_KEY_PRESS;
Packit 1069cd
  else if (event->type == GDK_KEY_RELEASE)
Packit 1069cd
    cevent.key.type = CLUTTER_KEY_RELEASE;
Packit 1069cd
  else
Packit 1069cd
    return FALSE;
Packit 1069cd
Packit 1069cd
  manager = clutter_device_manager_get_default ();
Packit 1069cd
  device = clutter_device_manager_get_core_device (manager, CLUTTER_KEYBOARD_DEVICE);
Packit 1069cd
Packit 1069cd
  cevent.key.stage = CLUTTER_STAGE (priv->stage);
Packit 1069cd
  cevent.key.time = event->time;
Packit 1069cd
  cevent.key.modifier_state = event->state;
Packit 1069cd
  cevent.key.keyval = event->keyval;
Packit 1069cd
  cevent.key.hardware_keycode = event->hardware_keycode;
Packit 1069cd
  cevent.key.unicode_value = gdk_keyval_to_unicode (event->keyval);
Packit 1069cd
  cevent.key.device = device;
Packit 1069cd
Packit 1069cd
  clutter_do_event (&cevent);
Packit 1069cd
Packit 1069cd
  return FALSE;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_style_updated (GtkWidget *widget)
Packit 1069cd
{
Packit 1069cd
  GdkScreen *screen;
Packit 1069cd
  GtkSettings *gtk_settings;
Packit 1069cd
  ClutterSettings *clutter_settings;
Packit 1069cd
  gchar *font_name;
Packit 1069cd
  gint double_click_time, double_click_distance;
Packit 1069cd
#if defined(GDK_WINDOWING_X11) && defined(CLUTTER_WINDOWING_X11)
Packit 1069cd
  gint xft_dpi, xft_hinting, xft_antialias;
Packit 1069cd
  gchar *xft_hintstyle, *xft_rgba;
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
  if (gtk_widget_get_realized (widget))
Packit 1069cd
    {
Packit 1069cd
#if 0
Packit 1069cd
      GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (widget)->priv;
Packit 1069cd
      GtkStyleContext *style_context;
Packit 1069cd
      GtkStateFlags state_flags;
Packit 1069cd
      GdkRGBA *bg_color;
Packit 1069cd
      ClutterColor color;
Packit 1069cd
Packit 1069cd
      style_context = gtk_widget_get_style_context (widget);
Packit 1069cd
      state_flags = gtk_widget_get_state_flags (widget);
Packit 1069cd
      gtk_style_context_get (style_context, state_flags,
Packit 1069cd
                             "background-color", &bg_color,
Packit 1069cd
                             NULL);
Packit 1069cd
Packit 1069cd
      color.red   = CLAMP (bg_color->red   * 255, 0, 255);
Packit 1069cd
      color.green = CLAMP (bg_color->green * 255, 0, 255);
Packit 1069cd
      color.blue  = CLAMP (bg_color->blue  * 255, 0, 255);
Packit 1069cd
      color.alpha = CLAMP (bg_color->alpha * 255, 0, 255);
Packit 1069cd
      clutter_stage_set_color (CLUTTER_STAGE (priv->stage), &color;;
Packit 1069cd
Packit 1069cd
      gdk_rgba_free (bg_color);
Packit 1069cd
#endif
Packit 1069cd
    }
Packit 1069cd
Packit 1069cd
  if (gtk_widget_has_screen (widget))
Packit 1069cd
    screen = gtk_widget_get_screen (widget);
Packit 1069cd
  else
Packit 1069cd
    screen = gdk_screen_get_default ();
Packit 1069cd
Packit 1069cd
  gtk_settings = gtk_settings_get_for_screen (screen);
Packit 1069cd
  g_object_get (G_OBJECT (gtk_settings),
Packit 1069cd
                "gtk-font-name", &font_name,
Packit 1069cd
                "gtk-double-click-time", &double_click_time,
Packit 1069cd
                "gtk-double-click-distance", &double_click_distance,
Packit 1069cd
                NULL);
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_X11) && defined(CLUTTER_WINDOWING_X11)
Packit 1069cd
  if (GDK_IS_X11_SCREEN (screen))
Packit 1069cd
    {
Packit 1069cd
      g_object_get (G_OBJECT (gtk_settings),
Packit 1069cd
                    "gtk-xft-dpi", &xft_dpi,
Packit 1069cd
                    "gtk-xft-antialias", &xft_antialias,
Packit 1069cd
                    "gtk-xft-hinting", &xft_hinting,
Packit 1069cd
                    "gtk-xft-hintstyle", &xft_hintstyle,
Packit 1069cd
                    "gtk-xft-rgba", &xft_rgba,
Packit 1069cd
                    NULL);
Packit 1069cd
    }
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
  /* copy all settings and values coming from GTK+ into
Packit 1069cd
   * the ClutterBackend; this way, a scene embedded into
Packit 1069cd
   * a GtkClutterEmbed will not look completely alien
Packit 1069cd
   */
Packit 1069cd
  clutter_settings = clutter_settings_get_default ();
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_X11) && defined(CLUTTER_WINDOWING_X11)
Packit 1069cd
  if (GDK_IS_X11_SCREEN (screen))
Packit 1069cd
    {
Packit 1069cd
      g_object_set (G_OBJECT (clutter_settings),
Packit 1069cd
                    "font-name", font_name,
Packit 1069cd
                    "double-click-time", double_click_time,
Packit 1069cd
                    "double-click-distance", double_click_distance,
Packit 1069cd
                    "font-antialias", xft_antialias,
Packit 1069cd
                    "font-dpi", xft_dpi,
Packit 1069cd
                    "font-hinting", xft_hinting,
Packit 1069cd
                    "font-hint-style", xft_hintstyle,
Packit 1069cd
                    "font-subpixel-order", xft_rgba,
Packit 1069cd
                    NULL);
Packit 1069cd
    }
Packit 1069cd
  else
Packit 1069cd
#endif
Packit 1069cd
    {
Packit 1069cd
      g_object_set (G_OBJECT (clutter_settings),
Packit 1069cd
                    "font-name", font_name,
Packit 1069cd
                    "double-click-time", double_click_time,
Packit 1069cd
                    "double-click-distance", double_click_distance,
Packit 1069cd
                    NULL);
Packit 1069cd
    }
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_X11) && defined(CLUTTER_WINDOWING_X11)
Packit 1069cd
  if (GDK_IS_X11_SCREEN (screen))
Packit 1069cd
    {
Packit 1069cd
      g_free (xft_hintstyle);
Packit 1069cd
      g_free (xft_rgba);
Packit 1069cd
    }
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
  g_free (font_name);
Packit 1069cd
Packit 1069cd
  GTK_WIDGET_CLASS (gtk_clutter_embed_parent_class)->style_updated (widget);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
void
Packit 1069cd
_gtk_clutter_embed_set_child_active (GtkClutterEmbed *embed,
Packit 1069cd
                                     GtkWidget       *child,
Packit 1069cd
                                     gboolean         active)
Packit 1069cd
{
Packit 1069cd
  GdkWindow *child_window;
Packit 1069cd
Packit 1069cd
  child_window = gtk_widget_get_window (child);
Packit 1069cd
Packit 1069cd
  if (active)
Packit 1069cd
    {
Packit 1069cd
      embed->priv->n_active_children++;
Packit 1069cd
      gdk_offscreen_window_set_embedder (child_window,
Packit 1069cd
					 gtk_widget_get_window (GTK_WIDGET (embed)));
Packit 1069cd
    }
Packit 1069cd
  else
Packit 1069cd
    {
Packit 1069cd
      embed->priv->n_active_children--;
Packit 1069cd
      gdk_offscreen_window_set_embedder (child_window,
Packit 1069cd
					 NULL);
Packit 1069cd
    }
Packit 1069cd
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_add (GtkContainer *container,
Packit 1069cd
		       GtkWidget    *widget)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (container)->priv;
Packit 1069cd
Packit 1069cd
#ifndef G_DISABLE_ASSERT
Packit 1069cd
  if (G_UNLIKELY (!GTK_CLUTTER_IS_OFFSCREEN (widget)))
Packit 1069cd
    {
Packit 1069cd
      g_critical ("Widgets of type '%s' do not support children.",
Packit 1069cd
                  G_OBJECT_TYPE_NAME (container));
Packit 1069cd
      return;
Packit 1069cd
    }
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
  priv->children = g_list_prepend (priv->children, widget);
Packit 1069cd
  gtk_widget_set_parent (widget, GTK_WIDGET (container));
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_remove (GtkContainer *container,
Packit 1069cd
			  GtkWidget    *widget)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (container)->priv;
Packit 1069cd
  GList *l;
Packit 1069cd
Packit 1069cd
  l = g_list_find (priv->children, widget);
Packit 1069cd
  if (l != NULL)
Packit 1069cd
    {
Packit 1069cd
      priv->children = g_list_delete_link (priv->children, l);
Packit 1069cd
      gtk_widget_unparent (widget);
Packit 1069cd
    }
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_forall (GtkContainer	 *container,
Packit 1069cd
			  gboolean	  include_internals,
Packit 1069cd
			  GtkCallback	  callback,
Packit 1069cd
			  gpointer	  callback_data)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = GTK_CLUTTER_EMBED (container)->priv;
Packit 1069cd
  GList *l;
Packit 1069cd
Packit 1069cd
  if (include_internals)
Packit 1069cd
    {
Packit 1069cd
      for (l = priv->children; l != NULL; l = l->next)
Packit 1069cd
	callback (l->data, callback_data);
Packit 1069cd
    }
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static GType
Packit 1069cd
gtk_clutter_embed_child_type (GtkContainer *container)
Packit 1069cd
{
Packit 1069cd
  /* we only accept GtkClutterOffscreen children */
Packit 1069cd
  return GTK_CLUTTER_TYPE_OFFSCREEN;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static gboolean
Packit 1069cd
gtk_clutter_embed_event (GtkWidget *widget,
Packit 1069cd
                         GdkEvent  *event)
Packit 1069cd
{
Packit 1069cd
#if defined(CLUTTER_WINDOWING_GDK)
Packit 1069cd
  if (clutter_check_windowing_backend (CLUTTER_WINDOWING_GDK))
Packit 1069cd
    clutter_gdk_handle_event (event);
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
  return FALSE;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_set_property (GObject       *gobject,
Packit 1069cd
                                guint          prop_id,
Packit 1069cd
                                const GValue *value,
Packit 1069cd
                                GParamSpec   *pspec)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbed *embed = GTK_CLUTTER_EMBED (gobject);
Packit 1069cd
Packit 1069cd
  switch (prop_id)
Packit 1069cd
    {
Packit 1069cd
    case PROP_USE_LAYOUT_SIZE:
Packit 1069cd
      gtk_clutter_embed_set_use_layout_size (embed, g_value_get_boolean (value));
Packit 1069cd
      break;
Packit 1069cd
Packit 1069cd
    default:
Packit 1069cd
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
Packit 1069cd
      break;
Packit 1069cd
    }
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_get_property (GObject    *gobject,
Packit 1069cd
                                guint       prop_id,
Packit 1069cd
                                GValue     *value,
Packit 1069cd
                                GParamSpec *pspec)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbed *embed = GTK_CLUTTER_EMBED (gobject);
Packit 1069cd
Packit 1069cd
  switch (prop_id)
Packit 1069cd
    {
Packit 1069cd
    case PROP_USE_LAYOUT_SIZE:
Packit 1069cd
      g_value_set_boolean (value, embed->priv->use_layout_size);
Packit 1069cd
      break;
Packit 1069cd
Packit 1069cd
    default:
Packit 1069cd
      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
Packit 1069cd
      break;
Packit 1069cd
    }
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_class_init (GtkClutterEmbedClass *klass)
Packit 1069cd
{
Packit 1069cd
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit 1069cd
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
Packit 1069cd
  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
Packit 1069cd
  GParamSpec *pspec;
Packit 1069cd
Packit 1069cd
  gobject_class->dispose = gtk_clutter_embed_dispose;
Packit 1069cd
  gobject_class->set_property = gtk_clutter_embed_set_property;
Packit 1069cd
  gobject_class->get_property = gtk_clutter_embed_get_property;
Packit 1069cd
Packit 1069cd
  widget_class->style_updated = gtk_clutter_embed_style_updated;
Packit 1069cd
  widget_class->size_allocate = gtk_clutter_embed_size_allocate;
Packit 1069cd
  widget_class->draw = gtk_clutter_embed_draw;
Packit 1069cd
  widget_class->realize = gtk_clutter_embed_realize;
Packit 1069cd
  widget_class->unrealize = gtk_clutter_embed_unrealize;
Packit 1069cd
  widget_class->show = gtk_clutter_embed_show;
Packit 1069cd
  widget_class->map_event = gtk_clutter_embed_map_event;
Packit 1069cd
  widget_class->unmap_event = gtk_clutter_embed_unmap_event;
Packit 1069cd
  widget_class->focus_in_event = gtk_clutter_embed_focus_in;
Packit 1069cd
  widget_class->focus_out_event = gtk_clutter_embed_focus_out;
Packit 1069cd
  widget_class->key_press_event = gtk_clutter_embed_key_event;
Packit 1069cd
  widget_class->key_release_event = gtk_clutter_embed_key_event;
Packit 1069cd
  widget_class->event = gtk_clutter_embed_event;
Packit 1069cd
  widget_class->get_request_mode = gtk_clutter_embed_get_request_mode;
Packit 1069cd
  widget_class->get_preferred_width = gtk_clutter_embed_get_preferred_width;
Packit 1069cd
  widget_class->get_preferred_height = gtk_clutter_embed_get_preferred_height;
Packit 1069cd
  widget_class->get_preferred_width_for_height = gtk_clutter_embed_get_preferred_width_for_height;
Packit 1069cd
  widget_class->get_preferred_height_for_width = gtk_clutter_embed_get_preferred_height_for_width;
Packit 1069cd
Packit 1069cd
  container_class->add = gtk_clutter_embed_add;
Packit 1069cd
  container_class->remove = gtk_clutter_embed_remove;
Packit 1069cd
  container_class->forall = gtk_clutter_embed_forall;
Packit 1069cd
  container_class->child_type = gtk_clutter_embed_child_type;
Packit 1069cd
Packit 1069cd
Packit 1069cd
  /**
Packit 1069cd
   * GtkClutterEmbed:use-layout-size:
Packit 1069cd
   *
Packit 1069cd
   * The #GtkWidget to be embedded into the #GtkClutterActor
Packit 1069cd
   *
Packit 1069cd
   * Since: 1.4
Packit 1069cd
   */
Packit 1069cd
  pspec = g_param_spec_boolean ("use-layout-size",
Packit 1069cd
                                "Use layout size",
Packit 1069cd
				"Whether to use the reported size of the LayoutManager on the stage as the widget size.",
Packit 1069cd
				FALSE,
Packit 1069cd
				G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
Packit 1069cd
  g_object_class_install_property (gobject_class, PROP_USE_LAYOUT_SIZE, pspec);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
Packit 1069cd
static void
Packit 1069cd
registry_handle_global (void *data,
Packit 1069cd
                        struct wl_registry *registry,
Packit 1069cd
                        uint32_t name,
Packit 1069cd
                        const char *interface,
Packit 1069cd
                        uint32_t version)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbed *embed = data;
Packit 1069cd
  GtkClutterEmbedPrivate *priv = embed->priv;
Packit 1069cd
Packit 1069cd
  if (strcmp (interface, "wl_subcompositor") == 0)
Packit 1069cd
    {
Packit 1069cd
      priv->subcompositor = wl_registry_bind (registry,
Packit 1069cd
                                              name,
Packit 1069cd
                                              &wl_subcompositor_interface,
Packit 1069cd
                                              1);
Packit 1069cd
    }
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
registry_handle_global_remove (void *data,
Packit 1069cd
                               struct wl_registry *registry,
Packit 1069cd
                               uint32_t name)
Packit 1069cd
{
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
static const struct wl_registry_listener registry_listener = {
Packit 1069cd
  registry_handle_global,
Packit 1069cd
  registry_handle_global_remove
Packit 1069cd
};
Packit 1069cd
#endif
Packit 1069cd
Packit 1069cd
static void
Packit 1069cd
gtk_clutter_embed_init (GtkClutterEmbed *embed)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv;
Packit 1069cd
  GtkWidget *widget;
Packit 1069cd
Packit 1069cd
  embed->priv = priv = gtk_clutter_embed_get_instance_private (embed);
Packit 1069cd
  widget = GTK_WIDGET (embed);
Packit 1069cd
Packit 1069cd
  /* we have a real window backing our drawing */
Packit 1069cd
  gtk_widget_set_has_window (widget, TRUE);
Packit 1069cd
Packit 1069cd
  /* we accept key focus */
Packit 1069cd
  gtk_widget_set_can_focus (widget, TRUE);
Packit 1069cd
Packit 1069cd
  /* we own the whole drawing of this widget, including the background */
Packit 1069cd
  gtk_widget_set_app_paintable (widget, TRUE);
Packit 1069cd
Packit 1069cd
  /* this widget should expand in both directions */
Packit 1069cd
  gtk_widget_set_hexpand (widget, TRUE);
Packit 1069cd
  gtk_widget_set_vexpand (widget, TRUE);
Packit 1069cd
Packit 1069cd
  /* we always create new stages rather than use the default */
Packit 1069cd
  priv->stage = clutter_stage_new ();
Packit 1069cd
  g_object_set_data (G_OBJECT (priv->stage),
Packit 1069cd
		     "gtk-clutter-embed",
Packit 1069cd
		     embed);
Packit 1069cd
Packit 1069cd
  /* intercept the queue-redraw signal of the stage to know when
Packit 1069cd
   * Clutter-side requests a redraw; this way we can also request
Packit 1069cd
   * a redraw GTK-side
Packit 1069cd
   */
Packit 1069cd
  priv->queue_redraw_id =
Packit 1069cd
    g_signal_connect (priv->stage,
Packit 1069cd
                      "queue-redraw", G_CALLBACK (on_stage_queue_redraw),
Packit 1069cd
                      embed);
Packit 1069cd
Packit 1069cd
  /* intercept the queue-relayout signal of the stage to know when
Packit 1069cd
   * Clutter-side needs to renegotiate it's size; this way we can
Packit 1069cd
   * also request a resize GTK-side
Packit 1069cd
   */
Packit 1069cd
  priv->queue_relayout_id =
Packit 1069cd
    g_signal_connect (priv->stage,
Packit 1069cd
                      "queue-relayout", G_CALLBACK (on_stage_queue_relayout),
Packit 1069cd
                      embed);
Packit 1069cd
Packit 1069cd
Packit 1069cd
#if defined(GDK_WINDOWING_WAYLAND) && defined(CLUTTER_WINDOWING_WAYLAND)
Packit 1069cd
  {
Packit 1069cd
    GdkDisplay *gdk_display = gtk_widget_get_display (widget);
Packit 1069cd
    if (clutter_check_windowing_backend (CLUTTER_WINDOWING_WAYLAND) &&
Packit 1069cd
        GDK_IS_WAYLAND_DISPLAY (gdk_display))
Packit 1069cd
      {
Packit 1069cd
        struct wl_display *display;
Packit 1069cd
        struct wl_registry *registry;
Packit 1069cd
Packit 1069cd
        display = gdk_wayland_display_get_wl_display (gdk_display);
Packit 1069cd
        registry = wl_display_get_registry (display);
Packit 1069cd
        wl_registry_add_listener (registry, &registry_listener, embed);
Packit 1069cd
Packit 1069cd
        wl_display_roundtrip (display);
Packit 1069cd
      }
Packit 1069cd
  }
Packit 1069cd
#endif
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
/**
Packit 1069cd
 * gtk_clutter_embed_new:
Packit 1069cd
 *
Packit 1069cd
 * Creates a new #GtkClutterEmbed widget. This widget can be
Packit 1069cd
 * used to build a scene using Clutter API into a GTK+ application.
Packit 1069cd
 *
Packit 1069cd
 * Return value: the newly created #GtkClutterEmbed
Packit 1069cd
 */
Packit 1069cd
GtkWidget *
Packit 1069cd
gtk_clutter_embed_new (void)
Packit 1069cd
{
Packit 1069cd
  return g_object_new (GTK_CLUTTER_TYPE_EMBED, NULL);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
/**
Packit 1069cd
 * gtk_clutter_embed_get_stage:
Packit 1069cd
 * @embed: a #GtkClutterEmbed
Packit 1069cd
 *
Packit 1069cd
 * Retrieves the #ClutterStage from @embed. The returned stage can be
Packit 1069cd
 * used to add actors to the Clutter scene.
Packit 1069cd
 *
Packit 1069cd
 * Return value: (transfer none): the Clutter stage. You should never
Packit 1069cd
 *   destroy or unref the returned actor.
Packit 1069cd
 */
Packit 1069cd
ClutterActor *
Packit 1069cd
gtk_clutter_embed_get_stage (GtkClutterEmbed *embed)
Packit 1069cd
{
Packit 1069cd
  g_return_val_if_fail (GTK_CLUTTER_IS_EMBED (embed), NULL);
Packit 1069cd
Packit 1069cd
  return embed->priv->stage;
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
/**
Packit 1069cd
 * gtk_clutter_embed_set_use_layout_size:
Packit 1069cd
 * @embed: a #GtkClutterEmbed
Packit 1069cd
 * @use_layout_size: a boolean
Packit 1069cd
 *
Packit 1069cd
 * Changes the way @embed requests size. If @use_layout_size is
Packit 1069cd
 * %TRUE, the @embed widget will request the size that the
Packit 1069cd
 * LayoutManager reports as the preferred size. This means that
Packit 1069cd
 * a Gtk+ window will automatically get the natural and minimum
Packit 1069cd
 * toplevel window sizes. This is useful when the contents of the
Packit 1069cd
 * clutter stage is similar to a traditional UI.
Packit 1069cd
 *
Packit 1069cd
 * If @use_layout_size is %FALSE (which is the default) then @embed
Packit 1069cd
 * will not request any size and its up to the embedder to make sure
Packit 1069cd
 * there is some size (by setting a custom size on the widget or a default
Packit 1069cd
 * size on the toplevel. This makes more sense when using the @embed
Packit 1069cd
 * as a viewport into a potentially unlimited clutter space.
Packit 1069cd
 *
Packit 1069cd
 * Since: 1.4
Packit 1069cd
 */
Packit 1069cd
void
Packit 1069cd
gtk_clutter_embed_set_use_layout_size (GtkClutterEmbed *embed,
Packit 1069cd
                                       gboolean use_layout_size)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = embed->priv;
Packit 1069cd
Packit 1069cd
  g_return_if_fail (GTK_CLUTTER_IS_EMBED (embed));
Packit 1069cd
Packit 1069cd
  use_layout_size = !!use_layout_size;
Packit 1069cd
  if (use_layout_size != priv->use_layout_size)
Packit 1069cd
    {
Packit 1069cd
      priv->use_layout_size = use_layout_size;
Packit 1069cd
      gtk_widget_queue_resize (GTK_WIDGET (embed));
Packit 1069cd
      g_object_notify (G_OBJECT (embed), "use-layout-size");
Packit 1069cd
   }
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
extern gboolean
Packit 1069cd
gtk_clutter_embed_get_honor_stage_size (GtkClutterEmbed *embed);
Packit 1069cd
Packit 1069cd
gboolean
Packit 1069cd
gtk_clutter_embed_get_honor_stage_size (GtkClutterEmbed *embed)
Packit 1069cd
{
Packit 1069cd
  return gtk_clutter_embed_get_use_layout_size (embed);
Packit 1069cd
}
Packit 1069cd
Packit 1069cd
/**
Packit 1069cd
 * gtk_clutter_embed_get_use_layout_size:
Packit 1069cd
 * @embed: a #GtkClutterEmbed
Packit 1069cd
 *
Packit 1069cd
 * Retrieves whether the embedding uses the layout size, see
Packit 1069cd
 * gtk_clutter_embed_set_use_layout_size() for details.
Packit 1069cd
 *
Packit 1069cd
 * Return value: %TRUE if reporting stage size as widget size, %FALSE otherwise.
Packit 1069cd
 *
Packit 1069cd
 * Since: 1.4
Packit 1069cd
 */
Packit 1069cd
gboolean
Packit 1069cd
gtk_clutter_embed_get_use_layout_size (GtkClutterEmbed *embed)
Packit 1069cd
{
Packit 1069cd
  GtkClutterEmbedPrivate *priv = embed->priv;
Packit 1069cd
Packit 1069cd
  g_return_val_if_fail (GTK_CLUTTER_IS_EMBED (embed), FALSE);
Packit 1069cd
Packit 1069cd
  return priv->use_layout_size;
Packit 1069cd
}