+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>
Merge from clutter.git/master
stage = _clutter_backend_get_stage (backend);
if (!stage)
return;
-
+
switch (event->type)
{
case CLUTTER_NOTHING:
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_2BUTTON_PRESS:
case CLUTTER_3BUTTON_PRESS:
- g_signal_emit_by_name (stage, "button-press-event", event);
- break;
case CLUTTER_BUTTON_RELEASE:
- g_signal_emit_by_name (stage, "button-release-event", event);
- break;
case CLUTTER_SCROLL:
- g_signal_emit_by_name (stage, "scroll-event", event);
- 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);
- }
+ clutter_stage_event (CLUTTER_STAGE (stage), event);
break;
+
case CLUTTER_STAGE_STATE:
- break;
- case CLUTTER_DESTROY_NOTIFY:
- break;
case CLUTTER_CLIENT_MESSAGE:
break;
}
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);
}
/**
if (g_main_loop_is_running (context->main_loops->data))
{
+ /* FIXME - add thread locking around this call */
g_main_loop_run (loop);
}
* Locks the Clutter thread lock.
*/
void
-clutter_threads_enter(void)
+clutter_threads_enter (void)
{
ClutterMainContext *context = CLUTTER_CONTEXT ();
enum
{
EVENT,
+ EVENT_AFTER,
BUTTON_PRESS_EVENT,
BUTTON_RELEASE_EVENT,
SCROLL_EVENT,
KEY_RELEASE_EVENT,
MOTION_EVENT,
STAGE_STATE_EVENT,
- DELETE_EVENT,
LAST_SIGNAL
};
-static guint stage_signals[LAST_SIGNAL] = { 0 };
+static guint stage_signals[LAST_SIGNAL] = { 0, };
static void
clutter_stage_paint (ClutterActor *actor)
G_TYPE_NONE, 1,
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:
* @stage: the actor which received the event
* @event: a #ClutterButtonEvent
G_TYPE_NONE, 1,
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));
}
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 ******/
/**
/* signals */
void (* event) (ClutterStage *stage,
ClutterEvent *event);
+ void (* event_after) (ClutterStage *stage,
+ ClutterEvent *event);
void (* button_press_event) (ClutterStage *stage,
ClutterButtonEvent *event);
void (* button_release_event) (ClutterStage *stage,
ClutterMotionEvent *event);
void (* stage_state_event) (ClutterStage *stage,
ClutterStageStateEvent *event);
- gboolean (* delete_event) (ClutterStage *stage,
- ClutterAnyEvent *event);
/* padding for future expansion */
void (*_clutter_stage1) (void);
gint y,
gint width,
gint height);
+gboolean clutter_stage_event (ClutterStage *stage,
+ ClutterEvent *event);
G_END_DECLS
glDisable (GL_LIGHTING);
glDisable (GL_DEPTH_TEST);
- /* FIXME Check is redundant */
- if (G_LIKELY(CLUTTER_ACTOR_CLASS (clutter_stage_egl_parent_class)->paint))
- /* Basically call up to ClutterGroup paint here */
- 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
* specific calls, like swapping buffers.
clutter_stage_egl_set_offscreen (ClutterStage *stage,
gboolean offscreen)
{
-
+ g_warning ("Stage of type `%s' do not support ClutterStage::set_offscreen",
+ G_OBJECT_TYPE_NAME (stage));
}
static void
gint width,
gint height)
{
- /* FIXME: implement */
+ g_warning ("Stage of type `%s' do not support ClutterStage::draw_to_pixbuf",
+ G_OBJECT_TYPE_NAME (stage));
}
static void
return CLUTTER_STAGE_EGL (stage)->xvisinfo;
}
+/**
+ * clutter_egl_set_stage_foreign:
+ * @stage: a #ClutterStage
+ * @window: FIXME
+ *
+ * FIXME
+ *
+ * Since: 0.4
+ */
void
clutter_egl_set_stage_foreign (ClutterStage *stage,
Window window)
{
Atom atom = (Atom) xevent->xclient.data.l[0];
Atom Atom_WM_DELETE_WINDOW;
+ Atom Atom_NEW_WM_PING;
ClutterStage *stage = CLUTTER_STAGE (backend_glx->stage);
Window stage_xwindow = clutter_glx_get_stage_window (stage);
Atom_WM_DELETE_WINDOW = XInternAtom (backend_glx->xdpy,
"WM_DELETE_WINDOW",
False);
+ Atom_NEW_WM_PING = XInternAtom (backend_glx->xdpy, "_NET_WM_PING", False);
if (atom == Atom_WM_DELETE_WINDOW &&
xevent->xany.window == stage_xwindow)
return TRUE;
}
+ else if (atom == Atom_NEW_WM_PING &&
+ xevent->xany.window == stage_xwindow)
+ {
+ XClientMessageEvent xclient = xevent->xclient;
+
+ xclient.window = backend_glx->xwin_root;
+ XSendEvent (backend_glx->xdpy, xclient.window,
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ (XEvent *) &xclient);
+
+ return FALSE;
+ }
- /* do not send the WM_PROTOCOLS events to the queue */
+ /* do not send any of the WM_PROTOCOLS events to the queue */
return FALSE;
}
set_wm_protocols (Display *xdisplay,
Window xwindow)
{
- Atom protocols[3];
+ Atom protocols[2];
int n = 0;
protocols[n++] = XInternAtom (xdisplay, "WM_DELETE_WINDOW", False);
- protocols[n++] = XInternAtom (xdisplay, "WM_TAKE_FOCUS", False);
protocols[n++] = XInternAtom (xdisplay, "_NET_WM_PING", False);
XSetWMProtocols (xdisplay, xwindow, protocols, n);
clutter_stage_hide_cursor
clutter_stage_get_actor_at_pos
clutter_stage_snapshot
+clutter_stage_event
<SUBSECTION Standard>
CLUTTER_STAGE
CLUTTER_IS_STAGE
@clutterstage: the object which received the signal.
@arg1:
-<!-- ##### SIGNAL ClutterStage::delete-event ##### -->
+<!-- ##### SIGNAL ClutterStage::event ##### -->
<para>
</para>
@clutterstage: the object which received the signal.
-@Param2:
-@Returns:
+@arg1:
-<!-- ##### SIGNAL ClutterStage::event ##### -->
+<!-- ##### SIGNAL ClutterStage::event-after ##### -->
<para>
</para>
@set_offscreen:
@draw_to_pixbuf:
@event:
+@event_after:
@button_press_event:
@button_release_event:
@scroll_event:
@key_release_event:
@motion_event:
@stage_state_event:
-@delete_event:
@_clutter_stage1:
@_clutter_stage2:
@_clutter_stage3:
@Returns:
+<!-- ##### FUNCTION clutter_stage_event ##### -->
+<para>
+
+</para>
+
+@stage:
+@event:
+@Returns:
+
+
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
main (int argc, char *argv[])
{
clutter_init (&argc, &argv);
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_CALLBACK (key_press_cb), NULL);
g_signal_connect (stage, "key-release-event",