Merge from stable: add XEMBED support

Add the XEMBED protocol support in the GLX backend, for embedding the
stage window into another X window. This allows cross-toolkit inclusion
and makes clutter-gtk possible.
This commit is contained in:
Emmanuele Bassi 2007-04-16 16:50:40 +00:00
parent 85d979fe78
commit 246a84d528
3 changed files with 138 additions and 6 deletions

View File

@ -37,11 +37,11 @@ G_BEGIN_DECLS
enum enum
{ {
/* Map to xlibs masks */ /* Map to xlibs masks */
CLUTTER_BUTTON1_MASK = (1<<8), CLUTTER_BUTTON1_MASK = (1 << 8),
CLUTTER_BUTTON2_MASK = (1<<9), CLUTTER_BUTTON2_MASK = (1 << 9),
CLUTTER_BUTTON3_MASK = (1<<10), CLUTTER_BUTTON3_MASK = (1 << 10),
CLUTTER_BUTTON4_MASK = (1<<11), CLUTTER_BUTTON4_MASK = (1 << 11),
CLUTTER_BUTTON5_MASK = (1<<12) CLUTTER_BUTTON5_MASK = (1 << 12)
}; };
typedef enum typedef enum
@ -57,7 +57,8 @@ typedef enum
CLUTTER_BUTTON_RELEASE, CLUTTER_BUTTON_RELEASE,
CLUTTER_SCROLL, CLUTTER_SCROLL,
CLUTTER_STAGE_STATE, CLUTTER_STAGE_STATE,
CLUTTER_DESTROY_NOTIFY CLUTTER_DESTROY_NOTIFY,
CLUTTER_CLIENT_MESSAGE
} ClutterEventType; } ClutterEventType;
typedef enum typedef enum

View File

@ -41,6 +41,28 @@
#include <X11/Xatom.h> #include <X11/Xatom.h>
/* 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; typedef struct _ClutterEventSource ClutterEventSource;
struct _ClutterEventSource struct _ClutterEventSource
@ -84,6 +106,59 @@ clutter_check_xpending (ClutterBackend *backend)
return XPending (CLUTTER_BACKEND_GLX (backend)->xdpy); 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 void
_clutter_events_init (ClutterBackend *backend) _clutter_events_init (ClutterBackend *backend)
@ -96,6 +171,8 @@ _clutter_events_init (ClutterBackend *backend)
connection_number = ConnectionNumber (backend_glx->xdpy); connection_number = ConnectionNumber (backend_glx->xdpy);
CLUTTER_NOTE (EVENT, "Connection number: %d", connection_number); 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); source = backend_glx->event_source = clutter_event_source_new (backend);
event_source = (ClutterEventSource *) source; event_source = (ClutterEventSource *) source;
g_source_set_priority (source, CLUTTER_PRIORITY_EVENTS); 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_add_poll (source, &event_source->event_poll_fd);
g_source_set_can_recurse (source, TRUE); g_source_set_can_recurse (source, TRUE);
g_source_attach (source, NULL); g_source_attach (source, NULL);
xembed_set_info (backend_glx->xdpy,
clutter_glx_get_stage_window (CLUTTER_STAGE (backend_glx->stage)),
0);
} }
void void
@ -128,6 +209,7 @@ _clutter_events_uninit (ClutterBackend *backend)
} }
} }
static void static void
set_user_time (Display *display, set_user_time (Display *display,
Window *xwindow, Window *xwindow,
@ -200,6 +282,48 @@ translate_key_event (ClutterBackend *backend,
0); /* FIXME: index with modifiers */ 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 static gboolean
clutter_event_translate (ClutterBackend *backend, clutter_event_translate (ClutterBackend *backend,
ClutterEvent *event, ClutterEvent *event,
@ -316,6 +440,12 @@ clutter_event_translate (ClutterBackend *backend,
xevent->xdestroywindow.window); xevent->xdestroywindow.window);
event->type = event->any.type = CLUTTER_DESTROY_NOTIFY; event->type = event->any.type = CLUTTER_DESTROY_NOTIFY;
break; 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: default:
/* ignore every other event */ /* ignore every other event */
res = FALSE; res = FALSE;

View File

@ -85,6 +85,7 @@ Windowing events handled by Clutter.
@CLUTTER_SCROLL: @CLUTTER_SCROLL:
@CLUTTER_STAGE_STATE: @CLUTTER_STAGE_STATE:
@CLUTTER_DESTROY_NOTIFY: @CLUTTER_DESTROY_NOTIFY:
@CLUTTER_CLIENT_MESSAGE:
<!-- ##### UNION ClutterEvent ##### --> <!-- ##### UNION ClutterEvent ##### -->
<para> <para>