[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-devel
Subject: Re: QXEmbed and its many variants
From: Leon Bottou <leon () bottou ! org>
Date: 2003-02-22 1:12:08
[Download RAW message or body]
Slightly updated versions of my patches to qxembed.
- L.
["qxembed.diff" (text/x-diff)]
--- kdelibs/kdeui/qxembed.h 2002-08-16 21:58:50.000000000 -0400
+++ qxembed.h 2003-02-21 08:48:13.000000000 -0500
@@ -78,8 +78,41 @@
*/
~QXEmbed();
+ /**
+ * Embedded applications should call this function to make sure
+ * they support the XEMBED protocol. It is called automatically
+ * when you use @ref #embedClientIntoWindow() or
+ * @ref #processClientCmdline(). Clients might have to call it
+ * manually when you use @ref #embed().
+ */
static void initialize();
+ enum Protocol { XEMBED, XPLAIN };
+
+ /**
+ * Sets the protocol used for embedding windows.
+ * This function must be called before embedding a window.
+ * Protocol XEMBED provides maximal functionality (focus, tabs, etc)
+ * but requires explicit cooperation from the embedded window.
+ * Protocol XPLAIN provides maximal compatibility with
+ * embedded applications that do not support the XEMBED protocol.
+ * The default is XEMBED.
+ *
+ * Future work:
+ * Create a protocol AUTO that selects the best option.
+ * This will be possible with the XEMBED v2 specification.
+ */
+
+ void setProtocol( Protocol proto );
+
+ /**
+ * Returns the protocol used for embedding the current window.
+ *
+ * @return the protocol used by QXEmbed.
+ */
+
+ Protocol protocol();
+
/**
* Embeds the window with the identifier w into this xembed widget.
*
@@ -88,8 +121,9 @@
* about its target embedder. In that case, it is not necessary to call
* embed(). Instead, the client will call the static function
* @ref #embedClientIntoWindow().
- *
+ *
* @param w the identifier of the window to embed
+ * @param proto is the embedding protocol to use
* @see #embeddedWinId()
*/
void embed( WId w );
@@ -181,6 +215,7 @@
private:
WId window;
QXEmbedData* d;
+ void checkGrab();
void sendSyntheticConfigureNotifyEvent();
};
--- kdelibs/kdeui/qxembed.cpp 2002-11-21 16:59:25.000000000 -0500
+++ qxembed.cpp 2003-02-21 19:43:05.000000000 -0500
@@ -97,15 +97,18 @@
public:
QXEmbedData(){
autoDelete = TRUE;
+ xplain = FALSE;
+ xgrab = FALSE;
lastPos = QPoint(0,0);
}
~QXEmbedData(){};
bool autoDelete;
+ bool xplain;
+ bool xgrab;
QWidget* focusProxy;
QPoint lastPos;
-
};
class QXEmbedAppFilter : public QObject
@@ -139,6 +142,7 @@
static void send_xembed_message( WId window, long message, long detail = 0,
long data1 = 0, long data2 = 0)
{
+ if (!window) return;
XEvent ev;
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
@@ -153,7 +157,9 @@
XSendEvent(qt_xdisplay(), window, FALSE, NoEventMask, &ev);
}
-static void sendClientMessage(Window window, Atom a, long x){
+static void sendClientMessage(Window window, Atom a, long x)
+{
+ if (!window) return;
XEvent ev;
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
@@ -165,6 +171,18 @@
XSendEvent(qt_xdisplay(), window, FALSE, NoEventMask, &ev);
}
+static void sendFocusMessage(Window window, int type, int mode, int detail)
+{
+ if (!window) return;
+ XEvent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.xfocus.type = type;
+ ev.xfocus.window = window;
+ ev.xfocus.mode = mode;
+ ev.xfocus.detail = detail;
+ XSendEvent(qt_xdisplay(), window, FALSE, FocusChangeMask, &ev);
+}
+
bool QXEmbedAppFilter::eventFilter( QObject *o, QEvent * e)
{
@@ -456,6 +474,10 @@
topLevelWidget()->installEventFilter( this );
qApp->installEventFilter( this );
+ if (isActiveWindow())
+ if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
+ XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), RevertToParent, \
qt_x_time ); +
setAcceptDrops( TRUE );
}
@@ -464,11 +486,13 @@
*/
QXEmbed::~QXEmbed()
{
-
- if ( window != 0 ) {
+ if ( d && d->xgrab)
+ XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() );
+
+ if ( window != 0 ) {
if ( autoDelete() )
XUnmapWindow( qt_xdisplay(), window );
-
+
XReparentWindow(qt_xdisplay(), window, qt_xrootwin(), 0, 0);
XSync(qt_xdisplay(), FALSE);
@@ -484,9 +508,43 @@
}
XFlush( qt_xdisplay() );
}
- window = 0;
+ window = 0;
- delete d;
+ delete d;
+}
+
+
+/*!
+ Sets the protocol used for embedding windows.
+ This function must be called before embedding a window.
+ Protocol XEMBED provides maximal functionality (focus, tabs, etc)
+ but requires explicit cooperation from the embedded window.
+ Protocol XPLAIN provides maximal compatibility with
+ embedded applications that do not support the XEMBED protocol.
+ The default is XEMBED.
+
+ Future work:
+ Create a protocol AUTO that selects the best option.
+ This will be possible with the XEMBED v2 specification.
+*/
+void QXEmbed::setProtocol( Protocol proto )
+{
+ if (window == 0) {
+ d->xplain = FALSE;
+ if (proto == XPLAIN)
+ d->xplain = TRUE;
+ }
+}
+
+/*!
+ Returns the protocol used for embedding the current window.
+*/
+
+QXEmbed::Protocol QXEmbed::protocol()
+{
+ if (d->xplain)
+ return XPLAIN;
+ return XEMBED;
}
@@ -504,7 +562,6 @@
{
if (window != 0)
XMapRaised(qt_xdisplay(), window);
-
}
@@ -518,12 +575,19 @@
if ( o == topLevelWidget() ) {
if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), \
RevertToParent, qt_x_time );
- send_xembed_message( window, XEMBED_WINDOW_ACTIVATE );
+ if (d->xplain)
+ checkGrab();
+ else
+ send_xembed_message( window, XEMBED_WINDOW_ACTIVATE );
}
break;
case QEvent::WindowDeactivate:
- if ( o == topLevelWidget() )
- send_xembed_message( window, XEMBED_WINDOW_DEACTIVATE );
+ if ( o == topLevelWidget() ) {
+ if (d->xplain)
+ checkGrab();
+ else
+ send_xembed_message( window, XEMBED_WINDOW_DEACTIVATE );
+ }
break;
case QEvent::Move:
{
@@ -553,7 +617,7 @@
if (!window)
return;
last_key_event.window = window;
- XSendEvent(qt_xdisplay(), window, FALSE, NoEventMask, (XEvent*)&last_key_event);
+ XSendEvent(qt_xdisplay(), window, FALSE, KeyPressMask, \
(XEvent*)&last_key_event);
}
@@ -564,7 +628,7 @@
if (!window)
return;
last_key_event.window = window;
- XSendEvent(qt_xdisplay(), window, FALSE, NoEventMask, (XEvent*)&last_key_event);
+ XSendEvent(qt_xdisplay(), window, FALSE, KeyReleaseMask, \
(XEvent*)&last_key_event); }
/*!\reimp
@@ -572,10 +636,15 @@
void QXEmbed::focusInEvent( QFocusEvent * e ){
if (!window)
return;
- int detail = XEMBED_FOCUS_CURRENT;
- if ( e->reason() == QFocusEvent::Tab )
- detail = tabForward?XEMBED_FOCUS_FIRST:XEMBED_FOCUS_LAST;
- send_xembed_message( window, XEMBED_FOCUS_IN, detail);
+ if (d->xplain) {
+ checkGrab();
+ sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
+ } else {
+ int detail = XEMBED_FOCUS_CURRENT;
+ if ( e->reason() == QFocusEvent::Tab )
+ detail = tabForward?XEMBED_FOCUS_FIRST:XEMBED_FOCUS_LAST;
+ send_xembed_message( window, XEMBED_FOCUS_IN, detail);
+ }
}
/*!\reimp
@@ -583,7 +652,12 @@
void QXEmbed::focusOutEvent( QFocusEvent * ){
if (!window)
return;
- send_xembed_message( window, XEMBED_FOCUS_OUT );
+ if (d->xplain) {
+ checkGrab();
+ sendFocusMessage(window, XFocusOut, NotifyNormal, NotifyPointer );
+ } else {
+ send_xembed_message( window, XEMBED_FOCUS_OUT );
+ }
}
@@ -675,10 +749,16 @@
QApplication::postEvent( parent(), layoutHint );
}
windowChanged( window );
- send_xembed_message( window, XEMBED_EMBEDDED_NOTIFY, 0, (long) winId() );
- send_xembed_message( window, isActiveWindow() ? XEMBED_WINDOW_ACTIVATE : \
XEMBED_WINDOW_DEACTIVATE );
- if ( hasFocus() )
- send_xembed_message( window, XEMBED_FOCUS_IN );
+ if (d->xplain) {
+ checkGrab();
+ if ( hasFocus() )
+ sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
+ } else {
+ send_xembed_message( window, XEMBED_EMBEDDED_NOTIFY, 0, (long) winId() );
+ send_xembed_message( window, isActiveWindow() ? XEMBED_WINDOW_ACTIVATE : \
XEMBED_WINDOW_DEACTIVATE ); + if ( hasFocus() )
+ send_xembed_message( window, XEMBED_FOCUS_IN );
+ }
}
@@ -730,6 +810,19 @@
embed( window );
}
break;
+ case ButtonPress:
+ if (d->xplain) {
+ QFocusEvent::setReason( QFocusEvent::Mouse );
+ setFocus();
+ QFocusEvent::resetReason();
+ XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime);
+ return TRUE;
+ }
+ break;
+ case ButtonRelease:
+ if (d->xplain)
+ XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime);
+ break;
case MapRequest:
if ( window && e->xmaprequest.window == window )
XMapRaised(qt_xdisplay(), window );
@@ -918,7 +1011,25 @@
return TRUE;
}
-void QXEmbed::sendSyntheticConfigureNotifyEvent() {
+
+void QXEmbed::checkGrab()
+{
+ if (d->xplain && isActiveWindow() && !hasFocus()) {
+ if (! d->xgrab)
+ XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, winId(),
+ FALSE, ButtonPressMask, GrabModeSync, GrabModeAsync,
+ None, None );
+ d->xgrab = TRUE;
+ } else {
+ if (d->xgrab)
+ XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() );
+ d->xgrab = FALSE;
+ }
+}
+
+
+void QXEmbed::sendSyntheticConfigureNotifyEvent()
+{
QPoint globalPos = mapToGlobal(QPoint(0,0));
if (window) {
// kdDebug(6100) << "*************** sendSyntheticConfigureNotify \
******************" << endl;
["nsplugin.diff" (text/x-diff)]
Index: nspluginloader.cpp
===================================================================
RCS file: /home/kde/kdebase/nsplugins/nspluginloader.cpp,v
retrieving revision 1.30
diff -u -3 -p -r1.30 nspluginloader.cpp
--- nspluginloader.cpp 27 Oct 2002 18:31:00 -0000 1.30
+++ nspluginloader.cpp 21 Feb 2003 14:16:44 -0000
@@ -56,6 +56,7 @@ NSPluginInstance::NSPluginInstance(QWidg
shown = false;
_loader = NSPluginLoader::instance();
setBackgroundMode(QWidget::NoBackground);
+ setProtocol(QXEmbed::XPLAIN);
embed( NSPluginInstanceIface_stub::winId() );
displayPlugin();
shown = true;
Index: viewer/nsplugin.cpp
===================================================================
RCS file: /home/kde/kdebase/nsplugins/viewer/nsplugin.cpp,v
retrieving revision 1.77
diff -u -3 -p -r1.77 nsplugin.cpp
--- viewer/nsplugin.cpp 22 Aug 2002 16:39:59 -0000 1.77
+++ viewer/nsplugin.cpp 21 Feb 2003 14:16:45 -0000
@@ -322,6 +322,20 @@ NPError g_NPN_SetValue(NPP /*instance*/,
/******************************************************************/
+void
+NSPluginInstance::forwarder(Widget w, XtPointer cl_data, XEvent * event, Boolean * cont)
+{
+ NSPluginInstance *inst = (NSPluginInstance*)cl_data;
+ *cont = True;
+ if (inst->_area == 0 || event->xkey.window == XtWindow(inst->_area))
+ return;
+ *cont = False;
+ event->xkey.window = XtWindow(inst->_area);
+ event->xkey.subwindow = None;
+ XtDispatchEvent(event);
+}
+
+
NSPluginInstance::NSPluginInstance(NPP privateData, NPPluginFuncs *pluginFuncs,
KLibrary *handle, int width, int height,
QString src, QString /*mime*/,
@@ -381,6 +395,12 @@ NSPluginInstance::NSPluginInstance(NPP p
_area = XmCreateDrawingArea( _form, (char*)("drawingArea"), args, nargs);
XtRealizeWidget(_area);
XtMapWidget(_area);
+
+ // Register forwarder
+ XtAddEventHandler(_toplevel, (KeyPressMask|KeyReleaseMask),
+ False, forwarder, (XtPointer)this );
+ XtAddEventHandler(_form, (KeyPressMask|KeyReleaseMask),
+ False, forwarder, (XtPointer)this );
}
NSPluginInstance::~NSPluginInstance()
@@ -429,6 +449,10 @@ void NSPluginInstance::destroy()
if (saved)
g_NPN_MemFree(saved);
+ XtRemoveEventHandler(_form, (KeyPressMask|KeyReleaseMask),
+ False, forwarder, (XtPointer)this);
+ XtRemoveEventHandler(_toplevel, (KeyPressMask|KeyReleaseMask),
+ False, forwarder, (XtPointer)this);
XtDestroyWidget(_area);
XtDestroyWidget(_form);
XtDestroyWidget(_toplevel);
Index: viewer/nsplugin.h
===================================================================
RCS file: /home/kde/kdebase/nsplugins/viewer/nsplugin.h,v
retrieving revision 1.32
diff -u -3 -p -r1.32 nsplugin.h
--- viewer/nsplugin.h 9 Jul 2002 04:18:52 -0000 1.32
+++ viewer/nsplugin.h 21 Feb 2003 14:16:45 -0000
@@ -201,6 +201,8 @@ private slots:
private:
friend class NSPluginStreamBase;
+ static void forwarder(Widget, XtPointer, XEvent *, Boolean*);
+
void destroy();
bool _destroyed;
>> Visit http://mail.kde.org/mailman/listinfo/kde-devel#unsub to unsubscribe <<
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic