diff --git a/clutter/clutter-event.h b/clutter/clutter-event.h index cb0eaaa93..0506fa0fa 100644 --- a/clutter/clutter-event.h +++ b/clutter/clutter-event.h @@ -37,11 +37,11 @@ G_BEGIN_DECLS enum { /* Map to xlibs masks */ - CLUTTER_BUTTON1_MASK = (1<<8), - CLUTTER_BUTTON2_MASK = (1<<9), - CLUTTER_BUTTON3_MASK = (1<<10), - CLUTTER_BUTTON4_MASK = (1<<11), - CLUTTER_BUTTON5_MASK = (1<<12) + CLUTTER_BUTTON1_MASK = (1 << 8), + CLUTTER_BUTTON2_MASK = (1 << 9), + CLUTTER_BUTTON3_MASK = (1 << 10), + CLUTTER_BUTTON4_MASK = (1 << 11), + CLUTTER_BUTTON5_MASK = (1 << 12) }; typedef enum @@ -57,7 +57,8 @@ typedef enum CLUTTER_BUTTON_RELEASE, CLUTTER_SCROLL, CLUTTER_STAGE_STATE, - CLUTTER_DESTROY_NOTIFY + CLUTTER_DESTROY_NOTIFY, + CLUTTER_CLIENT_MESSAGE } ClutterEventType; typedef enum diff --git a/clutter/glx/clutter-event-glx.c b/clutter/glx/clutter-event-glx.c index ddbc80d87..237e8ca5b 100644 --- a/clutter/glx/clutter-event-glx.c +++ b/clutter/glx/clutter-event-glx.c @@ -41,6 +41,28 @@ #include +/* XEMBED protocol support for toolkit embedding */ +#define XEMBED_MAPPED (1 << 0) +#define MAX_SUPPORTED_XEMBED_VERSION 1 + +#define XEMBED_EMBEDDED_NOTIFY 0 +#define XEMBED_WINDOW_ACTIVATE 1 +#define XEMBED_WINDOW_DEACTIVATE 2 +#define XEMBED_REQUEST_FOCUS 3 +#define XEMBED_FOCUS_IN 4 +#define XEMBED_FOCUS_OUT 5 +#define XEMBED_FOCUS_NEXT 6 +#define XEMBED_FOCUS_PREV 7 +/* 8-9 were used for XEMBED_GRAB_KEY/XEMBED_UNGRAB_KEY */ +#define XEMBED_MODALITY_ON 10 +#define XEMBED_MODALITY_OFF 11 +#define XEMBED_REGISTER_ACCELERATOR 12 +#define XEMBED_UNREGISTER_ACCELERATOR 13 +#define XEMBED_ACTIVATE_ACCELERATOR 14 + +static Atom Atom_XEMBED = 0; +static Window ParentEmbedderWin = None; + typedef struct _ClutterEventSource ClutterEventSource; struct _ClutterEventSource @@ -84,6 +106,59 @@ clutter_check_xpending (ClutterBackend *backend) return XPending (CLUTTER_BACKEND_GLX (backend)->xdpy); } +static gboolean +xembed_send_message (Display *xdisplay, + Window window, + long message, + long detail, + long data1, + long data2) +{ + XEvent ev; + + memset (&ev, 0, sizeof (ev)); + + ev.xclient.type = ClientMessage; + ev.xclient.window = window; + ev.xclient.message_type = Atom_XEMBED; + ev.xclient.format = 32; + ev.xclient.data.l[0] = CurrentTime; + ev.xclient.data.l[1] = message; + ev.xclient.data.l[2] = detail; + ev.xclient.data.l[3] = data1; + ev.xclient.data.l[4] = data2; + + clutter_glx_trap_x_errors (); + + XSendEvent (xdisplay, window, False, NoEventMask, &ev); + XSync (xdisplay, False); + + if (clutter_glx_untrap_x_errors ()) + return False; + + return True; +} + +static void +xembed_set_info (Display *xdisplay, + Window window, + gint flags) +{ + gint32 list[2]; + Atom atom_XEMBED_INFO; + + atom_XEMBED_INFO = XInternAtom (xdisplay, "_XEMBED_INFO", False); + + list[0] = MAX_SUPPORTED_XEMBED_VERSION; + list[1] = XEMBED_MAPPED; + + clutter_glx_trap_x_errors (); + XChangeProperty (xdisplay, window, + atom_XEMBED_INFO, + atom_XEMBED_INFO, 32, + PropModeReplace, (unsigned char *) list, 2); + clutter_glx_untrap_x_errors (); +} void _clutter_events_init (ClutterBackend *backend) @@ -96,6 +171,8 @@ _clutter_events_init (ClutterBackend *backend) connection_number = ConnectionNumber (backend_glx->xdpy); CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number); + Atom_XEMBED = XInternAtom (backend_glx->xdpy, "_XEMBED", False); + source = backend_glx->event_source = clutter_event_source_new (backend); event_source = (ClutterEventSource *) source; g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS); @@ -108,6 +185,10 @@ _clutter_events_init (ClutterBackend *backend) g_source_add_poll (source, &event_source->event_poll_fd); g_source_set_can_recurse (source, TRUE); g_source_attach (source, NULL); + + xembed_set_info (backend_glx->xdpy, + clutter_glx_get_stage_window (CLUTTER_STAGE (backend_glx->stage)), + 0); } void @@ -128,6 +209,7 @@ _clutter_events_uninit (ClutterBackend *backend) } } + static void set_user_time (Display *display, Window *xwindow, @@ -200,6 +282,48 @@ translate_key_event (ClutterBackend *backend, 0); /* FIXME: index with modifiers */ } +static void +handle_xembed_event (ClutterBackendGlx *backend_glx, + XEvent *xevent) +{ + ClutterActor *stage; + + stage = _clutter_backend_get_stage (CLUTTER_BACKEND (backend_glx)); + + switch (xevent->xclient.data.l[1]) + { + case XEMBED_EMBEDDED_NOTIFY: + CLUTTER_NOTE (EVENT, "got XEMBED_EMBEDDED_NOTIFY from %lx", + xevent->xclient.data.l[3]); + + ParentEmbedderWin = xevent->xclient.data.l[3]; + + clutter_actor_realize (stage); + clutter_actor_show (stage); + + xembed_set_info (backend_glx->xdpy, + clutter_glx_get_stage_window (CLUTTER_STAGE (stage)), + XEMBED_MAPPED); + break; + case XEMBED_WINDOW_ACTIVATE: + CLUTTER_NOTE (EVENT, "got XEMBED_WINDOW_ACTIVATE"); + break; + case XEMBED_WINDOW_DEACTIVATE: + CLUTTER_NOTE (EVENT, "got XEMBED_WINDOW_DEACTIVATE"); + break; + case XEMBED_FOCUS_IN: + CLUTTER_NOTE (EVENT, "got XEMBED_FOCUS_IN"); + if (ParentEmbedderWin) + xembed_send_message (backend_glx->xdpy, ParentEmbedderWin, + XEMBED_FOCUS_NEXT, + 0, 0, 0); + break; + default: + CLUTTER_NOTE (EVENT, "got unknown XEMBED message"); + break; + } +} + static gboolean clutter_event_translate (ClutterBackend *backend, ClutterEvent *event, @@ -316,6 +440,12 @@ clutter_event_translate (ClutterBackend *backend, xevent->xdestroywindow.window); event->type = event->any.type = CLUTTER_DESTROY_NOTIFY; break; + case ClientMessage: + CLUTTER_NOTE (EVENT, "client message"); + if (xevent->xclient.message_type == Atom_XEMBED) + handle_xembed_event (backend_glx, xevent); + event->type = event->any.type = CLUTTER_CLIENT_MESSAGE; + break; default: /* ignore every other event */ res = FALSE; diff --git a/doc/reference/tmpl/clutter-event.sgml b/doc/reference/tmpl/clutter-event.sgml index 1efac5329..3aa661797 100644 --- a/doc/reference/tmpl/clutter-event.sgml +++ b/doc/reference/tmpl/clutter-event.sgml @@ -85,6 +85,7 @@ Windowing events handled by Clutter. @CLUTTER_SCROLL: @CLUTTER_STAGE_STATE: @CLUTTER_DESTROY_NOTIFY: +@CLUTTER_CLIENT_MESSAGE: