[stage] Rework the Stage implementation class

Instead of using ClutterActor for the base class of the Stage
implementation we should extend the StageWindow interface with
the required bits (geometry, realization) and use a simple object
class.

This require a wee bit of changes across Backend, Stage and
StageWindow, even though it's mostly re-shuffling.

First of all, StageWindow should get new virtual functions:

  * geometry:
    - resize()
    - get_geometry()

  * realization
    - realize()
    - unrealize()

This covers all the bits that we use from ClutterActor currently
inside the stage implementations.

The ClutterBackend::create_stage() virtual function should create
a StageWindow, and not an Actor (it should always have been; the
fact that it returned an Actor was a leak of the black magic going
on underneath). Since we never guaranteed ABI compatibility for
the Backend class, this is not a problem.

Internally to ClutterStage we can finally drop the shenanigans of
setting/unsetting actor flags on the implementation: if the realization
succeeds, for instance, we set the REALIZED flag on the Stage and
we're done.

As an initial proof of concept, the X11 and GLX stage implementations
have been ported to the New World Order(tm) and show no regressions.
This commit is contained in:
Emmanuele Bassi 2009-08-13 12:34:07 +01:00
parent c69209a253
commit 6988744db7
11 changed files with 255 additions and 215 deletions

View File

@ -93,6 +93,7 @@ source_h = \
$(srcdir)/clutter-shader-types.h \ $(srcdir)/clutter-shader-types.h \
$(srcdir)/clutter-stage.h \ $(srcdir)/clutter-stage.h \
$(srcdir)/clutter-stage-manager.h \ $(srcdir)/clutter-stage-manager.h \
$(srcdir)/clutter-stage-window.h \
$(srcdir)/clutter-texture.h \ $(srcdir)/clutter-texture.h \
$(srcdir)/clutter-text.h \ $(srcdir)/clutter-text.h \
$(srcdir)/clutter-timeline.h \ $(srcdir)/clutter-timeline.h \
@ -206,7 +207,6 @@ source_h_priv = \
$(srcdir)/clutter-private.h \ $(srcdir)/clutter-private.h \
$(srcdir)/clutter-id-pool.h \ $(srcdir)/clutter-id-pool.h \
$(srcdir)/clutter-script-private.h \ $(srcdir)/clutter-script-private.h \
$(srcdir)/clutter-stage-window.h \
$(srcdir)/clutter-timeout-interval.h \ $(srcdir)/clutter-timeout-interval.h \
$(NULL) $(NULL)

View File

@ -258,14 +258,14 @@ _clutter_backend_post_parse (ClutterBackend *backend,
return TRUE; return TRUE;
} }
ClutterActor * ClutterStageWindow *
_clutter_backend_create_stage (ClutterBackend *backend, _clutter_backend_create_stage (ClutterBackend *backend,
ClutterStage *wrapper, ClutterStage *wrapper,
GError **error) GError **error)
{ {
ClutterBackendClass *klass; ClutterBackendClass *klass;
ClutterStageManager *stage_manager; ClutterStageManager *stage_manager;
ClutterActor *stage = NULL; ClutterStageWindow *stage_window;
g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), FALSE); g_return_val_if_fail (CLUTTER_IS_BACKEND (backend), FALSE);
g_return_val_if_fail (CLUTTER_IS_STAGE (wrapper), FALSE); g_return_val_if_fail (CLUTTER_IS_STAGE (wrapper), FALSE);
@ -274,16 +274,16 @@ _clutter_backend_create_stage (ClutterBackend *backend,
klass = CLUTTER_BACKEND_GET_CLASS (backend); klass = CLUTTER_BACKEND_GET_CLASS (backend);
if (klass->create_stage) if (klass->create_stage)
stage = klass->create_stage (backend, wrapper, error); stage_window = klass->create_stage (backend, wrapper, error);
if (!stage) if (!stage_window)
return NULL; return NULL;
g_assert (CLUTTER_IS_STAGE_WINDOW (stage)); g_assert (CLUTTER_IS_STAGE_WINDOW (stage_window));
_clutter_stage_set_window (wrapper, CLUTTER_STAGE_WINDOW (stage)); _clutter_stage_set_window (wrapper, stage_window);
_clutter_stage_manager_add_stage (stage_manager, wrapper); _clutter_stage_manager_add_stage (stage_manager, wrapper);
return stage; return stage_window;
} }
void void

View File

@ -33,9 +33,10 @@
#include <pango/pango.h> #include <pango/pango.h>
#include <clutter/clutter-actor.h> #include <clutter/clutter-actor.h>
#include <clutter/clutter-stage.h>
#include <clutter/clutter-event.h> #include <clutter/clutter-event.h>
#include <clutter/clutter-feature.h> #include <clutter/clutter-feature.h>
#include <clutter/clutter-stage.h>
#include <clutter/clutter-stage-window.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -67,7 +68,7 @@ struct _ClutterBackendClass
GError **error); GError **error);
gboolean (* post_parse) (ClutterBackend *backend, gboolean (* post_parse) (ClutterBackend *backend,
GError **error); GError **error);
ClutterActor * (* create_stage) (ClutterBackend *backend, ClutterStageWindow *(* create_stage) (ClutterBackend *backend,
ClutterStage *wrapper, ClutterStage *wrapper,
GError **error); GError **error);
void (* init_events) (ClutterBackend *backend); void (* init_events) (ClutterBackend *backend);

View File

@ -188,7 +188,7 @@ GType _clutter_backend_impl_get_type (void);
void _clutter_backend_redraw (ClutterBackend *backend, void _clutter_backend_redraw (ClutterBackend *backend,
ClutterStage *stage); ClutterStage *stage);
ClutterActor *_clutter_backend_create_stage (ClutterBackend *backend, ClutterStageWindow *_clutter_backend_create_stage (ClutterBackend *backend,
ClutterStage *wrapper, ClutterStage *wrapper,
GError **error); GError **error);
void _clutter_backend_ensure_context (ClutterBackend *backend, void _clutter_backend_ensure_context (ClutterBackend *backend,

View File

@ -26,8 +26,85 @@ clutter_stage_window_get_type (void)
&stage_window_info, 0); &stage_window_info, 0);
g_type_interface_add_prerequisite (stage_window_type, g_type_interface_add_prerequisite (stage_window_type,
CLUTTER_TYPE_ACTOR); G_TYPE_OBJECT);
} }
return stage_window_type; return stage_window_type;
} }
ClutterActor *
_clutter_stage_window_get_wrapper (ClutterStageWindow *window)
{
return CLUTTER_STAGE_WINDOW_GET_IFACE (window)->get_wrapper (window);
}
void
_clutter_stage_window_set_title (ClutterStageWindow *window,
const gchar *title)
{
CLUTTER_STAGE_WINDOW_GET_IFACE (window)->set_title (window, title);
}
void
_clutter_stage_window_set_fullscreen (ClutterStageWindow *window,
gboolean is_fullscreen)
{
CLUTTER_STAGE_WINDOW_GET_IFACE (window)->set_fullscreen (window,
is_fullscreen);
}
void
_clutter_stage_window_set_cursor_visible (ClutterStageWindow *window,
gboolean is_visible)
{
CLUTTER_STAGE_WINDOW_GET_IFACE (window)->set_cursor_visible (window,
is_visible);
}
void
_clutter_stage_window_set_user_resizable (ClutterStageWindow *window,
gboolean is_resizable)
{
CLUTTER_STAGE_WINDOW_GET_IFACE (window)->set_user_resizable (window,
is_resizable);
}
gboolean
_clutter_stage_window_realize (ClutterStageWindow *window)
{
return CLUTTER_STAGE_WINDOW_GET_IFACE (window)->realize (window);
}
void
_clutter_stage_window_unrealize (ClutterStageWindow *window)
{
CLUTTER_STAGE_WINDOW_GET_IFACE (window)->unrealize (window);
}
void
_clutter_stage_window_show (ClutterStageWindow *window,
gboolean do_raise)
{
CLUTTER_STAGE_WINDOW_GET_IFACE (window)->show (window, do_raise);
}
void
_clutter_stage_window_hide (ClutterStageWindow *window)
{
CLUTTER_STAGE_WINDOW_GET_IFACE (window)->hide (window);
}
void
_clutter_stage_window_resize (ClutterStageWindow *window,
gint width,
gint height)
{
CLUTTER_STAGE_WINDOW_GET_IFACE (window)->resize (window, width, height);
}
void
_clutter_stage_window_get_geometry (ClutterStageWindow *window,
ClutterGeometry *geometry)
{
CLUTTER_STAGE_WINDOW_GET_IFACE (window)->get_geometry (window, geometry);
}

View File

@ -28,13 +28,46 @@ struct _ClutterStageWindowIface
void (* set_user_resizable) (ClutterStageWindow *stage_window, void (* set_user_resizable) (ClutterStageWindow *stage_window,
gboolean is_resizable); gboolean is_resizable);
gboolean (* realize) (ClutterStageWindow *stage_window);
void (* unrealize) (ClutterStageWindow *stage_window);
void (* show) (ClutterStageWindow *stage_window, void (* show) (ClutterStageWindow *stage_window,
gboolean do_raise); gboolean do_raise);
void (* hide) (ClutterStageWindow *stage_window); void (* hide) (ClutterStageWindow *stage_window);
void (* resize) (ClutterStageWindow *stage_window,
gint width,
gint height);
void (* get_geometry) (ClutterStageWindow *stage_window,
ClutterGeometry *geometry);
}; };
GType clutter_stage_window_get_type (void) G_GNUC_CONST; GType clutter_stage_window_get_type (void) G_GNUC_CONST;
ClutterActor *_clutter_stage_window_get_wrapper (ClutterStageWindow *window);
void _clutter_stage_window_set_title (ClutterStageWindow *window,
const gchar *title);
void _clutter_stage_window_set_fullscreen (ClutterStageWindow *window,
gboolean is_fullscreen);
void _clutter_stage_window_set_cursor_visible (ClutterStageWindow *window,
gboolean is_visible);
void _clutter_stage_window_set_user_resizable (ClutterStageWindow *window,
gboolean is_resizable);
gboolean _clutter_stage_window_realize (ClutterStageWindow *window);
void _clutter_stage_window_unrealize (ClutterStageWindow *window);
void _clutter_stage_window_show (ClutterStageWindow *window,
gboolean do_raise);
void _clutter_stage_window_hide (ClutterStageWindow *window);
void _clutter_stage_window_resize (ClutterStageWindow *window,
gint width,
gint height);
void _clutter_stage_window_get_geometry (ClutterStageWindow *window,
ClutterGeometry *geometry);
G_END_DECLS G_END_DECLS
#endif /* __CLUTTER_STAGE_WINDOW_H__ */ #endif /* __CLUTTER_STAGE_WINDOW_H__ */

View File

@ -78,7 +78,7 @@ G_DEFINE_TYPE (ClutterStage, clutter_stage, CLUTTER_TYPE_GROUP);
struct _ClutterStagePrivate struct _ClutterStagePrivate
{ {
/* the stage implementation */ /* the stage implementation */
ClutterActor *impl; ClutterStageWindow *impl;
ClutterColor color; ClutterColor color;
ClutterPerspective perspective; ClutterPerspective perspective;
@ -134,14 +134,18 @@ clutter_stage_get_preferred_width (ClutterActor *self,
gfloat *natural_width_p) gfloat *natural_width_p)
{ {
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
ClutterGeometry geom = { 0, };
if (priv->impl == NULL) if (priv->impl == NULL)
return; return;
CLUTTER_ACTOR_GET_CLASS (priv->impl)->get_preferred_width (priv->impl, _clutter_stage_window_get_geometry (priv->impl, &geom);
for_height,
min_width_p, if (min_width_p)
natural_width_p); *min_width_p = geom.width;
if (natural_width_p)
*natural_width_p = geom.width;
} }
static void static void
@ -151,14 +155,18 @@ clutter_stage_get_preferred_height (ClutterActor *self,
gfloat *natural_height_p) gfloat *natural_height_p)
{ {
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
ClutterGeometry geom = { 0, };
if (priv->impl == NULL) if (priv->impl == NULL)
return; return;
CLUTTER_ACTOR_GET_CLASS (priv->impl)->get_preferred_height (priv->impl, _clutter_stage_window_get_geometry (priv->impl, &geom);
for_width,
min_height_p, if (min_height_p)
natural_height_p); *min_height_p = geom.height;
if (natural_height_p)
*natural_height_p = geom.height;
} }
static void static void
clutter_stage_allocate (ClutterActor *self, clutter_stage_allocate (ClutterActor *self,
@ -167,12 +175,16 @@ clutter_stage_allocate (ClutterActor *self,
{ {
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
gboolean origin_changed; gboolean origin_changed;
gint width, height;
origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED) ? TRUE : FALSE; origin_changed = (flags & CLUTTER_ABSOLUTE_ORIGIN_CHANGED) ? TRUE : FALSE;
if (priv->impl == NULL) if (priv->impl == NULL)
return; return;
width = clutter_actor_box_get_width (box);
height = clutter_actor_box_get_height (box);
/* if the stage is fixed size (for instance, it's using a frame-buffer) /* if the stage is fixed size (for instance, it's using a frame-buffer)
* then we simply ignore any allocation request and override the * then we simply ignore any allocation request and override the
* allocation chain. * allocation chain.
@ -183,41 +195,31 @@ clutter_stage_allocate (ClutterActor *self,
CLUTTER_NOTE (LAYOUT, CLUTTER_NOTE (LAYOUT,
"Following allocation to %dx%d (origin %s)", "Following allocation to %dx%d (origin %s)",
(int) (box->x2 - box->x1), width, height,
(int) (box->y2 - box->y1),
origin_changed ? "changed" : "not changed"); origin_changed ? "changed" : "not changed");
klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class); klass = CLUTTER_ACTOR_CLASS (clutter_stage_parent_class);
klass->allocate (self, box, flags); klass->allocate (self, box, flags);
klass = CLUTTER_ACTOR_GET_CLASS (priv->impl); _clutter_stage_window_resize (priv->impl, width, height);
klass->allocate (priv->impl, box, flags);
} }
else else
{ {
ClutterActorBox override = { 0, }; ClutterActorBox override = { 0, };
ClutterGeometry geom = { 0, };
ClutterActorClass *klass; ClutterActorClass *klass;
gfloat natural_width, natural_height;
/* propagate the allocation */ _clutter_stage_window_get_geometry (priv->impl, &geom);
klass = CLUTTER_ACTOR_GET_CLASS (priv->impl);
klass->allocate (self, box, flags);
/* get the preferred size from the backend */
clutter_actor_get_preferred_size (priv->impl,
NULL, NULL,
&natural_width, &natural_height);
override.x1 = 0; override.x1 = 0;
override.y1 = 0; override.y1 = 0;
override.x2 = natural_width; override.x2 = geom.width;
override.y2 = natural_height; override.y2 = geom.height;
CLUTTER_NOTE (LAYOUT, CLUTTER_NOTE (LAYOUT,
"Overrigin original allocation of %dx%d " "Overrigin original allocation of %dx%d "
"with %dx%d (origin %s)", "with %dx%d (origin %s)",
(int) (box->x2 - box->x1), width, height,
(int) (box->y2 - box->y1),
(int) (override.x2), (int) (override.x2),
(int) (override.y2), (int) (override.y2),
origin_changed ? "changed" : "not changed"); origin_changed ? "changed" : "not changed");
@ -260,8 +262,10 @@ clutter_stage_paint (ClutterActor *self)
else else
cogl_disable_fog (); cogl_disable_fog ();
#if 0
CLUTTER_NOTE (PAINT, "Proxying the paint to the stage implementation"); CLUTTER_NOTE (PAINT, "Proxying the paint to the stage implementation");
clutter_actor_paint (priv->impl); _clutter_stage_window_paint (priv->impl);
#endif
/* this will take care of painting every child */ /* this will take care of painting every child */
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->paint (self); CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->paint (self);
@ -283,6 +287,7 @@ static void
clutter_stage_realize (ClutterActor *self) clutter_stage_realize (ClutterActor *self)
{ {
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
gboolean is_realized;
/* Make sure the viewport and projection matrix are valid for the /* Make sure the viewport and projection matrix are valid for the
* first paint (which will likely occur before the ConfigureNotify * first paint (which will likely occur before the ConfigureNotify
@ -291,13 +296,16 @@ clutter_stage_realize (ClutterActor *self)
CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_SYNC_MATRICES); CLUTTER_SET_PRIVATE_FLAGS (self, CLUTTER_ACTOR_SYNC_MATRICES);
g_assert (priv->impl != NULL); g_assert (priv->impl != NULL);
clutter_actor_realize (priv->impl); is_realized = _clutter_stage_window_realize (priv->impl);
/* ensure that the stage is using the context if the /* ensure that the stage is using the context if the
* realization sequence was successful * realization sequence was successful
*/ */
if (CLUTTER_ACTOR_IS_REALIZED (priv->impl)) if (is_realized)
clutter_stage_ensure_current (CLUTTER_STAGE (self)); {
CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (CLUTTER_STAGE (self));
}
else else
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED); CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
} }
@ -309,7 +317,9 @@ clutter_stage_unrealize (ClutterActor *self)
/* and then unrealize the implementation */ /* and then unrealize the implementation */
g_assert (priv->impl != NULL); g_assert (priv->impl != NULL);
clutter_actor_unrealize (priv->impl); _clutter_stage_window_unrealize (priv->impl);
CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_REALIZED);
clutter_stage_ensure_current (CLUTTER_STAGE (self)); clutter_stage_ensure_current (CLUTTER_STAGE (self));
} }
@ -318,7 +328,6 @@ static void
clutter_stage_show (ClutterActor *self) clutter_stage_show (ClutterActor *self)
{ {
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
ClutterStageWindow *impl;
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self); CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->show (self);
@ -327,19 +336,16 @@ clutter_stage_show (ClutterActor *self)
_clutter_stage_maybe_relayout (self); _clutter_stage_maybe_relayout (self);
g_assert (priv->impl != NULL); g_assert (priv->impl != NULL);
impl = CLUTTER_STAGE_WINDOW (priv->impl); _clutter_stage_window_show (priv->impl, TRUE);
CLUTTER_STAGE_WINDOW_GET_IFACE (impl)->show (impl, TRUE);
} }
static void static void
clutter_stage_hide (ClutterActor *self) clutter_stage_hide (ClutterActor *self)
{ {
ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv; ClutterStagePrivate *priv = CLUTTER_STAGE (self)->priv;
ClutterStageWindow *impl;
g_assert (priv->impl != NULL); g_assert (priv->impl != NULL);
impl = CLUTTER_STAGE_WINDOW (priv->impl); _clutter_stage_window_hide (priv->impl);
CLUTTER_STAGE_WINDOW_GET_IFACE (impl)->hide (impl);
CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self); CLUTTER_ACTOR_CLASS (clutter_stage_parent_class)->hide (self);
} }
@ -375,7 +381,7 @@ static void
clutter_stage_real_fullscreen (ClutterStage *stage) clutter_stage_real_fullscreen (ClutterStage *stage)
{ {
ClutterStagePrivate *priv = stage->priv; ClutterStagePrivate *priv = stage->priv;
gfloat natural_width, natural_height; ClutterGeometry geom;
ClutterActorBox box; ClutterActorBox box;
/* we need to force an allocation here because the size /* we need to force an allocation here because the size
@ -385,14 +391,12 @@ clutter_stage_real_fullscreen (ClutterStage *stage)
* the fact that fullscreening the stage on the X11 backends * the fact that fullscreening the stage on the X11 backends
* is really an asynchronous operation * is really an asynchronous operation
*/ */
clutter_actor_get_preferred_size (CLUTTER_ACTOR (priv->impl), _clutter_stage_window_get_geometry (priv->impl, &geom);
NULL, NULL,
&natural_width, &natural_height);
box.x1 = 0; box.x1 = 0;
box.y1 = 0; box.y1 = 0;
box.x2 = natural_width; box.x2 = geom.width;
box.y2 = natural_height; box.y2 = geom.height;
clutter_actor_allocate (CLUTTER_ACTOR (stage), clutter_actor_allocate (CLUTTER_ACTOR (stage),
&box, &box,
@ -723,11 +727,11 @@ clutter_stage_dispose (GObject *object)
_clutter_stage_manager_remove_stage (stage_manager, stage); _clutter_stage_manager_remove_stage (stage_manager, stage);
if (priv->impl) if (priv->impl != NULL)
{ {
CLUTTER_NOTE (BACKEND, "Disposing of the stage implementation"); CLUTTER_NOTE (BACKEND, "Disposing of the stage implementation");
clutter_actor_hide (priv->impl);
clutter_actor_destroy (priv->impl); g_object_unref (priv->impl);
priv->impl = NULL; priv->impl = NULL;
} }
@ -1008,16 +1012,11 @@ clutter_stage_init (ClutterStage *self)
{ {
g_warning ("Unable to create a new stage, falling back to the " g_warning ("Unable to create a new stage, falling back to the "
"default stage."); "default stage.");
priv->impl = CLUTTER_ACTOR (_clutter_stage_get_default_window ()); priv->impl = _clutter_stage_get_default_window ();
/* at this point we must have a default stage, or we're screwed */ /* at this point we must have a default stage, or we're screwed */
g_assert (priv->impl != NULL); g_assert (priv->impl != NULL);
} }
else
g_object_ref_sink (priv->impl);
/* make sure that the implementation is considered a top level */
CLUTTER_SET_PRIVATE_FLAGS (priv->impl, CLUTTER_ACTOR_IS_TOPLEVEL);
priv->event_queue = g_queue_new (); priv->event_queue = g_queue_new ();
@ -2044,7 +2043,7 @@ _clutter_stage_set_window (ClutterStage *stage,
if (stage->priv->impl) if (stage->priv->impl)
g_object_unref (stage->priv->impl); g_object_unref (stage->priv->impl);
stage->priv->impl = CLUTTER_ACTOR (stage_window); stage->priv->impl = stage_window;
} }
ClutterStageWindow * ClutterStageWindow *

View File

@ -67,6 +67,7 @@
#include "clutter-shader-types.h" #include "clutter-shader-types.h"
#include "clutter-stage.h" #include "clutter-stage.h"
#include "clutter-stage-manager.h" #include "clutter-stage-manager.h"
#include "clutter-stage-window.h"
#include "clutter-texture.h" #include "clutter-texture.h"
#include "clutter-text.h" #include "clutter-text.h"
#include "clutter-timeline.h" #include "clutter-timeline.h"

View File

@ -585,22 +585,22 @@ clutter_backend_glx_redraw (ClutterBackend *backend,
} }
} }
static ClutterActor * static ClutterStageWindow *
clutter_backend_glx_create_stage (ClutterBackend *backend, clutter_backend_glx_create_stage (ClutterBackend *backend,
ClutterStage *wrapper, ClutterStage *wrapper,
GError **error) GError **error)
{ {
ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend); ClutterBackendX11 *backend_x11 = CLUTTER_BACKEND_X11 (backend);
ClutterStageX11 *stage_x11; ClutterStageWindow *stage_window;
ClutterActor *stage; ClutterStageX11 *stage_x11;
CLUTTER_NOTE (BACKEND, "Creating stage of type '%s'", CLUTTER_NOTE (BACKEND, "Creating stage of type '%s'",
g_type_name (CLUTTER_STAGE_TYPE)); g_type_name (CLUTTER_STAGE_TYPE));
stage = g_object_new (CLUTTER_TYPE_STAGE_GLX, NULL); stage_window = g_object_new (CLUTTER_TYPE_STAGE_GLX, NULL);
/* copy backend data into the stage */ /* copy backend data into the stage */
stage_x11 = CLUTTER_STAGE_X11 (stage); stage_x11 = CLUTTER_STAGE_X11 (stage_window);
stage_x11->xdpy = backend_x11->xdpy; stage_x11->xdpy = backend_x11->xdpy;
stage_x11->xwin_root = backend_x11->xwin_root; stage_x11->xwin_root = backend_x11->xwin_root;
stage_x11->xscreen = backend_x11->xscreen_num; stage_x11->xscreen = backend_x11->xscreen_num;
@ -609,13 +609,13 @@ clutter_backend_glx_create_stage (ClutterBackend *backend,
CLUTTER_NOTE (BACKEND, CLUTTER_NOTE (BACKEND,
"GLX stage created[%p] (dpy:%p, screen:%d, root:%u, wrap:%p)", "GLX stage created[%p] (dpy:%p, screen:%d, root:%u, wrap:%p)",
stage, stage_window,
stage_x11->xdpy, stage_x11->xdpy,
stage_x11->xscreen, stage_x11->xscreen,
(unsigned int) stage_x11->xwin_root, (unsigned int) stage_x11->xwin_root,
wrapper); wrapper);
return stage; return stage_window;
} }
static XVisualInfo * static XVisualInfo *

View File

@ -49,6 +49,8 @@
static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface); static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
static ClutterStageWindowIface *clutter_stage_glx_parent_iface = NULL;
G_DEFINE_TYPE_WITH_CODE (ClutterStageGLX, G_DEFINE_TYPE_WITH_CODE (ClutterStageGLX,
clutter_stage_glx, clutter_stage_glx,
CLUTTER_TYPE_STAGE_X11, CLUTTER_TYPE_STAGE_X11,
@ -56,10 +58,10 @@ G_DEFINE_TYPE_WITH_CODE (ClutterStageGLX,
clutter_stage_window_iface_init)); clutter_stage_window_iface_init));
static void static void
clutter_stage_glx_unrealize (ClutterActor *actor) clutter_stage_glx_unrealize (ClutterStageWindow *stage_window)
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor); ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
gboolean was_offscreen; gboolean was_offscreen;
/* Note unrealize should free up any backend stage related resources */ /* Note unrealize should free up any backend stage related resources */
@ -67,9 +69,6 @@ clutter_stage_glx_unrealize (ClutterActor *actor)
g_object_get (stage_x11->wrapper, "offscreen", &was_offscreen, NULL); g_object_get (stage_x11->wrapper, "offscreen", &was_offscreen, NULL);
if (CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->unrealize != NULL)
CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->unrealize (actor);
clutter_x11_trap_x_errors (); clutter_x11_trap_x_errors ();
if (G_UNLIKELY (was_offscreen)) if (G_UNLIKELY (was_offscreen))
@ -110,19 +109,19 @@ clutter_stage_glx_unrealize (ClutterActor *actor)
CLUTTER_MARK (); CLUTTER_MARK ();
} }
static void static gboolean
clutter_stage_glx_realize (ClutterActor *actor) clutter_stage_glx_realize (ClutterStageWindow *stage_window)
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (actor); ClutterStageGLX *stage_glx = CLUTTER_STAGE_GLX (stage_window);
ClutterBackend *backend; ClutterBackend *backend;
ClutterBackendGLX *backend_glx; ClutterBackendGLX *backend_glx;
ClutterBackendX11 *backend_x11; ClutterBackendX11 *backend_x11;
gboolean is_offscreen; gboolean is_offscreen;
CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]", CLUTTER_NOTE (ACTOR, "Realizing stage '%s' [%p]",
G_OBJECT_TYPE_NAME (actor), G_OBJECT_TYPE_NAME (stage_window),
actor); stage_window);
g_object_get (stage_x11->wrapper, "offscreen", &is_offscreen, NULL); g_object_get (stage_x11->wrapper, "offscreen", &is_offscreen, NULL);
@ -140,7 +139,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
if (stage_x11->xvisinfo == None) if (stage_x11->xvisinfo == None)
{ {
g_critical ("Unable to find suitable GL visual."); g_critical ("Unable to find suitable GL visual.");
goto fail; return FALSE;
} }
if (stage_x11->xwin == None) if (stage_x11->xwin == None)
@ -209,7 +208,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
{ {
g_critical ("Unable to realize stage: %s", error->message); g_critical ("Unable to realize stage: %s", error->message);
g_error_free (error); g_error_free (error);
goto fail; return FALSE;
} }
CLUTTER_NOTE (BACKEND, "Successfully realized stage"); CLUTTER_NOTE (BACKEND, "Successfully realized stage");
@ -230,7 +229,7 @@ clutter_stage_glx_realize (ClutterActor *actor)
if (stage_x11->xvisinfo == None) if (stage_x11->xvisinfo == None)
{ {
g_critical ("Unable to find suitable GL visual."); g_critical ("Unable to find suitable GL visual.");
goto fail; return FALSE;
} }
stage_x11->xpixmap = XCreatePixmap (stage_x11->xdpy, stage_x11->xpixmap = XCreatePixmap (stage_x11->xdpy,
@ -257,20 +256,14 @@ clutter_stage_glx_realize (ClutterActor *actor)
{ {
g_critical ("Unable to realize stage: %s", error->message); g_critical ("Unable to realize stage: %s", error->message);
g_error_free (error); g_error_free (error);
goto fail; return FALSE;
} }
CLUTTER_NOTE (BACKEND, "Successfully realized stage"); CLUTTER_NOTE (BACKEND, "Successfully realized stage");
} }
/* we need to chain up to the X11 stage implementation in order to /* chain up to the StageX11 implementation */
* set the window state in case we set it before realizing the stage return clutter_stage_glx_parent_iface->realize (stage_window);
*/
CLUTTER_ACTOR_CLASS (clutter_stage_glx_parent_class)->realize (actor);
return;
fail:
CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_REALIZED);
} }
static void static void
@ -283,12 +276,8 @@ static void
clutter_stage_glx_class_init (ClutterStageGLXClass *klass) clutter_stage_glx_class_init (ClutterStageGLXClass *klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->dispose = clutter_stage_glx_dispose; gobject_class->dispose = clutter_stage_glx_dispose;
actor_class->realize = clutter_stage_glx_realize;
actor_class->unrealize = clutter_stage_glx_unrealize;
} }
static void static void
@ -299,5 +288,10 @@ clutter_stage_glx_init (ClutterStageGLX *stage)
static void static void
clutter_stage_window_iface_init (ClutterStageWindowIface *iface) clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
{ {
clutter_stage_glx_parent_iface = g_type_interface_peek_parent (iface);
iface->realize = clutter_stage_glx_realize;
iface->unrealize = clutter_stage_glx_unrealize;
/* the rest is inherited from ClutterStageX11 */ /* the rest is inherited from ClutterStageX11 */
} }

View File

@ -50,7 +50,7 @@ static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface);
G_DEFINE_TYPE_WITH_CODE (ClutterStageX11, G_DEFINE_TYPE_WITH_CODE (ClutterStageX11,
clutter_stage_x11, clutter_stage_x11,
CLUTTER_TYPE_GROUP, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_STAGE_WINDOW,
clutter_stage_window_iface_init)); clutter_stage_window_iface_init));
@ -95,24 +95,24 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11,
resize = clutter_stage_get_user_resizable (stage_x11->wrapper); resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
if (stage_x11->xwin != None && stage_x11->is_foreign_xwin == FALSE) if (stage_x11->xwin != None && !stage_x11->is_foreign_xwin)
{ {
gint min_width, min_height;
ClutterGeometry min_size;
XSizeHints *size_hints; XSizeHints *size_hints;
gfloat min_width, min_height;
size_hints = XAllocSizeHints(); size_hints = XAllocSizeHints();
_clutter_stage_window_get_geometry (CLUTTER_STAGE_WINDOW (stage_x11),
&min_size);
if (new_width < 0) if (new_width < 0)
clutter_actor_get_preferred_width (CLUTTER_ACTOR (stage_x11), min_width = min_size.width;
-1,
&min_width, NULL);
else else
min_width = new_width; min_width = new_width;
if (new_height < 0) if (new_height < 0)
clutter_actor_get_preferred_height (CLUTTER_ACTOR (stage_x11), min_height = min_size.height;
min_width,
&min_height, NULL);
else else
min_height = new_height; min_height = new_height;
@ -122,8 +122,8 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11,
restrictions on the window size */ restrictions on the window size */
if (!stage_x11->fullscreen_on_map) if (!stage_x11->fullscreen_on_map)
{ {
size_hints->min_width = (int) min_width; size_hints->min_width = min_width;
size_hints->min_height = (int) min_height; size_hints->min_height = min_height;
size_hints->flags = PMinSize; size_hints->flags = PMinSize;
if (!resize) if (!resize)
@ -154,12 +154,10 @@ clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11)
} }
static void static void
clutter_stage_x11_get_preferred_width (ClutterActor *self, clutter_stage_x11_get_geometry (ClutterStageWindow *stage_window,
gfloat for_height, ClutterGeometry *geometry)
gfloat *min_width_p,
gfloat *natural_width_p)
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
gboolean is_fullscreen, resize; gboolean is_fullscreen, resize;
is_fullscreen = FALSE; is_fullscreen = FALSE;
@ -169,110 +167,53 @@ clutter_stage_x11_get_preferred_width (ClutterActor *self,
if (is_fullscreen || stage_x11->fullscreen_on_map) if (is_fullscreen || stage_x11->fullscreen_on_map)
{ {
int width; geometry->width = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen);
geometry->height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen);
width = DisplayWidth (stage_x11->xdpy, stage_x11->xscreen);
if (min_width_p)
*min_width_p = width;
if (natural_width_p)
*natural_width_p = width;
return; return;
} }
resize = clutter_stage_get_user_resizable (stage_x11->wrapper); resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
if (min_width_p) if (resize)
{ {
if (resize) /* FIXME need API to set this */
*min_width_p = 1; /* FIXME need API to set this */ geometry->width = 1;
else geometry->height = 1;
*min_width_p = stage_x11->xwin_width; }
else
{
geometry->width = stage_x11->xwin_width;
geometry->height = stage_x11->xwin_height;
} }
if (natural_width_p)
*natural_width_p = stage_x11->xwin_width;
} }
static void static void
clutter_stage_x11_get_preferred_height (ClutterActor *self, clutter_stage_x11_resize (ClutterStageWindow *stage_window,
gfloat for_width, gint width,
gfloat *min_height_p, gint height)
gfloat *natural_height_p)
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
gboolean is_fullscreen, resize;
is_fullscreen = FALSE; if (width == 0 || height == 0)
g_object_get (G_OBJECT (stage_x11->wrapper),
"fullscreen-set", &is_fullscreen,
NULL);
if (is_fullscreen || stage_x11->fullscreen_on_map)
{
int height;
height = DisplayHeight (stage_x11->xdpy, stage_x11->xscreen);
if (min_height_p)
*min_height_p = height;
if (natural_height_p)
*natural_height_p = height;
return;
}
resize = clutter_stage_get_user_resizable (stage_x11->wrapper);
if (min_height_p)
{
if (resize)
*min_height_p = 1; /* FIXME need API to set this */
else
*min_height_p = stage_x11->xwin_height;
}
if (natural_height_p)
*natural_height_p = stage_x11->xwin_height;
}
static void
clutter_stage_x11_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (self);
ClutterActorClass *parent_class;
gint new_width, new_height;
new_width = ABS ((int) (box->x2 - box->x1));
new_height = ABS ((int) (box->y2 - box->y1));
if (new_width == 0 || new_height == 0)
{ {
/* Should not happen, if this turns up we need to debug it and /* Should not happen, if this turns up we need to debug it and
* determine the cleanest way to fix. * determine the cleanest way to fix.
*/ */
g_warning ("X11 stage not allowed to have 0 width or height"); g_warning ("X11 stage not allowed to have 0 width or height");
new_width = 1; width = 1;
new_height = 1; height = 1;
} }
CLUTTER_NOTE (BACKEND, "New allocation received: (%d, %d)", CLUTTER_NOTE (BACKEND, "New size received: (%d, %d)", width, height);
new_width,
new_height);
if (new_width != stage_x11->xwin_width || if (width != stage_x11->xwin_width ||
new_height != stage_x11->xwin_height) height != stage_x11->xwin_height)
{ {
stage_x11->xwin_width = new_width; stage_x11->xwin_width = width;
stage_x11->xwin_height = new_height; stage_x11->xwin_height = height;
if (stage_x11->xwin != None && if (stage_x11->xwin != None && !stage_x11->is_foreign_xwin)
!stage_x11->is_foreign_xwin)
{ {
CLUTTER_NOTE (BACKEND, "%s: XResizeWindow[%x] (%d, %d)", CLUTTER_NOTE (BACKEND, "%s: XResizeWindow[%x] (%d, %d)",
G_STRLOC, G_STRLOC,
@ -289,18 +230,16 @@ clutter_stage_x11_allocate (ClutterActor *self,
stage_x11->xwin_height); stage_x11->xwin_height);
} }
clutter_stage_x11_fix_window_size (stage_x11, new_width, new_height); clutter_stage_x11_fix_window_size (stage_x11, width, height);
if (stage_x11->xpixmap != None) if (stage_x11->xpixmap != None)
{ {
/* Need to recreate to resize */ /* Need to recreate to resize */
_clutter_actor_rerealize (self, NULL, NULL); _clutter_actor_rerealize (CLUTTER_ACTOR (stage_x11->wrapper),
NULL,
NULL);
} }
} }
/* chain up to fill in actor->priv->allocation */
parent_class = CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class);
parent_class->allocate (self, box, flags);
} }
static inline void static inline void
@ -395,14 +334,16 @@ set_cursor_visible (ClutterStageX11 *stage_x11)
} }
} }
static void static gboolean
clutter_stage_x11_realize (ClutterActor *actor) clutter_stage_x11_realize (ClutterStageWindow *stage_window)
{ {
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor); ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_window);
set_wm_pid (stage_x11); set_wm_pid (stage_x11);
set_wm_title (stage_x11); set_wm_title (stage_x11);
set_cursor_visible (stage_x11); set_cursor_visible (stage_x11);
return TRUE;
} }
static void static void
@ -599,7 +540,6 @@ clutter_stage_x11_show (ClutterStageWindow *stage_window,
g_assert (STAGE_X11_IS_MAPPED (stage_x11)); g_assert (STAGE_X11_IS_MAPPED (stage_x11));
clutter_actor_map (CLUTTER_ACTOR (stage_x11));
clutter_actor_map (CLUTTER_ACTOR (stage_x11->wrapper)); clutter_actor_map (CLUTTER_ACTOR (stage_x11->wrapper));
/* we force a redraw here, so that by the time we have /* we force a redraw here, so that by the time we have
@ -623,7 +563,6 @@ clutter_stage_x11_hide (ClutterStageWindow *stage_window)
g_assert (!STAGE_X11_IS_MAPPED (stage_x11)); g_assert (!STAGE_X11_IS_MAPPED (stage_x11));
clutter_actor_unmap (CLUTTER_ACTOR (stage_x11));
clutter_actor_unmap (CLUTTER_ACTOR (stage_x11->wrapper)); clutter_actor_unmap (CLUTTER_ACTOR (stage_x11->wrapper));
XWithdrawWindow (stage_x11->xdpy, XWithdrawWindow (stage_x11->xdpy,
@ -658,16 +597,9 @@ static void
clutter_stage_x11_class_init (ClutterStageX11Class *klass) clutter_stage_x11_class_init (ClutterStageX11Class *klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->finalize = clutter_stage_x11_finalize; gobject_class->finalize = clutter_stage_x11_finalize;
gobject_class->dispose = clutter_stage_x11_dispose; gobject_class->dispose = clutter_stage_x11_dispose;
actor_class->realize = clutter_stage_x11_realize;
actor_class->get_preferred_width = clutter_stage_x11_get_preferred_width;
actor_class->get_preferred_height = clutter_stage_x11_get_preferred_height;
actor_class->allocate = clutter_stage_x11_allocate;
} }
static void static void
@ -705,6 +637,9 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface)
iface->set_user_resizable = clutter_stage_x11_set_user_resizable; iface->set_user_resizable = clutter_stage_x11_set_user_resizable;
iface->show = clutter_stage_x11_show; iface->show = clutter_stage_x11_show;
iface->hide = clutter_stage_x11_hide; iface->hide = clutter_stage_x11_hide;
iface->resize = clutter_stage_x11_resize;
iface->get_geometry = clutter_stage_x11_get_geometry;
iface->realize = clutter_stage_x11_realize;
} }
/** /**