2007-04-25 Emmanuele Bassi <ebassi@openedhand.com>

Merge from clutter.git/master

	* clutter/glx/clutter-event-glx.c:
	* clutter/glx/clutter-stage-glx.c: Implement the _NET_WM_PING
	protocol handling on the main stage window.

	* clutter/clutter-stage.h:
	* clutter/clutter-stage.c:
	* clutter/clutter-main.c: Handle CLUTTER_DELETE events internally,
	by calling clutter_main_quit(), and remove the ::delete-event
	signal from ClutterStage; clean up the signal emission sequence
	for the events: emit the ::event signal before emitting any signal
	and the ::event-after signal after the signal has been emitted; move
	the signal emission calls inside ClutterStage so we can call
	g_signal_emit() instead of g_signal_emit_by_name(), thus sparing us
	a lookup for each event.

	* examples/test.c: Remove ::delete-event signal handling.
This commit is contained in:
Emmanuele Bassi 2007-04-25 14:22:24 +00:00
parent 296649e865
commit a7a511ce79
10 changed files with 184 additions and 80 deletions

View File

@ -1,3 +1,24 @@
2007-04-25 Emmanuele Bassi <ebassi@openedhand.com>
Merge from clutter.git/master
* clutter/glx/clutter-event-glx.c:
* clutter/glx/clutter-stage-glx.c: Implement the _NET_WM_PING
protocol handling on the main stage window.
* clutter/clutter-stage.h:
* clutter/clutter-stage.c:
* clutter/clutter-main.c: Handle CLUTTER_DELETE events internally,
by calling clutter_main_quit(), and remove the ::delete-event
signal from ClutterStage; clean up the signal emission sequence
for the events: emit the ::event signal before emitting any signal
and the ::event-after signal after the signal has been emitted; move
the signal emission calls inside ClutterStage so we can call
g_signal_emit() instead of g_signal_emit_by_name(), thus sparing us
a lookup for each event.
* examples/test.c: Remove ::delete-event signal handling.
2007-04-19 Emmanuele Bassi <ebassi@openedhand.com> 2007-04-19 Emmanuele Bassi <ebassi@openedhand.com>
Merge from clutter.git/master Merge from clutter.git/master

View File

@ -133,45 +133,25 @@ clutter_main_do_event (ClutterEvent *event,
{ {
case CLUTTER_NOTHING: case CLUTTER_NOTHING:
break; break;
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_DELETE:
if (clutter_stage_event (CLUTTER_STAGE (stage), event))
clutter_main_quit ();
break;
case CLUTTER_KEY_PRESS:
case CLUTTER_KEY_RELEASE:
case CLUTTER_MOTION:
case CLUTTER_BUTTON_PRESS: case CLUTTER_BUTTON_PRESS:
case CLUTTER_2BUTTON_PRESS: case CLUTTER_2BUTTON_PRESS:
case CLUTTER_3BUTTON_PRESS: case CLUTTER_3BUTTON_PRESS:
g_signal_emit_by_name (stage, "button-press-event", event);
break;
case CLUTTER_BUTTON_RELEASE: case CLUTTER_BUTTON_RELEASE:
g_signal_emit_by_name (stage, "button-release-event", event);
break;
case CLUTTER_SCROLL: case CLUTTER_SCROLL:
g_signal_emit_by_name (stage, "scroll-event", event); clutter_stage_event (CLUTTER_STAGE (stage), event);
break; break;
case CLUTTER_KEY_PRESS:
g_signal_emit_by_name (stage, "key-press-event", event);
break;
case CLUTTER_KEY_RELEASE:
g_signal_emit_by_name (stage, "key-release-event", event);
break;
case CLUTTER_MOTION:
g_signal_emit_by_name (stage, "motion-event", event);
break;
case CLUTTER_DELETE:
{
gboolean res = FALSE;
g_object_ref (stage);
g_signal_emit_by_name (stage, "delete-event", event, &res);
CLUTTER_NOTE (EVENT, "delete-event return: %s",
res == TRUE ? "true" : "false");
if (!res)
clutter_main_quit ();
g_object_unref (stage);
}
break;
case CLUTTER_STAGE_STATE: case CLUTTER_STAGE_STATE:
break;
case CLUTTER_DESTROY_NOTIFY:
break;
case CLUTTER_CLIENT_MESSAGE: case CLUTTER_CLIENT_MESSAGE:
break; break;
} }
@ -189,7 +169,8 @@ clutter_main_quit (void)
g_return_if_fail (context->main_loops != NULL); g_return_if_fail (context->main_loops != NULL);
g_main_loop_quit (context->main_loops->data); if (g_main_loop_is_running (context->main_loops->data))
g_main_loop_quit (context->main_loops->data);
} }
/** /**
@ -232,6 +213,7 @@ clutter_main (void)
if (g_main_loop_is_running (context->main_loops->data)) if (g_main_loop_is_running (context->main_loops->data))
{ {
/* FIXME - add thread locking around this call */
g_main_loop_run (loop); g_main_loop_run (loop);
} }
@ -257,7 +239,7 @@ clutter_main (void)
* Locks the Clutter thread lock. * Locks the Clutter thread lock.
*/ */
void void
clutter_threads_enter(void) clutter_threads_enter (void)
{ {
ClutterMainContext *context = CLUTTER_CONTEXT (); ClutterMainContext *context = CLUTTER_CONTEXT ();

View File

@ -78,6 +78,7 @@ enum
enum enum
{ {
EVENT, EVENT,
EVENT_AFTER,
BUTTON_PRESS_EVENT, BUTTON_PRESS_EVENT,
BUTTON_RELEASE_EVENT, BUTTON_RELEASE_EVENT,
SCROLL_EVENT, SCROLL_EVENT,
@ -85,12 +86,11 @@ enum
KEY_RELEASE_EVENT, KEY_RELEASE_EVENT,
MOTION_EVENT, MOTION_EVENT,
STAGE_STATE_EVENT, STAGE_STATE_EVENT,
DELETE_EVENT,
LAST_SIGNAL LAST_SIGNAL
}; };
static guint stage_signals[LAST_SIGNAL] = { 0 }; static guint stage_signals[LAST_SIGNAL] = { 0, };
static void static void
clutter_stage_paint (ClutterActor *actor) clutter_stage_paint (ClutterActor *actor)
@ -248,6 +248,23 @@ clutter_stage_class_init (ClutterStageClass *klass)
clutter_marshal_VOID__BOXED, clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1, G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
* ClutterStage::event-after:
* @stage: the actor which received the event
* @event: a #ClutterEvent
*
* The ::event-after signal is emitted after each event, except for
* the "delete-event" is received by @stage.
*/
stage_signals[EVENT_AFTER] =
g_signal_new ("event-after",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageClass, event_after),
NULL, NULL,
clutter_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/** /**
* ClutterStage::button-press-event: * ClutterStage::button-press-event:
* @stage: the actor which received the event * @stage: the actor which received the event
@ -353,16 +370,6 @@ clutter_stage_class_init (ClutterStageClass *klass)
G_TYPE_NONE, 1, G_TYPE_NONE, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
stage_signals[DELETE_EVENT] =
g_signal_new ("delete-event",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (ClutterStageClass, delete_event),
_clutter_boolean_accumulator, NULL,
clutter_marshal_BOOLEAN__BOXED,
G_TYPE_BOOLEAN, 1,
CLUTTER_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate)); g_type_class_add_private (gobject_class, sizeof (ClutterStagePrivate));
} }
@ -836,6 +843,83 @@ clutter_stage_get_actor_at_pos (ClutterStage *stage,
return found; return found;
} }
/**
* clutter_stage_event:
* @stage: a #ClutterStage
* @event: a #ClutterEvent
*
* This function is used to emit an event on the main stage.
* You should rarely need to use this function, except for
* synthetising events.
*
* Return value: the return value from the signal emission
*
* Since: 0.4
*/
gboolean
clutter_stage_event (ClutterStage *stage,
ClutterEvent *event)
{
gboolean res = TRUE;
gint signal_num = -1;
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
g_object_ref (stage);
g_signal_emit (stage, stage_signals[EVENT], 0, event);
switch (event->type)
{
case CLUTTER_NOTHING:
break;
case CLUTTER_BUTTON_PRESS:
case CLUTTER_2BUTTON_PRESS:
case CLUTTER_3BUTTON_PRESS:
signal_num = BUTTON_PRESS_EVENT;
break;
case CLUTTER_BUTTON_RELEASE:
signal_num = BUTTON_RELEASE_EVENT;
break;
case CLUTTER_SCROLL:
signal_num = SCROLL_EVENT;
break;
case CLUTTER_KEY_PRESS:
signal_num = KEY_PRESS_EVENT;
break;
case CLUTTER_KEY_RELEASE:
signal_num = KEY_RELEASE_EVENT;
break;
case CLUTTER_MOTION:
signal_num = MOTION_EVENT;
break;
case CLUTTER_DELETE:
signal_num = -1;
break;
case CLUTTER_STAGE_STATE:
signal_num = -1;
break;
case CLUTTER_DESTROY_NOTIFY:
signal_num = -1;
break;
case CLUTTER_CLIENT_MESSAGE:
signal_num = -1;
break;
}
if (signal_num != -1)
{
g_signal_emit (stage, stage_signals[signal_num], 0, event);
g_signal_emit (stage, stage_signals[EVENT_AFTER], 0, event);
res = TRUE;
}
g_object_unref (stage);
return res;
}
/*** Perspective boxed type ******/ /*** Perspective boxed type ******/
/** /**

View File

@ -94,6 +94,8 @@ struct _ClutterStageClass
/* signals */ /* signals */
void (* event) (ClutterStage *stage, void (* event) (ClutterStage *stage,
ClutterEvent *event); ClutterEvent *event);
void (* event_after) (ClutterStage *stage,
ClutterEvent *event);
void (* button_press_event) (ClutterStage *stage, void (* button_press_event) (ClutterStage *stage,
ClutterButtonEvent *event); ClutterButtonEvent *event);
void (* button_release_event) (ClutterStage *stage, void (* button_release_event) (ClutterStage *stage,
@ -108,8 +110,6 @@ struct _ClutterStageClass
ClutterMotionEvent *event); ClutterMotionEvent *event);
void (* stage_state_event) (ClutterStage *stage, void (* stage_state_event) (ClutterStage *stage,
ClutterStageStateEvent *event); ClutterStageStateEvent *event);
gboolean (* delete_event) (ClutterStage *stage,
ClutterAnyEvent *event);
/* padding for future expansion */ /* padding for future expansion */
void (*_clutter_stage1) (void); void (*_clutter_stage1) (void);
@ -158,6 +158,8 @@ GdkPixbuf * clutter_stage_snapshot (ClutterStage *stage,
gint y, gint y,
gint width, gint width,
gint height); gint height);
gboolean clutter_stage_event (ClutterStage *stage,
ClutterEvent *event);
G_END_DECLS G_END_DECLS

View File

@ -206,10 +206,8 @@ clutter_stage_egl_paint (ClutterActor *self)
glDisable (GL_LIGHTING); glDisable (GL_LIGHTING);
glDisable (GL_DEPTH_TEST); glDisable (GL_DEPTH_TEST);
/* FIXME Check is redundant */ /* Basically call up to ClutterGroup paint here */
if (G_LIKELY(CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->paint)) CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->paint (self);
/* Basically call up to ClutterGroup paint here */
CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->paint (self);
/* Why this paint is done in backend as likely GL windowing system /* Why this paint is done in backend as likely GL windowing system
* specific calls, like swapping buffers. * specific calls, like swapping buffers.
@ -370,7 +368,8 @@ static void
clutter_stage_egl_set_offscreen (ClutterStage *stage, clutter_stage_egl_set_offscreen (ClutterStage *stage,
gboolean offscreen) gboolean offscreen)
{ {
g_warning ("Stage of type `%s' do not support ClutterStage::set_offscreen",
G_OBJECT_TYPE_NAME (stage));
} }
static void static void
@ -388,7 +387,8 @@ clutter_stage_egl_draw_to_pixbuf (ClutterStage *stage,
gint width, gint width,
gint height) gint height)
{ {
/* FIXME: implement */ g_warning ("Stage of type `%s' do not support ClutterStage::draw_to_pixbuf",
G_OBJECT_TYPE_NAME (stage));
} }
static void static void
@ -474,6 +474,15 @@ clutter_egl_get_stage_visual (ClutterStage *stage)
return CLUTTER_STAGE_EGL (stage)->xvisinfo; return CLUTTER_STAGE_EGL (stage)->xvisinfo;
} }
/**
* clutter_egl_set_stage_foreign:
* @stage: a #ClutterStage
* @window: FIXME
*
* FIXME
*
* Since: 0.4
*/
void void
clutter_egl_set_stage_foreign (ClutterStage *stage, clutter_egl_set_stage_foreign (ClutterStage *stage,
Window window) Window window)

View File

@ -290,6 +290,7 @@ handle_wm_protocols_event (ClutterBackendGlx *backend_glx,
{ {
Atom atom = (Atom) xevent->xclient.data.l[0]; Atom atom = (Atom) xevent->xclient.data.l[0];
Atom Atom_WM_DELETE_WINDOW; Atom Atom_WM_DELETE_WINDOW;
Atom Atom_NEW_WM_PING;
ClutterStage *stage = CLUTTER_STAGE (backend_glx->stage); ClutterStage *stage = CLUTTER_STAGE (backend_glx->stage);
Window stage_xwindow = clutter_glx_get_stage_window (stage); Window stage_xwindow = clutter_glx_get_stage_window (stage);
@ -297,6 +298,7 @@ handle_wm_protocols_event (ClutterBackendGlx *backend_glx,
Atom_WM_DELETE_WINDOW = XInternAtom (backend_glx->xdpy, Atom_WM_DELETE_WINDOW = XInternAtom (backend_glx->xdpy,
"WM_DELETE_WINDOW", "WM_DELETE_WINDOW",
False); False);
Atom_NEW_WM_PING = XInternAtom (backend_glx->xdpy, "_NET_WM_PING", False);
if (atom == Atom_WM_DELETE_WINDOW && if (atom == Atom_WM_DELETE_WINDOW &&
xevent->xany.window == stage_xwindow) xevent->xany.window == stage_xwindow)
@ -315,8 +317,21 @@ handle_wm_protocols_event (ClutterBackendGlx *backend_glx,
return TRUE; return TRUE;
} }
else if (atom == Atom_NEW_WM_PING &&
xevent->xany.window == stage_xwindow)
{
XClientMessageEvent xclient = xevent->xclient;
/* do not send the WM_PROTOCOLS events to the queue */ xclient.window = backend_glx->xwin_root;
XSendEvent (backend_glx->xdpy, xclient.window,
False,
SubstructureRedirectMask | SubstructureNotifyMask,
(XEvent *) &xclient);
return FALSE;
}
/* do not send any of the WM_PROTOCOLS events to the queue */
return FALSE; return FALSE;
} }

View File

@ -112,11 +112,10 @@ static void
set_wm_protocols (Display *xdisplay, set_wm_protocols (Display *xdisplay,
Window xwindow) Window xwindow)
{ {
Atom protocols[3]; Atom protocols[2];
int n = 0; int n = 0;
protocols[n++] = XInternAtom (xdisplay, "WM_DELETE_WINDOW", False); protocols[n++] = XInternAtom (xdisplay, "WM_DELETE_WINDOW", False);
protocols[n++] = XInternAtom (xdisplay, "WM_TAKE_FOCUS", False);
protocols[n++] = XInternAtom (xdisplay, "_NET_WM_PING", False); protocols[n++] = XInternAtom (xdisplay, "_NET_WM_PING", False);
XSetWMProtocols (xdisplay, xwindow, protocols, n); XSetWMProtocols (xdisplay, xwindow, protocols, n);

View File

@ -331,6 +331,7 @@ clutter_stage_show_cursor
clutter_stage_hide_cursor clutter_stage_hide_cursor
clutter_stage_get_actor_at_pos clutter_stage_get_actor_at_pos
clutter_stage_snapshot clutter_stage_snapshot
clutter_stage_event
<SUBSECTION Standard> <SUBSECTION Standard>
CLUTTER_STAGE CLUTTER_STAGE
CLUTTER_IS_STAGE CLUTTER_IS_STAGE

View File

@ -80,16 +80,15 @@ Macro evaluating to the height of the #ClutterStage
@clutterstage: the object which received the signal. @clutterstage: the object which received the signal.
@arg1: @arg1:
<!-- ##### SIGNAL ClutterStage::delete-event ##### --> <!-- ##### SIGNAL ClutterStage::event ##### -->
<para> <para>
</para> </para>
@clutterstage: the object which received the signal. @clutterstage: the object which received the signal.
@Param2: @arg1:
@Returns:
<!-- ##### SIGNAL ClutterStage::event ##### --> <!-- ##### SIGNAL ClutterStage::event-after ##### -->
<para> <para>
</para> </para>
@ -160,6 +159,7 @@ Macro evaluating to the height of the #ClutterStage
@set_offscreen: @set_offscreen:
@draw_to_pixbuf: @draw_to_pixbuf:
@event: @event:
@event_after:
@button_press_event: @button_press_event:
@button_release_event: @button_release_event:
@scroll_event: @scroll_event:
@ -167,7 +167,6 @@ Macro evaluating to the height of the #ClutterStage
@key_release_event: @key_release_event:
@motion_event: @motion_event:
@stage_state_event: @stage_state_event:
@delete_event:
@_clutter_stage1: @_clutter_stage1:
@_clutter_stage2: @_clutter_stage2:
@_clutter_stage3: @_clutter_stage3:
@ -257,3 +256,13 @@ Macro evaluating to the height of the #ClutterStage
@Returns: @Returns:
<!-- ##### FUNCTION clutter_stage_event ##### -->
<para>
</para>
@stage:
@event:
@Returns:

View File

@ -79,22 +79,6 @@ key_release_cb (ClutterStage *stage,
g_print ("key-release-event\n"); g_print ("key-release-event\n");
} }
static gboolean
delete_event_cb (ClutterStage *stage,
ClutterEvent *event,
gpointer data)
{
static gboolean res = FALSE;
g_print ("delete-event: %s\n",
res == FALSE ? "first attempt" : "second attempt");
res = !res;
return res;
}
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
@ -107,8 +91,6 @@ main (int argc, char *argv[])
clutter_init (&argc, &argv); clutter_init (&argc, &argv);
stage = clutter_stage_get_default (); stage = clutter_stage_get_default ();
g_signal_connect (stage, "delete-event",
G_CALLBACK (delete_event_cb), NULL);
g_signal_connect (stage, "key-press-event", g_signal_connect (stage, "key-press-event",
G_CALLBACK (key_press_cb), NULL); G_CALLBACK (key_press_cb), NULL);
g_signal_connect (stage, "key-release-event", g_signal_connect (stage, "key-release-event",