From kwin Mon Oct 13 22:42:20 2003 From: Leon Bottou Date: Mon, 13 Oct 2003 22:42:20 +0000 To: kwin Subject: Re: [Kwin] Re: Embedding multible java applets and focus problems X-MARC-Message: https://marc.info/?l=kwin&m=106608505730889 MIME-Version: 1 Content-Type: multipart/mixed; boundary="--Boundary-00=_Mpyi/o2E/4bWK1h" --Boundary-00=_Mpyi/o2E/4bWK1h Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline 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. --Boundary-00=_Mpyi/o2E/4bWK1h Content-Type: text/x-c++src; charset="iso-8859-1"; name="qxembedtest.cpp" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="qxembedtest.cpp" #include #include #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(); } --Boundary-00=_Mpyi/o2E/4bWK1h Content-Type: text/x-diff; charset="iso-8859-1"; name="qxembed.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="qxembed.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. + + - Accumulated community knowledge. + + + +*/ + #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; --Boundary-00=_Mpyi/o2E/4bWK1h Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Kwin mailing list Kwin@mail.kde.org http://mail.kde.org/mailman/listinfo/kwin --Boundary-00=_Mpyi/o2E/4bWK1h--