[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kfm-devel
Subject:    Re: [Kwin] Re: Embedding multible java applets and focus problems
From:       Leon Bottou <leon () bottou ! org>
Date:       2003-10-13 22:42:20
[Download RAW message or body]

On Monday 13 October 2003 04:35 pm, Leon Bottou wrote:
> As it is now, the XAddToSaveSet is only performed
> when the embedding is achieved by calling embed().
> Not when using QXEmbed::embedClientIntoWindow().
> Nobody noticed...
>

After playing with it, I believe that QXEmbed should never perform XAddToSaveSet.

If the embedding application terminates on xkill, we never want the embedded 
application to resist the change and stick around.  In fact, if we really want this,
it is quite easy for the embedding application to call XAddToSaveSet just after 
calling QXEmbed::embed().

If the embedding application exits cleanly, we want the embedded application 
to exit cleanly too. This is already the case because autoDelete() takes care of this.

The only case when it does not happen is when we forget to properly 
destroy the hierarchy of Qt widgets.   This can happen when the
toplevel widget is allocated with new and someone calls qApp->quit()
and exits without performing a delete.  This is in fact the only case where
the XAddToChangeSet makes a difference.  Maybe this is what is happening
with the java viewer.

So here is my latest patches.

They work with the little test program below (qxembedtest.cpp).
I will now replace my libkdeui.so and see what happens...

- L.



["qxembedtest.cpp" (text/x-c++src)]

#include <stdlib.h>
#include <stdio.h>

#include "qxembed.h"

#include "qapplication.h"
#include "qpushbutton.h"
#include "qlineedit.h"
#include "qhbox.h"
#include "qvbox.h"


void 
die(char *s)
{
  fprintf(stderr,"qxembedtest: %s\n", s);
  exit(10);
}

int 
main(int argc, char**argv)
{
  WId wid;

  QApplication a(argc, argv);
  
  if (argc != 2)
    die("usage: qxembedtest [qtoptions] windowid");
  wid = strtol(argv[1], NULL, 0);
  if (! wid)
    die("qxembedtest: illegal window id");
  fprintf(stderr,"qxembedtest: using wid=0x%08x\n", wid);
  
  QWidget *main = new QVBox(NULL,"main",Qt::WDestructiveClose);
  QWidget *top = new QHBox(main);
  
  QPushButton *quit = new QPushButton("Quit", top);
  QObject::connect( quit, SIGNAL(clicked()), main, SLOT(close()) );
  QLineEdit *edit = new QLineEdit(top);
  edit->setText( "Just to see focus changes");

  QXEmbed *embed = new QXEmbed(main);
  embed->setProtocol(QXEmbed::XPLAIN);
  embed->setAutoDelete(true);

  a.setMainWidget(main);
  main->show();
  
  embed->embed(wid);

  return a.exec();
}

["qxembed.diff" (text/x-diff)]

? kpixmapio.loT
? qxembed.diff
? qxembedtest
Index: qxembed.cpp
===================================================================
RCS file: /home/kde/kdelibs/kdeui/qxembed.cpp,v
retrieving revision 1.44
diff -u -3 -p -r1.44 qxembed.cpp
--- qxembed.cpp	25 Sep 2003 18:16:54 -0000	1.44
+++ qxembed.cpp	13 Oct 2003 22:39:09 -0000
@@ -51,6 +51,26 @@
 
 #include "qxembed.h"
 
+/* WARNING: 
+   Breaking QXEmbed breaks most of KDE.
+   To make things worse, QXEmbed is a very 
+   intricate code with inadequate comments.
+
+   Suggested readings:
+   - Xlib Reference Manual  
+       (sections about focus, reparenting, window management)
+   - ICCCM Manual
+       (window management)
+   - XEMBED specification 
+       (http://www.freedesktop.org/Standards/xembed-spec)
+   - XPLAIN and XEMBED.
+       <http://lists.kde.org/?w=2&r=1&s=qxembed+variants&q=t>
+   - Accumulated community knowledge.
+       <http://lists.kde.org/?w=2&r=1&s=qxembed&q=t>
+       <http://lists.kde.org/?l=kde-devel&w=2&r=1&s=qxembed&q=b>
+       <http://lists.kde.org/?l=kfm-devel&w=2&r=1&s=qxembed&q=b>
+*/
+
 #ifndef XK_ISO_Left_Tab
 #define XK_ISO_Left_Tab                                 0xFE20
 #endif
@@ -492,27 +512,24 @@ QXEmbed::~QXEmbed()
   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);
-
-        if ( autoDelete() ) {
-            XEvent ev;
-            memset(&ev, 0, sizeof(ev));
-            ev.xclient.type = ClientMessage;
-            ev.xclient.window = window;
-            ev.xclient.message_type = qt_wm_protocols;
-            ev.xclient.format = 32;
-            ev.xclient.data.s[0] = qt_wm_delete_window;
-            XSendEvent(qt_xdisplay(), window, false, NoEventMask, &ev);
-        }
-        XFlush( qt_xdisplay() );
-     }
+  if ( window && autoDelete() ) 
+      {
+          XUnmapWindow( qt_xdisplay(), window );
+          XReparentWindow(qt_xdisplay(), window, qt_xrootwin(), 0, 0);
+          XSync(qt_xdisplay(), false);
+          
+          XEvent ev;
+          memset(&ev, 0, sizeof(ev));
+          ev.xclient.type = ClientMessage;
+          ev.xclient.window = window;
+          ev.xclient.message_type = qt_wm_protocols;
+          ev.xclient.format = 32;
+          ev.xclient.data.s[0] = qt_wm_delete_window;
+          XSendEvent(qt_xdisplay(), window, false, NoEventMask, &ev);
+          XFlush( qt_xdisplay() );
+      }
+
   window = 0;
-  
   Window focus;
   int revert;
   XGetInputFocus( qt_xdisplay(), &focus, &revert );
@@ -678,6 +695,7 @@ void QXEmbed::focusOutEvent( QFocusEvent
         send_xembed_message( window, XEMBED_FOCUS_OUT );
     }
     if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
+      if ( qApp->activeWindow() == topLevelWidget() )
         XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
                         RevertToParent, qt_x_time );
 }
@@ -735,15 +753,15 @@ void QXEmbed::embed(WId w)
     kdDebug() << "************************** Embed "<< QString("0x%1").arg(w, 0, 16) \
<< " into " << QString("0x%1").arg(winId(), 0, 16) << " window=" << \
QString("0x%1").arg(window, 0, 16) << " **********" << endl;   if (!w)
         return;
-    XAddToSaveSet( qt_xdisplay(), w );
-    bool has_window =  w == window;
+
+    bool has_window =  (w == window);
     window = w;
     if ( !has_window ) {
         if ( !wstate_withdrawn(window) ) {
             XWithdrawWindow(qt_xdisplay(), window, qt_xscreen());
             QApplication::flushX();
             while (!wstate_withdrawn(window))
-                ;
+                USLEEP(1000);
         }
         Window parent;
         get_parent(w, &parent);
@@ -758,28 +776,6 @@ void QXEmbed::embed(WId w)
             kdDebug() << QString(">>> Loop %1: reparent of 0x%2 into 0x%3 \
failed").arg(i).arg(w, 0, 16).arg(winId(), 0, 16) << endl;  USLEEP(1000);
         }
-        QApplication::syncX();
-    }
-
-    XResizeWindow(qt_xdisplay(), w, width(), height());
-    XMapRaised(qt_xdisplay(), window);
-    sendSyntheticConfigureNotifyEvent();
-    extraData()->xDndProxy = w;
-
-    if ( parent() ) {
-        QEvent * layoutHint = new QEvent( QEvent::LayoutHint );
-        QApplication::postEvent( parent(), layoutHint );
-    }
-    windowChanged( window );
-    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 );
     }
 }
 
@@ -829,7 +825,29 @@ bool QXEmbed::x11Event( XEvent* e)
         } else if ( e->xreparent.parent == winId() ){
             // we got a window
             window = e->xreparent.window;
-            embed( window );
+            // finish the embedding process
+            XResizeWindow(qt_xdisplay(), window, width(), height());
+            XMapRaised(qt_xdisplay(), window);
+            sendSyntheticConfigureNotifyEvent();
+            extraData()->xDndProxy = window;
+            if ( parent() ) {
+                QEvent * layoutHint = new QEvent( QEvent::LayoutHint );
+                QApplication::postEvent( parent(), layoutHint );
+            }
+            windowChanged( window );
+            if (d->xplain) {
+                checkGrab();
+                if ( hasFocus() )
+                    sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer \
); +            } else {
+                 send_xembed_message( window, XEMBED_EMBEDDED_NOTIFY, 0, (long) \
winId() ); +                 if (isActiveWindow())
+                     send_xembed_message( window, XEMBED_WINDOW_ACTIVATE);
+                 else
+                     send_xembed_message( window, XEMBED_WINDOW_DEACTIVATE);
+                 if ( hasFocus() )
+                     send_xembed_message( window, XEMBED_FOCUS_IN );
+            }
         }
         break;
     case ButtonPress:
@@ -1016,10 +1034,24 @@ QSize QXEmbed::minimumSizeHint() const
     return QSize( minw, minh );
 }
 
+/*!  
+   Sets the flag indicating what shoud be done with the embedded window when
+   the embedding window is destroyed.  When the flag is true, the embedded
+   window stays alive and receives a WM_DELETE_WINDOW message that causes most
+   applications to exit cleanly.  This is the default.  Otherwise, the
+   destruction of the QXEmbed object simply destroys the embedded window.
+*/
+
 void QXEmbed::setAutoDelete( bool b)
 {
     d->autoDelete = b;
 }
+
+/*!
+   Returns the value of flag indicating what shoud be done with the
+   embedded window when the embedding window is destroyed.
+   \sa setAutoDelete()
+ */
 
 bool QXEmbed::autoDelete() const
 {
Index: qxembed.h
===================================================================
RCS file: /home/kde/kdelibs/kdeui/qxembed.h,v
retrieving revision 1.21
diff -u -3 -p -r1.21 qxembed.h
--- qxembed.h	21 Aug 2003 09:51:37 -0000	1.21
+++ qxembed.h	13 Oct 2003 22:39:09 -0000
@@ -176,7 +176,21 @@ public:
 
     bool eventFilter( QObject *, QEvent * );
 
+    /**
+     * Sets the flag indicating what shoud be done with the embedded window
+     * when the embedding window is destroyed.  When the flag is true, the
+     * embedded window stays alive and receives a WM_DELETE_WINDOW message
+     * that causes most applications to exit cleanly.  This is the default.
+     * Otherwise, the destruction of the QXEmbed object simply destroys the
+     * embedded window. 
+     */
     void setAutoDelete( bool );
+
+    /**
+     * Returns the value of flag indicating what shoud be done with the
+     * embedded window when the embedding window is destroyed.
+     * \sa setAutoDelete()
+     */
     bool autoDelete() const;
 
     bool customWhatsThis() const;



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic