|
Packit |
1069cd |
/* gtk-clutter-actor.c: Gtk widget ClutterActor
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* Copyright (C) 2009 Red Hat, Inc
|
|
Packit |
1069cd |
* Copyright (C) 2010 Intel Corp
|
|
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 |
* Alexander Larsson <alexl@redhat.com>
|
|
Packit |
1069cd |
* Danielle Madeley <danielle.madeley@collabora.co.uk>
|
|
Packit |
1069cd |
* Emmanuele Bassi <ebassi@linux.intel.com>
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/**
|
|
Packit |
1069cd |
* SECTION:gtk-clutter-actor
|
|
Packit |
1069cd |
* @title: GtkClutterActor
|
|
Packit |
1069cd |
* @short_description: actor for embedding a Widget in a Clutter stage
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* #GtkClutterActor is a #ClutterContainer that also allows embedding
|
|
Packit |
1069cd |
* any #GtkWidget in a Clutter scenegraph.
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* #GtkClutterActor only allows embedding #GtkWidgets when inside
|
|
Packit |
1069cd |
* the #ClutterStage provided by a #GtkClutterEmbed: it is not possible to
|
|
Packit |
1069cd |
* use #GtkClutterActor in a #ClutterStage handled by Clutter alone.
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#include "config.h"
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#include "gtk-clutter-actor-internal.h"
|
|
Packit |
1069cd |
#include "gtk-clutter-offscreen.h"
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#include <math.h>
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#include <glib-object.h>
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#include <gdk/gdk.h>
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#ifdef CLUTTER_WINDOWING_X11
|
|
Packit |
1069cd |
#include <clutter/x11/clutter-x11.h>
|
|
Packit |
1069cd |
#endif
|
|
Packit |
1069cd |
#ifdef GDK_WINDOWING_X11
|
|
Packit |
1069cd |
#include <gdk/gdkx.h>
|
|
Packit |
1069cd |
#endif
|
|
Packit |
1069cd |
#ifdef CAIRO_HAS_XLIB_SURFACE
|
|
Packit |
1069cd |
#include <cairo/cairo-xlib.h>
|
|
Packit |
1069cd |
#endif
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#ifdef CLUTTER_WINDOWING_WIN32
|
|
Packit |
1069cd |
#include <clutter/win32/clutter-win32.h>
|
|
Packit |
1069cd |
#endif
|
|
Packit |
1069cd |
#ifdef GDK_WINDOWING_WIN32
|
|
Packit |
1069cd |
#include <gdk/gdkwin32.h>
|
|
Packit |
1069cd |
#endif
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
G_DEFINE_TYPE (GtkClutterActor, gtk_clutter_actor, CLUTTER_TYPE_ACTOR)
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#define GTK_CLUTTER_ACTOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_CLUTTER_TYPE_ACTOR, GtkClutterActorPrivate))
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/* #define ENABLE_DEBUG 1 */
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#ifdef ENABLE_DEBUG
|
|
Packit |
1069cd |
#define DEBUG(x) g_printerr(x)
|
|
Packit |
1069cd |
#else
|
|
Packit |
1069cd |
#define DEBUG(x)
|
|
Packit |
1069cd |
#endif
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
struct _GtkClutterActorPrivate
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkWidget *widget;
|
|
Packit |
1069cd |
GtkWidget *embed;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#ifdef CLUTTER_WINDOWING_X11
|
|
Packit |
1069cd |
Drawable pixmap;
|
|
Packit |
1069cd |
#endif
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/* canvas instance used as a fallback; owned
|
|
Packit |
1069cd |
* by the texture actor below
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
ClutterContent *canvas;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
ClutterActor *texture;
|
|
Packit |
1069cd |
};
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
enum
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
PROP_0,
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
PROP_CONTENTS
|
|
Packit |
1069cd |
};
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/* we allow overriding the default platform-specific code with an
|
|
Packit |
1069cd |
* environment variable
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
static inline gboolean
|
|
Packit |
1069cd |
gtk_clutter_actor_use_image_surface (void)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
static const char *env = NULL;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (G_UNLIKELY (env == NULL))
|
|
Packit |
1069cd |
env = g_getenv ("GTK_CLUTTER_ACTOR_SURFACE");
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
return g_strcmp0 (env, "image") == 0;
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/* paints the GtkClutterActorPrivate:surface on the cairo_t provided by
|
|
Packit |
1069cd |
* a ClutterCanvas, if we use the fallback path. this implies a copy,
|
|
Packit |
1069cd |
* plus a copy when we move the contents of the surface we use in the
|
|
Packit |
1069cd |
* ClutterCanvas on to the GPU, but it's the most portable method we have
|
|
Packit |
1069cd |
* at our disposal to implement embedding GTK widgets into Clutter actors.
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
static gboolean
|
|
Packit |
1069cd |
gtk_clutter_actor_draw_canvas (ClutterCanvas *canvas,
|
|
Packit |
1069cd |
cairo_t *cr,
|
|
Packit |
1069cd |
int width,
|
|
Packit |
1069cd |
int height,
|
|
Packit |
1069cd |
GtkClutterActor *actor)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = actor->priv;
|
|
Packit |
1069cd |
cairo_surface_t *surface =
|
|
Packit |
1069cd |
_gtk_clutter_offscreen_get_surface (GTK_CLUTTER_OFFSCREEN (priv->widget));
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/* clear the surface */
|
|
Packit |
1069cd |
cairo_save (cr);
|
|
Packit |
1069cd |
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 1.0);
|
|
Packit |
1069cd |
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
|
Packit |
1069cd |
cairo_paint (cr);
|
|
Packit |
1069cd |
cairo_restore (cr);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
|
Packit |
1069cd |
cairo_set_source_surface (cr, surface, 0.0, 0.0);
|
|
Packit |
1069cd |
cairo_paint (cr);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
return TRUE;
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_dispose (GObject *object)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = GTK_CLUTTER_ACTOR (object)->priv;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (priv->widget != NULL)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
gtk_widget_destroy (priv->widget);
|
|
Packit |
1069cd |
priv->widget = NULL;
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (priv->texture != NULL)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
clutter_actor_destroy (priv->texture);
|
|
Packit |
1069cd |
priv->texture = NULL;
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
G_OBJECT_CLASS (gtk_clutter_actor_parent_class)->dispose (object);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_realize (ClutterActor *actor)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActor *clutter = GTK_CLUTTER_ACTOR (actor);
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = clutter->priv;
|
|
Packit |
1069cd |
ClutterActor *stage;
|
|
Packit |
1069cd |
cairo_surface_t *surface;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
stage = clutter_actor_get_stage (actor);
|
|
Packit |
1069cd |
priv->embed = g_object_get_data (G_OBJECT (stage), "gtk-clutter-embed");
|
|
Packit |
1069cd |
gtk_container_add (GTK_CONTAINER (priv->embed), priv->widget);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
gtk_widget_realize (priv->widget);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
surface = _gtk_clutter_offscreen_get_surface (GTK_CLUTTER_OFFSCREEN (priv->widget));
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#if defined(CLUTTER_WINDOWING_X11) && defined(CAIRO_HAS_XLIB_SURFACE)
|
|
Packit |
1069cd |
if (!gtk_clutter_actor_use_image_surface () &&
|
|
Packit |
1069cd |
clutter_check_windowing_backend (CLUTTER_WINDOWING_X11) &&
|
|
Packit |
1069cd |
cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
gint pixmap_width, pixmap_height;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
pixmap_width = cairo_xlib_surface_get_width (surface);
|
|
Packit |
1069cd |
pixmap_height = cairo_xlib_surface_get_height (surface);
|
|
Packit |
1069cd |
priv->pixmap = cairo_xlib_surface_get_drawable (surface);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
clutter_x11_texture_pixmap_set_pixmap (CLUTTER_X11_TEXTURE_PIXMAP (priv->texture), priv->pixmap);
|
|
Packit |
1069cd |
clutter_actor_set_size (priv->texture, pixmap_width, pixmap_height);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
else
|
|
Packit |
1069cd |
#endif
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GdkWindow *window = gtk_widget_get_window (priv->widget);
|
|
Packit |
1069cd |
int width = gtk_widget_get_allocated_width (priv->widget);
|
|
Packit |
1069cd |
int height = gtk_widget_get_allocated_height (priv->widget);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
DEBUG (G_STRLOC ": Using image surface.\n");
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
clutter_actor_set_size (priv->texture, width, height);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
clutter_canvas_set_scale_factor (CLUTTER_CANVAS (priv->canvas),
|
|
Packit |
1069cd |
gdk_window_get_scale_factor (window));
|
|
Packit |
1069cd |
/* clutter_canvas_set_size() will invalidate its contents only
|
|
Packit |
1069cd |
* if the size differs, but we want to invalidate the contents
|
|
Packit |
1069cd |
* in any case; we cannot call clutter_content_invalidate()
|
|
Packit |
1069cd |
* unconditionally, though, because that may cause two
|
|
Packit |
1069cd |
* invalidations in a row, so we check the size of the canvas
|
|
Packit |
1069cd |
* first.
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
if (!clutter_canvas_set_size (CLUTTER_CANVAS (priv->canvas), width, height))
|
|
Packit |
1069cd |
clutter_content_invalidate (priv->canvas);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_unrealize (ClutterActor *actor)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActor *clutter = GTK_CLUTTER_ACTOR (actor);
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = clutter->priv;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (priv->widget == NULL)
|
|
Packit |
1069cd |
return;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
g_object_ref (priv->widget);
|
|
Packit |
1069cd |
gtk_container_remove (GTK_CONTAINER (priv->embed), priv->widget);
|
|
Packit |
1069cd |
priv->embed = NULL;
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_get_preferred_width (ClutterActor *actor,
|
|
Packit |
1069cd |
gfloat for_height,
|
|
Packit |
1069cd |
gfloat *min_width_p,
|
|
Packit |
1069cd |
gfloat *natural_width_p)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActor *clutter = GTK_CLUTTER_ACTOR (actor);
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = clutter->priv;
|
|
Packit |
1069cd |
gint min_width, natural_width;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
min_width = natural_width = 0;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (for_height >= 0)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
for_height = ceilf (for_height);
|
|
Packit |
1069cd |
gtk_widget_get_preferred_width_for_height (priv->widget,
|
|
Packit |
1069cd |
for_height,
|
|
Packit |
1069cd |
&min_width,
|
|
Packit |
1069cd |
&natural_width);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
else
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
gtk_widget_get_preferred_width (priv->widget,
|
|
Packit |
1069cd |
&min_width,
|
|
Packit |
1069cd |
&natural_width);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (min_width_p)
|
|
Packit |
1069cd |
*min_width_p = min_width;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (natural_width_p)
|
|
Packit |
1069cd |
*natural_width_p = natural_width;
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_get_preferred_height (ClutterActor *actor,
|
|
Packit |
1069cd |
gfloat for_width,
|
|
Packit |
1069cd |
gfloat *min_height_p,
|
|
Packit |
1069cd |
gfloat *natural_height_p)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActor *clutter = GTK_CLUTTER_ACTOR (actor);
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = clutter->priv;
|
|
Packit |
1069cd |
gint min_height, natural_height;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
min_height = natural_height = 0;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (for_width >= 0)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
for_width = ceilf (for_width);
|
|
Packit |
1069cd |
gtk_widget_get_preferred_height_for_width (priv->widget,
|
|
Packit |
1069cd |
for_width,
|
|
Packit |
1069cd |
&min_height,
|
|
Packit |
1069cd |
&natural_height);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
else
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
gtk_widget_get_preferred_height (priv->widget,
|
|
Packit |
1069cd |
&min_height,
|
|
Packit |
1069cd |
&natural_height);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (min_height_p)
|
|
Packit |
1069cd |
*min_height_p = min_height;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (natural_height_p)
|
|
Packit |
1069cd |
*natural_height_p = natural_height;
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_allocate (ClutterActor *actor,
|
|
Packit |
1069cd |
const ClutterActorBox *box,
|
|
Packit |
1069cd |
ClutterAllocationFlags flags)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActor *clutter = GTK_CLUTTER_ACTOR (actor);
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = clutter->priv;
|
|
Packit |
1069cd |
GtkAllocation child_allocation;
|
|
Packit |
1069cd |
GdkWindow *window;
|
|
Packit |
1069cd |
ClutterActorBox child_box;
|
|
Packit |
1069cd |
gint dummy;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
_gtk_clutter_offscreen_set_in_allocation (GTK_CLUTTER_OFFSCREEN (priv->widget), TRUE);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
child_allocation.x = 0;
|
|
Packit |
1069cd |
child_allocation.y = 0;
|
|
Packit |
1069cd |
child_allocation.width = clutter_actor_box_get_width (box);
|
|
Packit |
1069cd |
child_allocation.height = clutter_actor_box_get_height (box);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/* Silence the following GTK+ warning:
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* Gtk-WARNING **: Allocating size to Offscreen Container
|
|
Packit |
1069cd |
* without calling gtk_widget_get_preferred_width/height(). How does the
|
|
Packit |
1069cd |
* code know the size to allocate?
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
gtk_widget_get_preferred_width (priv->widget, &dummy, NULL);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
gtk_widget_size_allocate (priv->widget, &child_allocation);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (clutter_actor_is_realized (actor))
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
cairo_surface_t *surface;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/* The former size allocate may have queued an expose we then need to
|
|
Packit |
1069cd |
* process immediately, since we will paint the pixmap when this
|
|
Packit |
1069cd |
* returns (as size allocation is done from clutter_redraw which is
|
|
Packit |
1069cd |
* called from gtk_clutter_embed_expose_event(). If we don't do this
|
|
Packit |
1069cd |
* we may see an intermediate state of the pixmap, causing flicker
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
window = gtk_widget_get_window (priv->widget);
|
|
Packit |
1069cd |
gdk_window_process_updates (window, TRUE);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
surface = gdk_offscreen_window_get_surface (window);
|
|
Packit |
1069cd |
#if defined(CLUTTER_WINDOWING_X11) && defined(CAIRO_HAS_XLIB_SURFACE)
|
|
Packit |
1069cd |
if (!gtk_clutter_actor_use_image_surface () &&
|
|
Packit |
1069cd |
clutter_check_windowing_backend (CLUTTER_WINDOWING_X11) &&
|
|
Packit |
1069cd |
cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_XLIB)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
Drawable pixmap = cairo_xlib_surface_get_drawable (surface);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (pixmap != priv->pixmap)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
priv->pixmap = pixmap;
|
|
Packit |
1069cd |
clutter_x11_texture_pixmap_set_pixmap (CLUTTER_X11_TEXTURE_PIXMAP (priv->texture),
|
|
Packit |
1069cd |
priv->pixmap);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
else
|
|
Packit |
1069cd |
#endif
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
DEBUG (G_STRLOC ": Using image surface.\n");
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
clutter_canvas_set_scale_factor (CLUTTER_CANVAS (priv->canvas),
|
|
Packit |
1069cd |
gdk_window_get_scale_factor (window));
|
|
Packit |
1069cd |
clutter_canvas_set_size (CLUTTER_CANVAS (priv->canvas),
|
|
Packit |
1069cd |
gtk_widget_get_allocated_width (priv->widget),
|
|
Packit |
1069cd |
gtk_widget_get_allocated_height (priv->widget));
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
_gtk_clutter_offscreen_set_in_allocation (GTK_CLUTTER_OFFSCREEN (priv->widget), FALSE);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
clutter_actor_set_allocation (actor, box, (flags | CLUTTER_DELEGATE_LAYOUT));
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
child_box.x1 = child_box.y1 = 0.f;
|
|
Packit |
1069cd |
child_box.x2 = clutter_actor_box_get_width (box);
|
|
Packit |
1069cd |
child_box.y2 = clutter_actor_box_get_height (box);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/* we force the allocation of the offscreen texture */
|
|
Packit |
1069cd |
clutter_actor_allocate (priv->texture, &child_box, flags);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_paint (ClutterActor *actor)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = GTK_CLUTTER_ACTOR (actor)->priv;
|
|
Packit |
1069cd |
ClutterActorIter iter;
|
|
Packit |
1069cd |
ClutterActor *child;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/* we always paint the texture below everything else */
|
|
Packit |
1069cd |
clutter_actor_paint (priv->texture);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
clutter_actor_iter_init (&iter, actor);
|
|
Packit |
1069cd |
while (clutter_actor_iter_next (&iter, &child))
|
|
Packit |
1069cd |
clutter_actor_paint (child);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_show (ClutterActor *self)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = GTK_CLUTTER_ACTOR (self)->priv;
|
|
Packit |
1069cd |
GtkWidget *widget = gtk_bin_get_child (GTK_BIN (priv->widget));
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
CLUTTER_ACTOR_CLASS (gtk_clutter_actor_parent_class)->show (self);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/* proxy this call through to GTK+ */
|
|
Packit |
1069cd |
if (widget != NULL)
|
|
Packit |
1069cd |
gtk_widget_show (widget);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_hide (ClutterActor *self)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = GTK_CLUTTER_ACTOR (self)->priv;
|
|
Packit |
1069cd |
GtkWidget *widget;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
CLUTTER_ACTOR_CLASS (gtk_clutter_actor_parent_class)->hide (self);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/* proxy this call through to GTK+ */
|
|
Packit |
1069cd |
widget = gtk_bin_get_child (GTK_BIN (priv->widget));
|
|
Packit |
1069cd |
if (widget != NULL)
|
|
Packit |
1069cd |
gtk_widget_hide (widget);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_set_contents (GtkClutterActor *actor,
|
|
Packit |
1069cd |
GtkWidget *contents)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = GTK_CLUTTER_ACTOR (actor)->priv;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (contents == gtk_bin_get_child (GTK_BIN (priv->widget)))
|
|
Packit |
1069cd |
return;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
if (contents != NULL)
|
|
Packit |
1069cd |
gtk_container_add (GTK_CONTAINER (priv->widget), contents);
|
|
Packit |
1069cd |
else
|
|
Packit |
1069cd |
gtk_container_remove (GTK_CONTAINER (priv->widget),
|
|
Packit |
1069cd |
gtk_bin_get_child (GTK_BIN (priv->widget)));
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
g_object_notify (G_OBJECT (actor), "contents");
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
on_reactive_change (GtkClutterActor *actor)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = actor->priv;
|
|
Packit |
1069cd |
gboolean is_reactive;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
is_reactive = clutter_actor_get_reactive (CLUTTER_ACTOR (actor));
|
|
Packit |
1069cd |
_gtk_clutter_offscreen_set_active (GTK_CLUTTER_OFFSCREEN (priv->widget),
|
|
Packit |
1069cd |
is_reactive);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_set_property (GObject *gobject,
|
|
Packit |
1069cd |
guint prop_id,
|
|
Packit |
1069cd |
const GValue *value,
|
|
Packit |
1069cd |
GParamSpec *pspec)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActor *actor = GTK_CLUTTER_ACTOR (gobject);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
switch (prop_id)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
case PROP_CONTENTS:
|
|
Packit |
1069cd |
gtk_clutter_actor_set_contents (actor, g_value_get_object (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_actor_get_property (GObject *gobject,
|
|
Packit |
1069cd |
guint prop_id,
|
|
Packit |
1069cd |
GValue *value,
|
|
Packit |
1069cd |
GParamSpec *pspec)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = GTK_CLUTTER_ACTOR (gobject)->priv;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
switch (prop_id)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
case PROP_CONTENTS:
|
|
Packit |
1069cd |
g_value_set_object (value, gtk_bin_get_child (GTK_BIN (priv->widget)));
|
|
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_actor_class_init (GtkClutterActorClass *klass)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
Packit |
1069cd |
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
|
Packit |
1069cd |
GParamSpec *pspec;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
g_type_class_add_private (klass, sizeof (GtkClutterActorPrivate));
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
actor_class->paint = gtk_clutter_actor_paint;
|
|
Packit |
1069cd |
actor_class->realize = gtk_clutter_actor_realize;
|
|
Packit |
1069cd |
actor_class->unrealize = gtk_clutter_actor_unrealize;
|
|
Packit |
1069cd |
actor_class->show = gtk_clutter_actor_show;
|
|
Packit |
1069cd |
actor_class->hide = gtk_clutter_actor_hide;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
actor_class->get_preferred_width = gtk_clutter_actor_get_preferred_width;
|
|
Packit |
1069cd |
actor_class->get_preferred_height = gtk_clutter_actor_get_preferred_height;
|
|
Packit |
1069cd |
actor_class->allocate = gtk_clutter_actor_allocate;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
gobject_class->set_property = gtk_clutter_actor_set_property;
|
|
Packit |
1069cd |
gobject_class->get_property = gtk_clutter_actor_get_property;
|
|
Packit |
1069cd |
gobject_class->dispose = gtk_clutter_actor_dispose;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/**
|
|
Packit |
1069cd |
* GtkClutterActor:contents:
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* The #GtkWidget to be embedded into the #GtkClutterActor
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
pspec = g_param_spec_object ("contents",
|
|
Packit |
1069cd |
"Contents",
|
|
Packit |
1069cd |
"The widget to be embedded",
|
|
Packit |
1069cd |
GTK_TYPE_WIDGET,
|
|
Packit |
1069cd |
G_PARAM_READWRITE |
|
|
Packit |
1069cd |
G_PARAM_CONSTRUCT |
|
|
Packit |
1069cd |
G_PARAM_STATIC_STRINGS);
|
|
Packit |
1069cd |
g_object_class_install_property (gobject_class, PROP_CONTENTS, pspec);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
static void
|
|
Packit |
1069cd |
gtk_clutter_actor_init (GtkClutterActor *self)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv;
|
|
Packit |
1069cd |
ClutterActor *actor;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
self->priv = priv = GTK_CLUTTER_ACTOR_GET_PRIVATE (self);
|
|
Packit |
1069cd |
actor = CLUTTER_ACTOR (self);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
priv->widget = _gtk_clutter_offscreen_new (actor);
|
|
Packit |
1069cd |
gtk_widget_set_name (priv->widget, "Offscreen Container");
|
|
Packit |
1069cd |
g_object_ref_sink (priv->widget);
|
|
Packit |
1069cd |
gtk_widget_show (priv->widget);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
clutter_actor_set_reactive (actor, TRUE);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#if defined(CLUTTER_WINDOWING_X11)
|
|
Packit |
1069cd |
if (!gtk_clutter_actor_use_image_surface () &&
|
|
Packit |
1069cd |
clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
/* FIXME: write a GtkClutterWidgetContent that uses CoglTexturePixmapX11
|
|
Packit |
1069cd |
* and a cairo_surface_t internally
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
priv->texture = clutter_x11_texture_pixmap_new ();
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
|
Packit |
1069cd |
clutter_texture_set_sync_size (CLUTTER_TEXTURE (priv->texture), FALSE);
|
|
Packit |
1069cd |
G_GNUC_END_IGNORE_DEPRECATIONS
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
clutter_actor_add_child (actor, priv->texture);
|
|
Packit |
1069cd |
clutter_actor_set_name (priv->texture, "Onscreen Texture");
|
|
Packit |
1069cd |
clutter_actor_show (priv->texture);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
else
|
|
Packit |
1069cd |
#endif
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
DEBUG (G_STRLOC ": Using image surface.\n");
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
priv->canvas = clutter_canvas_new ();
|
|
Packit |
1069cd |
g_signal_connect (priv->canvas, "draw",
|
|
Packit |
1069cd |
G_CALLBACK (gtk_clutter_actor_draw_canvas),
|
|
Packit |
1069cd |
actor);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
priv->texture = clutter_actor_new ();
|
|
Packit |
1069cd |
clutter_actor_set_content (priv->texture, priv->canvas);
|
|
Packit |
1069cd |
clutter_actor_add_child (actor, priv->texture);
|
|
Packit |
1069cd |
clutter_actor_set_name (priv->texture, "Onscreen Texture");
|
|
Packit |
1069cd |
clutter_actor_show (priv->texture);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
g_object_unref (priv->canvas);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
g_signal_connect (self, "notify::reactive", G_CALLBACK (on_reactive_change), NULL);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
GtkWidget *
|
|
Packit |
1069cd |
_gtk_clutter_actor_get_embed (GtkClutterActor *actor)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
return actor->priv->embed;
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
void
|
|
Packit |
1069cd |
_gtk_clutter_actor_update (GtkClutterActor *actor,
|
|
Packit |
1069cd |
gint x,
|
|
Packit |
1069cd |
gint y,
|
|
Packit |
1069cd |
gint width,
|
|
Packit |
1069cd |
gint height)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
GtkClutterActorPrivate *priv = actor->priv;
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
#if defined(CLUTTER_WINDOWING_X11)
|
|
Packit |
1069cd |
if (!gtk_clutter_actor_use_image_surface () &&
|
|
Packit |
1069cd |
clutter_check_windowing_backend (CLUTTER_WINDOWING_X11))
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
clutter_x11_texture_pixmap_update_area (CLUTTER_X11_TEXTURE_PIXMAP (priv->texture),
|
|
Packit |
1069cd |
x, y, width, height);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
else
|
|
Packit |
1069cd |
#endif
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
clutter_content_invalidate (priv->canvas);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/**
|
|
Packit |
1069cd |
* gtk_clutter_actor_new:
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* Creates a new #GtkClutterActor.
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* This widget can be used to embed a #GtkWidget into a Clutter scene,
|
|
Packit |
1069cd |
* by retrieving the internal #GtkBin container using
|
|
Packit |
1069cd |
* gtk_clutter_actor_get_widget() and adding the #GtkWidget to it.
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* Return value: the newly created #GtkClutterActor
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
ClutterActor *
|
|
Packit |
1069cd |
gtk_clutter_actor_new (void)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
return g_object_new (GTK_CLUTTER_TYPE_ACTOR, NULL);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/**
|
|
Packit |
1069cd |
* gtk_clutter_actor_new_with_contents:
|
|
Packit |
1069cd |
* @contents: a #GtkWidget to pack into this #ClutterActor
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* Creates a new #GtkClutterActor widget. This widget can be
|
|
Packit |
1069cd |
* used to embed a Gtk widget into a clutter scene.
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* This function is the logical equivalent of:
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* |[
|
|
Packit |
1069cd |
* ClutterActor *actor = gtk_clutter_actor_new ();
|
|
Packit |
1069cd |
* GtkWidget *bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (actor));
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* gtk_container_add (GTK_CONTAINER (bin), contents);
|
|
Packit |
1069cd |
* ]|
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* Return value: the newly created #GtkClutterActor
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
ClutterActor *
|
|
Packit |
1069cd |
gtk_clutter_actor_new_with_contents (GtkWidget *contents)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
g_return_val_if_fail (GTK_IS_WIDGET (contents), NULL);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
return g_object_new (GTK_CLUTTER_TYPE_ACTOR,
|
|
Packit |
1069cd |
"contents", contents,
|
|
Packit |
1069cd |
NULL);
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/**
|
|
Packit |
1069cd |
* gtk_clutter_actor_get_widget:
|
|
Packit |
1069cd |
* @actor: a #GtkClutterActor
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* Retrieves the #GtkBin used to hold the #GtkClutterActor:contents widget
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* Return value: (transfer none): a #GtkBin
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
GtkWidget *
|
|
Packit |
1069cd |
gtk_clutter_actor_get_widget (GtkClutterActor *actor)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
g_return_val_if_fail (GTK_CLUTTER_IS_ACTOR (actor), NULL);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
return actor->priv->widget;
|
|
Packit |
1069cd |
}
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
/**
|
|
Packit |
1069cd |
* gtk_clutter_actor_get_contents:
|
|
Packit |
1069cd |
* @actor: a #GtkClutterActor
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* Retrieves the child of the #GtkBin used to hold the contents of @actor.
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* This convenience function is the logical equivalent of:
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* |[
|
|
Packit |
1069cd |
* GtkWidget *bin;
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* bin = gtk_clutter_actor_get_widget (GTK_CLUTTER_ACTOR (actor));
|
|
Packit |
1069cd |
* return gtk_bin_get_child (GTK_BIN (bin));
|
|
Packit |
1069cd |
* ]|
|
|
Packit |
1069cd |
*
|
|
Packit |
1069cd |
* Return value: (transfer none): a #GtkWidget, or %NULL if not content
|
|
Packit |
1069cd |
* has been set
|
|
Packit |
1069cd |
*/
|
|
Packit |
1069cd |
GtkWidget *
|
|
Packit |
1069cd |
gtk_clutter_actor_get_contents (GtkClutterActor *actor)
|
|
Packit |
1069cd |
{
|
|
Packit |
1069cd |
g_return_val_if_fail (GTK_CLUTTER_IS_ACTOR (actor), NULL);
|
|
Packit |
1069cd |
|
|
Packit |
1069cd |
return gtk_bin_get_child (GTK_BIN (actor->priv->widget));
|
|
Packit |
1069cd |
}
|