[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