+2007-11-26 Emmanuele Bassi <ebassi@openedhand.com>
+
+ * clutter/clutter-actor.c:
+ (clutter_actor_real_show),
+ (clutter_actor_real_hide): Do not set the MAPPED flag on the actor
+ if it is a top-level one (like ClutterStage); the backends are
+ responsible for setting that flag, as it might be the result of an
+ asynchronous operation (e.g. on X11).
+
+ * clutter/eglnative/clutter-stage-egl.c:
+ (clutter_stage_egl_show),
+ (clutter_stage_egl_hide): Set/unset the CLUTTER_ACTOR_MAPPED flag
+ on show and hide respectively.
+
+ * clutter/osx/clutter-stage-osx.c:
+ (clutter_stage_osx_show),
+ (clutter_stage_osx_hide): Ditto as above.
+
+ * clutter/sdl/clutter-stage-sdl.c:
+ (clutter_stage_sdl_show),
+ (clutter_stage_sdl_hide): Ditto as above, plus chain up to the
+ parent class show/hide virtual functions.
+
+ * clutter/x11/clutter-event-x11.c (event_translate): Use the MapNotify
+ and UnmapNotify events to call the X11 stage map/unmap functions.
+
+ * clutter/x11/clutter-stage-x11.[ch]:
+ (clutter_stage_x11_set_fullscreen): Set the fullscreen_on_map flag
+ with the fullscreen value.
+
+ (clutter_stage_x11_map), (clutter_stage_x11_unmap): Set the MAPPED
+ flag on the stage actor and redraw; also, if the fullscreen_on_map
+ flag was set, call clutter_stage_fullscreen() as well. (#648)
+
+ * tests/Makefile.am:
+ * tests/test-fullscreen.c: Add a fullscreen test case for checking
+ whether fullscreen works on every backend/platform.
+
2007-11-23 Emmanuele Bassi <ebassi@openedhand.com>
* clutter/clutter-actor.c:
if (!CLUTTER_ACTOR_IS_REALIZED (self))
clutter_actor_realize (self);
- CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
+ /* the mapped flag on the top-level actors is set by the
+ * per-backend implementation because it might be asynchronous
+ */
+ if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL))
+ CLUTTER_ACTOR_SET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
if (CLUTTER_ACTOR_IS_VISIBLE (self))
clutter_actor_queue_redraw (self);
{
if (CLUTTER_ACTOR_IS_VISIBLE (self))
{
- CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
+ /* see comment in clutter_actor_real_show() on why we don't set
+ * the mapped flag on the top-level actors
+ */
+ if (!(CLUTTER_PRIVATE_FLAGS (self) & CLUTTER_ACTOR_IS_TOPLEVEL))
+ CLUTTER_ACTOR_UNSET_FLAGS (self, CLUTTER_ACTOR_MAPPED);
+
clutter_actor_queue_redraw (self);
}
}
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
- /* we are always shown... */
-
- return;
+ CLUTTER_ACTOR_SET_FLAGS (stage_egl, CLUTTER_ACTOR_MAPPED);
}
static void
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
- /* we are always shown... */
-
- return;
+ CLUTTER_ACTOR_UNSET_FLAGS (stage_egl, CLUTTER_ACTOR_MAPPED);
}
static void
CLUTTER_NOTE (BACKEND, "show");
+ CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_MAPPED);
+
if (CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->show)
CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->show (actor);
CLUTTER_OSX_POOL_RELEASE();
+ CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_MAPPED);
+
if (CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->hide)
CLUTTER_ACTOR_CLASS (clutter_stage_osx_parent_class)->hide (actor);
}
static void
clutter_stage_sdl_show (ClutterActor *actor)
{
- ;
+ CLUTTER_ACTOR_SET_FLAGS (actor, CLUTTER_ACTOR_MAPPED);
+
+ CLUTTER_ACTOR_CLASS (clutter_stage_sdl_parent_class)->show (actor);
}
static void
clutter_stage_sdl_hide (ClutterActor *actor)
{
/* No way to easily unmap SDL window ? */
- ;
+ CLUTTER_ACTOR_UNSET_FLAGS (actor, CLUTTER_ACTOR_MAPPED);
+
+ CLUTTER_ACTOR_CLASS (clutter_stage_sdl_parent_class)->hide (actor);
}
static void
event->key.hardware_keycode = xevent->xkey.keycode;
/* FIXME: We need to handle other modifiers rather than just shift */
- event->key.keyval
- = XKeycodeToKeysym (xevent->xkey.display,
- xevent->xkey.keycode,
- (event->key.modifier_state & CLUTTER_SHIFT_MASK)
- ? 1 : 0);
+ event->key.keyval =
+ XKeycodeToKeysym (xevent->xkey.display,
+ xevent->xkey.keycode,
+ (event->key.modifier_state & CLUTTER_SHIFT_MASK) ? 1
+ : 0);
}
static gboolean
* we relay the event to the application and we let it
* handle the request
*/
- CLUTTER_NOTE (EVENT, "delete window:\twindow: %ld",
+ CLUTTER_NOTE (EVENT, "delete window:\txid: %ld",
xevent->xclient.window);
set_user_time (backend_x11,
switch (xevent->type)
{
case ConfigureNotify:
- if (xevent->xconfigure.width
- != clutter_actor_get_width (CLUTTER_ACTOR (stage))
- ||
- xevent->xconfigure.height
- != clutter_actor_get_height (CLUTTER_ACTOR (stage)))
- clutter_actor_set_size (CLUTTER_ACTOR (stage),
- xevent->xconfigure.width,
- xevent->xconfigure.height);
+ {
+ guint stage_width, stage_height;
+
+ clutter_actor_get_size (CLUTTER_ACTOR (stage),
+ &stage_width,
+ &stage_height);
+
+ if (xevent->xconfigure.width != stage_width ||
+ xevent->xconfigure.height != stage_height)
+ {
+ clutter_actor_set_size (CLUTTER_ACTOR (stage),
+ xevent->xconfigure.width,
+ xevent->xconfigure.height);
+ }
+ }
res = FALSE;
break;
+
case PropertyNotify:
- {
- if (xevent->xproperty.atom == backend_x11->atom_NET_WM_STATE)
- {
- Atom type;
- gint format;
- gulong nitems, bytes_after;
- guchar *data = NULL;
- Atom *atoms = NULL;
- gulong i;
- gboolean fullscreen_set = FALSE;
-
- clutter_x11_trap_x_errors ();
- XGetWindowProperty (backend_x11->xdpy,
- stage_xwindow,
- backend_x11->atom_NET_WM_STATE,
- 0, G_MAXLONG,
- False, XA_ATOM,
- &type, &format, &nitems,
- &bytes_after, &data);
- clutter_x11_untrap_x_errors ();
-
- if (type != None && data != NULL)
- {
- atoms = (Atom *)data;
-
- i = 0;
- while (i < nitems)
- {
- if (atoms[i] == backend_x11->atom_NET_WM_STATE_FULLSCREEN)
- fullscreen_set = TRUE;
- i++;
- }
-
- if (fullscreen_set
- != !!(stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN))
- {
- if (fullscreen_set)
- stage_x11->state |= CLUTTER_STAGE_STATE_FULLSCREEN;
- else
- stage_x11->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN;
-
- event->type = CLUTTER_STAGE_STATE;
- event->stage_state.changed_mask
- = CLUTTER_STAGE_STATE_FULLSCREEN;
- event->stage_state.new_state = stage_x11->state;
- }
- else
- res = FALSE;
-
- XFree (data);
- }
- }
- else
- res = FALSE;
- }
+ if (xevent->xproperty.atom == backend_x11->atom_NET_WM_STATE)
+ {
+ Atom type;
+ gint format;
+ gulong n_items, bytes_after;
+ guchar *data = NULL;
+ gboolean fullscreen_set = FALSE;
+
+ clutter_x11_trap_x_errors ();
+ XGetWindowProperty (backend_x11->xdpy, stage_xwindow,
+ backend_x11->atom_NET_WM_STATE,
+ 0, G_MAXLONG,
+ False, XA_ATOM,
+ &type, &format, &n_items,
+ &bytes_after, &data);
+ clutter_x11_untrap_x_errors ();
+
+ if (type != None && data != NULL)
+ {
+ Atom *atoms = (Atom *) data;
+ gulong i;
+ gboolean is_fullscreen = FALSE;
+
+ for (i = 0; i < n_items; i++)
+ {
+ if (atoms[i] == backend_x11->atom_NET_WM_STATE_FULLSCREEN)
+ fullscreen_set = TRUE;
+ }
+
+ is_fullscreen =
+ (stage_x11->state & CLUTTER_STAGE_STATE_FULLSCREEN);
+
+ if (fullscreen_set != is_fullscreen)
+ {
+ if (fullscreen_set)
+ stage_x11->state |= CLUTTER_STAGE_STATE_FULLSCREEN;
+ else
+ stage_x11->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN;
+
+ event->type = CLUTTER_STAGE_STATE;
+ event->stage_state.changed_mask =
+ CLUTTER_STAGE_STATE_FULLSCREEN;
+ event->stage_state.new_state = stage_x11->state;
+ }
+ else
+ res = FALSE;
+
+ XFree (data);
+ }
+ else
+ res = FALSE;
+ }
+ break;
+
+ case MapNotify:
+ clutter_stage_x11_map (stage_x11);
+ res = FALSE;
break;
+
+ case UnmapNotify:
+ clutter_stage_x11_unmap (stage_x11);
+ res = FALSE;
+ break;
+
case FocusIn:
if (!(stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED))
{
else
res = FALSE;
break;
+
case FocusOut:
if (stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED)
{
else
res = FALSE;
break;
+
case Expose:
{
XEvent foo_xev;
res = FALSE;
}
break;
+
case KeyPress:
event->type = CLUTTER_KEY_PRESS;
translate_key_event (backend, event, xevent);
set_user_time (backend_x11, &xwindow, xevent->xkey.time);
break;
+
case KeyRelease:
event->type = CLUTTER_KEY_RELEASE;
translate_key_event (backend, event, xevent);
break;
+
case ButtonPress:
switch (xevent->xbutton.button)
{
set_user_time (backend_x11, &xwindow, event->button.time);
break;
+
case ButtonRelease:
/* scroll events don't have a corresponding release */
if (xevent->xbutton.button == 4 ||
event->button.modifier_state = xevent->xbutton.state;
event->button.button = xevent->xbutton.button;
break;
+
case MotionNotify:
event->motion.type = event->type = CLUTTER_MOTION;
event->motion.time = xevent->xmotion.time;
event->motion.y = xevent->xmotion.y;
event->motion.modifier_state = xevent->xmotion.state;
break;
+
case DestroyNotify:
- CLUTTER_NOTE (EVENT, "destroy notify:\twindow: %ld",
+ CLUTTER_NOTE (EVENT, "destroy notify:\txid: %ld",
xevent->xdestroywindow.window);
event->type = event->any.type = CLUTTER_DESTROY_NOTIFY;
break;
+
case ClientMessage:
CLUTTER_NOTE (EVENT, "client message");
event->type = event->any.type = CLUTTER_DELETE;
}
break;
+
default:
/* ignore every other event */
res = FALSE;
if (!resize)
{
- size_hints->max_width
- = size_hints->min_width = stage_x11->xwin_width;
- size_hints->max_height
- = size_hints->min_height = stage_x11->xwin_height;
+ size_hints->max_width = size_hints->min_width =
+ stage_x11->xwin_width;
+ size_hints->max_height = size_hints->min_height =
+ stage_x11->xwin_height;
size_hints->flags = PMinSize|PMaxSize;
}
{
ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (actor);
- /* Chain up to set mapped flags */
- CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class)->show(actor);
-
if (stage_x11->xwin)
{
/* Fire off a redraw to avoid flicker on first map.
* Appears not to work perfectly on intel drivers at least.
*/
clutter_redraw();
+
XSync (stage_x11->xdpy, FALSE);
XMapWindow (stage_x11->xdpy, stage_x11->xwin);
}
+ /* chain up */
CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class)->show (actor);
}
if (stage_x11->xwin)
XUnmapWindow (stage_x11->xdpy, stage_x11->xwin);
+ /* chain up */
CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class)->hide (actor);
}
{
if (stage_x11->xwin != None)
{
- if (!CLUTTER_ACTOR_IS_MAPPED(CLUTTER_ACTOR (stage_x11)))
+ /* if the actor is not mapped we resize the stage window to match
+ * the size of the screen; this is useful for e.g. EGLX to avoid
+ * a resize when calling clutter_stage_fullscreen() before showing
+ * the stage
+ */
+ if (!CLUTTER_ACTOR_IS_MAPPED (stage_x11))
{
gint width, height;
clutter_actor_set_size (CLUTTER_ACTOR (stage_x11),
width, height);
+
/* FIXME: This wont work if we support more states */
- XChangeProperty
- (stage_x11->xdpy,
- stage_x11->xwin,
- backend_x11->atom_NET_WM_STATE, XA_ATOM, 32,
- PropModeReplace,
- (unsigned char *)&backend_x11->atom_NET_WM_STATE_FULLSCREEN,
- 1);
+ XChangeProperty (stage_x11->xdpy,
+ stage_x11->xwin,
+ backend_x11->atom_NET_WM_STATE, XA_ATOM, 32,
+ PropModeReplace,
+ (unsigned char *) &backend_x11->atom_NET_WM_STATE_FULLSCREEN, 1);
}
else
{
else
clutter_stage_set_user_resizable (stage, TRUE);
- send_wmspec_change_state(backend_x11,
- stage_x11->xwin,
+ send_wmspec_change_state(backend_x11, stage_x11->xwin,
backend_x11->atom_NET_WM_STATE_FULLSCREEN,
TRUE);
}
+
+ stage_x11->fullscreen_on_map = TRUE;
}
}
else
{
if (stage_x11->xwin != None)
{
- if (!CLUTTER_ACTOR_IS_MAPPED(CLUTTER_ACTOR (stage_x11)))
+ if (!CLUTTER_ACTOR_IS_MAPPED (stage_x11))
{
/* FIXME: This wont work if we support more states */
XDeleteProperty (stage_x11->xdpy,
was_resizeable = FALSE;
}
+
+ stage_x11->fullscreen_on_map = FALSE;
}
}
- CLUTTER_SET_PRIVATE_FLAGS(stage, CLUTTER_ACTOR_SYNC_MATRICES);
+ CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
}
static void
if (show_cursor)
{
-#if 0 /* HAVE_XFIXES - borked on fiesty at least so disabled until further
- * investigation.
- */
+#if 0 /* HAVE_XFIXES */
XFixesShowCursor (stage_x11->xdpy, stage_x11->xwin);
#else
XUndefineCursor (stage_x11->xdpy, stage_x11->xwin);
}
else
{
-#if 0 /* HAVE_XFIXES - borked */
+#if 0 /* HAVE_XFIXES */
XFixesHideCursor (stage_x11->xdpy, stage_x11->xwin);
#else
XColor col;
stage->xvisinfo = None;
stage->is_foreign_xwin = FALSE;
+ stage->fullscreen_on_map = FALSE;
- CLUTTER_SET_PRIVATE_FLAGS(stage, CLUTTER_ACTOR_SYNC_MATRICES);
+ CLUTTER_SET_PRIVATE_FLAGS (stage, CLUTTER_ACTOR_SYNC_MATRICES);
}
/**
return TRUE;
}
+
+void
+clutter_stage_x11_map (ClutterStageX11 *stage_x11)
+{
+ CLUTTER_ACTOR_SET_FLAGS (stage_x11, CLUTTER_ACTOR_MAPPED);
+
+ if (stage_x11->fullscreen_on_map)
+ clutter_stage_fullscreen (CLUTTER_STAGE (stage_x11));
+ else
+ clutter_stage_unfullscreen (CLUTTER_STAGE (stage_x11));
+
+ clutter_actor_queue_redraw (CLUTTER_ACTOR (stage_x11));
+}
+
+void
+clutter_stage_x11_unmap (ClutterStageX11 *stage_x11)
+{
+ CLUTTER_ACTOR_UNSET_FLAGS (stage_x11, CLUTTER_ACTOR_MAPPED);
+}
+
{
ClutterStage parent_instance;
- int is_foreign_xwin :1;
+ guint is_foreign_xwin : 1;
+ guint fullscreen_on_map : 1;
Display *xdpy;
Window xwin_root;
GType clutter_stage_x11_get_type (void) G_GNUC_CONST;
/* Private to subclasses */
-void
-clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11);
+void clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11);
+void clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11);
-void
-clutter_stage_x11_set_wm_protocols (ClutterStageX11 *stage_x11);
+void clutter_stage_x11_map (ClutterStageX11 *stage_x11);
+void clutter_stage_x11_unmap (ClutterStageX11 *stage_x11);
G_END_DECLS
test-actors test-behave test-text test-entry test-project \
test-boxes test-perspective test-rotate test-depth \
test-threads test-timeline test-score test-script \
- test-model test-grab test-effects
+ test-model test-grab test-effects test-fullscreen
INCLUDES = -I$(top_srcdir)/
LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la
test_script_SOURCES = test-script.c
test_model_SOURCES = test-model.c
test_effects_SOURCES = test-effects.c
+test_fullscreen_SOURCES = test-fullscreen.c
EXTRA_DIST = redhand.png test-script.json
--- /dev/null
+#include <stdlib.h>
+#include <clutter/clutter.h>
+
+enum
+{
+ START,
+ HIDE,
+ SHOW,
+ DONE
+};
+
+static int state = START;
+
+static void
+on_fullscreen (ClutterStage *stage)
+{
+ g_debug ("fullscreen set, size: %dx%d, mapped: %s",
+ clutter_actor_get_width (CLUTTER_ACTOR (stage)),
+ clutter_actor_get_height (CLUTTER_ACTOR (stage)),
+ CLUTTER_ACTOR_IS_MAPPED (stage) ? "true" : "false");
+}
+
+static void
+on_unfullscreen (ClutterStage *stage)
+{
+ g_debug ("fullscreen unset, size: %dx%d, mapped: %s",
+ clutter_actor_get_width (CLUTTER_ACTOR (stage)),
+ clutter_actor_get_height (CLUTTER_ACTOR (stage)),
+ CLUTTER_ACTOR_IS_MAPPED (stage) ? "true" : "false");
+}
+
+static gboolean
+toggle_fullscreen (gpointer dummy)
+{
+ ClutterActor *stage = clutter_stage_get_default ();
+ gboolean is_fullscreen = FALSE;
+
+ g_object_get (G_OBJECT (stage), "fullscreen", &is_fullscreen, NULL);
+
+ switch (state)
+ {
+ case START:
+ g_debug ("start: is_fullscreen := %s", is_fullscreen ? "true" : "false");
+ clutter_actor_hide (stage);
+ state = HIDE;
+ return TRUE;
+
+ case HIDE:
+ g_debug ("hide: is_fullscreen := %s", is_fullscreen ? "true" : "false");
+ clutter_actor_show (stage);
+ state = SHOW;
+ return TRUE;
+
+ case SHOW:
+ g_debug ("show: is_fullscreen := %s", is_fullscreen ? "true" : "false");
+ clutter_stage_unfullscreen (CLUTTER_STAGE (stage));
+ state = DONE;
+ return TRUE;
+
+ case DONE:
+ g_debug ("done: is_fullscreen := %s", is_fullscreen ? "true" : "false");
+ clutter_main_quit ();
+ break;
+ }
+
+ return FALSE;
+}
+
+int
+main (int argc, char *argv[])
+{
+ ClutterActor *stage;
+
+ clutter_init (&argc, &argv);
+
+ stage = clutter_stage_get_default ();
+ g_signal_connect (stage,
+ "fullscreen", G_CALLBACK (on_fullscreen),
+ NULL);
+ g_signal_connect (stage,
+ "unfullscreen", G_CALLBACK (on_unfullscreen),
+ NULL);
+
+ clutter_stage_fullscreen (CLUTTER_STAGE (stage));
+ clutter_actor_show (stage);
+
+ g_timeout_add (1000, toggle_fullscreen, NULL);
+
+ clutter_main ();
+
+ return EXIT_SUCCESS;
+}