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.
This commit is contained in:
Emmanuele Bassi 2007-11-26 12:07:25 +00:00
parent 99daccf1f3
commit a02e20a14a
10 changed files with 301 additions and 104 deletions

View File

@ -1,3 +1,41 @@
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:

View File

@ -233,7 +233,11 @@ clutter_actor_real_show (ClutterActor *self)
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);
@ -286,7 +290,12 @@ clutter_actor_real_hide (ClutterActor *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);
}
}

View File

@ -22,9 +22,7 @@ clutter_stage_egl_show (ClutterActor *actor)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
/* we are always shown... */
return;
CLUTTER_ACTOR_SET_FLAGS (stage_egl, CLUTTER_ACTOR_MAPPED);
}
static void
@ -32,9 +30,7 @@ clutter_stage_egl_hide (ClutterActor *actor)
{
ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (actor);
/* we are always shown... */
return;
CLUTTER_ACTOR_UNSET_FLAGS (stage_egl, CLUTTER_ACTOR_MAPPED);
}
static void

View File

@ -322,6 +322,8 @@ clutter_stage_osx_show (ClutterActor *actor)
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);
@ -347,6 +349,8 @@ clutter_stage_osx_hide (ClutterActor *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);
}

View File

@ -22,14 +22,18 @@ G_DEFINE_TYPE (ClutterStageSDL, clutter_stage_sdl, CLUTTER_TYPE_STAGE);
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

View File

@ -233,11 +233,11 @@ translate_key_event (ClutterBackend *backend,
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
@ -256,7 +256,7 @@ handle_wm_protocols_event (ClutterBackendX11 *backend_x11,
* 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,
@ -380,73 +380,89 @@ event_translate (ClutterBackend *backend,
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;
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, &nitems,
&bytes_after, &data);
clutter_x11_untrap_x_errors ();
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)
{
atoms = (Atom *)data;
if (type != None && data != NULL)
{
Atom *atoms = (Atom *) data;
gulong i;
gboolean is_fullscreen = FALSE;
i = 0;
while (i < nitems)
{
if (atoms[i] == backend_x11->atom_NET_WM_STATE_FULLSCREEN)
fullscreen_set = TRUE;
i++;
}
for (i = 0; i < n_items; i++)
{
if (atoms[i] == backend_x11->atom_NET_WM_STATE_FULLSCREEN)
fullscreen_set = TRUE;
}
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;
is_fullscreen =
(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;
if (fullscreen_set != is_fullscreen)
{
if (fullscreen_set)
stage_x11->state |= CLUTTER_STAGE_STATE_FULLSCREEN;
else
stage_x11->state &= ~CLUTTER_STAGE_STATE_FULLSCREEN;
XFree (data);
}
}
else
res = FALSE;
}
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))
{
@ -460,6 +476,7 @@ event_translate (ClutterBackend *backend,
else
res = FALSE;
break;
case FocusOut:
if (stage_x11->state & CLUTTER_STAGE_STATE_ACTIVATED)
{
@ -472,6 +489,7 @@ event_translate (ClutterBackend *backend,
else
res = FALSE;
break;
case Expose:
{
XEvent foo_xev;
@ -489,15 +507,18 @@ event_translate (ClutterBackend *backend,
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)
{
@ -535,6 +556,7 @@ event_translate (ClutterBackend *backend,
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 ||
@ -553,6 +575,7 @@ event_translate (ClutterBackend *backend,
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;
@ -560,11 +583,13 @@ event_translate (ClutterBackend *backend,
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");
@ -578,6 +603,7 @@ event_translate (ClutterBackend *backend,
event->type = event->any.type = CLUTTER_DELETE;
}
break;
default:
/* ignore every other event */
res = FALSE;

View File

@ -94,10 +94,10 @@ clutter_stage_x11_fix_window_size (ClutterStageX11 *stage_x11)
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;
}
@ -112,19 +112,18 @@ clutter_stage_x11_show (ClutterActor *actor)
{
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);
}
@ -136,6 +135,7 @@ clutter_stage_x11_hide (ClutterActor *actor)
if (stage_x11->xwin)
XUnmapWindow (stage_x11->xdpy, stage_x11->xwin);
/* chain up */
CLUTTER_ACTOR_CLASS (clutter_stage_x11_parent_class)->hide (actor);
}
@ -219,7 +219,12 @@ clutter_stage_x11_set_fullscreen (ClutterStage *stage,
{
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;
@ -228,14 +233,13 @@ clutter_stage_x11_set_fullscreen (ClutterStage *stage,
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
{
@ -247,18 +251,19 @@ clutter_stage_x11_set_fullscreen (ClutterStage *stage,
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,
@ -280,10 +285,12 @@ clutter_stage_x11_set_fullscreen (ClutterStage *stage,
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
@ -301,9 +308,7 @@ clutter_stage_x11_set_cursor_visible (ClutterStage *stage,
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);
@ -311,7 +316,7 @@ clutter_stage_x11_set_cursor_visible (ClutterStage *stage,
}
else
{
#if 0 /* HAVE_XFIXES - borked */
#if 0 /* HAVE_XFIXES */
XFixesHideCursor (stage_x11->xdpy, stage_x11->xwin);
#else
XColor col;
@ -420,8 +425,9 @@ clutter_stage_x11_init (ClutterStageX11 *stage)
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);
}
/**
@ -522,3 +528,23 @@ clutter_x11_set_stage_foreign (ClutterStage *stage,
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);
}

View File

@ -45,7 +45,8 @@ struct _ClutterStageX11
{
ClutterStage parent_instance;
int is_foreign_xwin :1;
guint is_foreign_xwin : 1;
guint fullscreen_on_map : 1;
Display *xdpy;
Window xwin_root;
@ -68,11 +69,11 @@ struct _ClutterStageX11Class
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

View File

@ -2,7 +2,7 @@ noinst_PROGRAMS = test-textures test-events test-offscreen test-scale \
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
@ -29,5 +29,6 @@ test_score_SOURCES = test-score.c
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

92
tests/test-fullscreen.c Normal file
View File

@ -0,0 +1,92 @@
#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;
}