src/gui/kernel/qx11embed_x11.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qplatformdefs.h"
       
    43 #include "qx11embed_x11.h"
       
    44 #include <qapplication.h>
       
    45 #include <qevent.h>
       
    46 #include <qpainter.h>
       
    47 #include <qlayout.h>
       
    48 #include <qstyle.h>
       
    49 #include <qstyleoption.h>
       
    50 #include <qdatetime.h>
       
    51 #include <qpointer.h>
       
    52 #include <qdebug.h>
       
    53 #include <qx11info_x11.h>
       
    54 #include <private/qt_x11_p.h>
       
    55 #include <private/qwidget_p.h>
       
    56 
       
    57 #define XK_MISCELLANY
       
    58 #define XK_LATIN1
       
    59 #define None 0
       
    60 #include <X11/Xlib.h>
       
    61 #include <X11/Xatom.h>
       
    62 #include <X11/Xutil.h>
       
    63 #include <X11/keysymdef.h>
       
    64 #include <X11/X.h>
       
    65 
       
    66 #ifndef XK_ISO_Left_Tab
       
    67 #define XK_ISO_Left_Tab 0xFE20
       
    68 #endif
       
    69 
       
    70 //#define QX11EMBED_DEBUG
       
    71 #ifdef QX11EMBED_DEBUG
       
    72 #include <qdebug.h>
       
    73 #endif
       
    74 
       
    75 QT_BEGIN_NAMESPACE
       
    76 
       
    77 /*!
       
    78     \class QX11EmbedWidget
       
    79     \ingroup advanced
       
    80 
       
    81     \brief The QX11EmbedWidget class provides an XEmbed client widget.
       
    82 
       
    83     XEmbed is an X11 protocol that supports the embedding of a widget
       
    84     from one application into another application.
       
    85 
       
    86     An XEmbed \e{client widget} is a window that is embedded into a
       
    87     \e container. A container is the graphical location that embeds
       
    88     (or \e swallows) an external application.
       
    89 
       
    90     QX11EmbedWidget is a widget used for writing XEmbed applets or
       
    91     plugins. When it has been embedded and the container receives tab
       
    92     focus, focus is passed on to the widget. When the widget reaches
       
    93     the end of its focus chain, focus is passed back to the
       
    94     container. Window activation, accelerator support, modality and
       
    95     drag and drop (XDND) are also handled.
       
    96 
       
    97     The widget and container can both initiate the embedding. If the
       
    98     widget is the initiator, the X11 window ID of the container that
       
    99     it wants to embed itself into must be passed to embedInto().
       
   100 
       
   101     If the container initiates the embedding, the window ID of the
       
   102     embedded widget must be known. The container calls embed(),
       
   103     passing the window ID.
       
   104 
       
   105     This example shows an application that embeds a QX11EmbedWidget
       
   106     subclass into the window whose ID is passed as a command-line
       
   107     argument:
       
   108 
       
   109     \snippet doc/src/snippets/qx11embedwidget/main.cpp 0
       
   110 
       
   111     The problem of obtaining the window IDs is often solved by the
       
   112     container invoking the application that provides the widget as a
       
   113     separate process (as a panel invokes a docked applet), passing
       
   114     its window ID to the new process as a command-line argument. The
       
   115     new process can then call embedInto() with the container's window
       
   116     ID, as shown in the example code above. Similarly, the new
       
   117     process can report its window ID to the container through IPC, in
       
   118     which case the container can embed the widget.
       
   119 
       
   120     When the widget has been embedded, it emits the signal
       
   121     embedded(). If it is closed by the container, the widget emits
       
   122     containerClosed(). If an error occurs when embedding, error() is
       
   123     emitted.
       
   124 
       
   125     There are XEmbed widgets available for KDE and GTK+. The GTK+
       
   126     equivalent of QX11EmbedWidget is GtkPlug. The corresponding KDE 3
       
   127     widget is called QXEmbed.
       
   128 
       
   129     \sa QX11EmbedContainer, {XEmbed Specification}
       
   130 */
       
   131 
       
   132 /*!
       
   133     \class QX11EmbedContainer
       
   134     \ingroup advanced
       
   135 
       
   136     \brief The QX11EmbedContainer class provides an XEmbed container
       
   137     widget.
       
   138 
       
   139     XEmbed is an X11 protocol that supports the embedding of a widget
       
   140     from one application into another application.
       
   141 
       
   142     An XEmbed \e container is the graphical location that embeds an
       
   143     external \e {client widget}. A client widget is a window that is
       
   144     embedded into a container.
       
   145 
       
   146     When a widget has been embedded and the container receives tab
       
   147     focus, focus is passed on to the widget. When the widget reaches
       
   148     the end of its focus chain, focus is passed back to the
       
   149     container. Window activation, accelerator support, modality and
       
   150     drag and drop (XDND) are also handled.
       
   151 
       
   152     QX11EmbedContainer is commonly used for writing panels or
       
   153     toolbars that hold applets, or for \e swallowing X11
       
   154     applications. When writing a panel application, one container
       
   155     widget is created on the toolbar, and it can then either swallow
       
   156     another widget using embed(), or allow an XEmbed widget to be
       
   157     embedded into itself. The container's X11 window ID, which is
       
   158     retrieved with winId(), must then be known to the client widget.
       
   159     After embedding, the client's window ID can be retrieved with
       
   160     clientWinId().
       
   161 
       
   162     In the following example, a container widget is created as the
       
   163     main widget. It then invokes an application called "playmovie",
       
   164     passing its window ID as a command line argument. The "playmovie"
       
   165     program is an XEmbed client widget. The widget embeds itself into
       
   166     the container using the container's window ID.
       
   167 
       
   168     \snippet doc/src/snippets/qx11embedcontainer/main.cpp 0
       
   169 
       
   170     When the client widget is embedded, the container emits the
       
   171     signal clientIsEmbedded(). The signal clientClosed() is emitted
       
   172     when a widget is closed.
       
   173 
       
   174     It is possible for QX11EmbedContainer to embed XEmbed widgets
       
   175     from toolkits other than Qt, such as GTK+. Arbitrary (non-XEmbed)
       
   176     X11 widgets can also be embedded, but the XEmbed-specific
       
   177     features such as window activation and focus handling are then
       
   178     lost.
       
   179 
       
   180     The GTK+ equivalent of QX11EmbedContainer is GtkSocket. The
       
   181     corresponding KDE 3 widget is called QXEmbed.
       
   182 
       
   183     \sa QX11EmbedWidget, {XEmbed Specification}
       
   184 */
       
   185 
       
   186 /*! \fn void QX11EmbedWidget::embedded()
       
   187 
       
   188     This signal is emitted by the widget that has been embedded by an
       
   189     XEmbed container.
       
   190 */
       
   191 
       
   192 /*! \fn void QX11EmbedWidget::containerClosed()
       
   193 
       
   194     This signal is emitted by the client widget when the container
       
   195     closes the widget. This can happen if the container itself
       
   196     closes, or if the widget is rejected.
       
   197 
       
   198     The container can reject a widget for any reason, but the most
       
   199     common cause of a rejection is when an attempt is made to embed a
       
   200     widget into a container that already has an embedded widget.
       
   201 */
       
   202 
       
   203 /*! \fn void QX11EmbedContainer::clientIsEmbedded()
       
   204 
       
   205     This signal is emitted by the container when a client widget has
       
   206     been embedded.
       
   207 */
       
   208 
       
   209 /*! \fn void QX11EmbedContainer::clientClosed()
       
   210 
       
   211     This signal is emitted by the container when the client widget
       
   212     closes.
       
   213 */
       
   214 
       
   215 /*!
       
   216     \fn void QX11EmbedWidget::error(QX11EmbedWidget::Error error)
       
   217 
       
   218     This signal is emitted if an error occurred as a result of
       
   219     embedding into or communicating with a container. The specified
       
   220     \a error describes the problem that occurred.
       
   221 
       
   222     \sa QX11EmbedWidget::Error
       
   223 */
       
   224 
       
   225 /*!
       
   226     \fn QX11EmbedContainer::Error QX11EmbedContainer::error() const
       
   227 
       
   228     Returns the last error that occurred.
       
   229 */
       
   230 
       
   231 /*! \fn void QX11EmbedContainer::error(QX11EmbedContainer::Error error)
       
   232 
       
   233     This signal is emitted if an error occurred when embedding or
       
   234     communicating with a client. The specified \a error describes the
       
   235     problem that occurred.
       
   236 
       
   237     \sa QX11EmbedContainer::Error
       
   238 */
       
   239 
       
   240 /*!
       
   241     \enum QX11EmbedWidget::Error
       
   242 
       
   243     \value Unknown An unrecognized error occurred.
       
   244 
       
   245     \value InvalidWindowID The X11 window ID of the container was
       
   246         invalid. This error is usually triggered by passing an invalid
       
   247         window ID to embedInto().
       
   248 
       
   249     \omitvalue Internal
       
   250 */
       
   251 
       
   252 /*!
       
   253     \enum QX11EmbedContainer::Error
       
   254 
       
   255     \value Unknown An unrecognized error occurred.
       
   256 
       
   257     \value InvalidWindowID The X11 window ID of the container was
       
   258         invalid. This error is usually triggered by passing an invalid
       
   259         window ID to embed().
       
   260 
       
   261     \omitvalue Internal
       
   262 */
       
   263 
       
   264 const int XButtonPress = ButtonPress;
       
   265 const int XButtonRelease = ButtonRelease;
       
   266 #undef ButtonPress
       
   267 #undef ButtonRelease
       
   268 
       
   269 // This is a hack to move topData() out from QWidgetPrivate to public.  We
       
   270 // need to to inspect window()'s embedded state.
       
   271 class QHackWidget : public QWidget
       
   272 {
       
   273     Q_DECLARE_PRIVATE(QWidget)
       
   274 public:
       
   275     QTLWExtra* topData() { return d_func()->topData(); }
       
   276 };
       
   277 
       
   278 static unsigned int XEMBED_VERSION = 0;
       
   279 
       
   280 enum QX11EmbedMessageType {
       
   281     XEMBED_EMBEDDED_NOTIFY = 0,
       
   282     XEMBED_WINDOW_ACTIVATE = 1,
       
   283     XEMBED_WINDOW_DEACTIVATE = 2,
       
   284     XEMBED_REQUEST_FOCUS = 3,
       
   285     XEMBED_FOCUS_IN = 4,
       
   286     XEMBED_FOCUS_OUT = 5,
       
   287     XEMBED_FOCUS_NEXT = 6,
       
   288     XEMBED_FOCUS_PREV = 7,
       
   289     XEMBED_MODALITY_ON = 10,
       
   290     XEMBED_MODALITY_OFF = 11,
       
   291     XEMBED_REGISTER_ACCELERATOR = 12,
       
   292     XEMBED_UNREGISTER_ACCELERATOR = 13,
       
   293     XEMBED_ACTIVATE_ACCELERATOR = 14
       
   294 };
       
   295 
       
   296 enum QX11EmbedFocusInDetail {
       
   297     XEMBED_FOCUS_CURRENT = 0,
       
   298     XEMBED_FOCUS_FIRST = 1,
       
   299     XEMBED_FOCUS_LAST = 2
       
   300 };
       
   301 
       
   302 enum QX11EmbedFocusInFlags {
       
   303     XEMBED_FOCUS_OTHER = (0 << 0),
       
   304     XEMBED_FOCUS_WRAPAROUND = (1 << 0)
       
   305 };
       
   306 
       
   307 enum QX11EmbedInfoFlags {
       
   308     XEMBED_MAPPED = (1 << 0)
       
   309 };
       
   310 
       
   311 enum QX11EmbedAccelModifiers {
       
   312     XEMBED_MODIFIER_SHIFT = (1 << 0),
       
   313     XEMBED_MODIFIER_CONTROL = (1 << 1),
       
   314     XEMBED_MODIFIER_ALT = (1 << 2),
       
   315     XEMBED_MODIFIER_SUPER = (1 << 3),
       
   316     XEMBED_MODIFIER_HYPER = (1 << 4)
       
   317 };
       
   318 
       
   319 enum QX11EmbedAccelFlags {
       
   320     XEMBED_ACCELERATOR_OVERLOADED = (1 << 0)
       
   321 };
       
   322 
       
   323 // Silence the default X11 error handler.
       
   324 static int x11ErrorHandler(Display *, XErrorEvent *)
       
   325 {
       
   326     return 0;
       
   327 }
       
   328 
       
   329 // Returns the X11 timestamp. Maintained mainly by qapplication
       
   330 // internals, but also updated by the XEmbed widgets.
       
   331 static Time x11Time()
       
   332 {
       
   333     return qt_x11Data->time;
       
   334 }
       
   335 
       
   336 // Gives the version and flags of the supported XEmbed protocol.
       
   337 static unsigned int XEmbedVersion()
       
   338 {
       
   339     return 0;
       
   340 }
       
   341 
       
   342 // Sends an XEmbed message.
       
   343 static void sendXEmbedMessage(WId window, Display *display, long message,
       
   344                   long detail = 0, long data1 = 0, long data2 = 0)
       
   345 {
       
   346     XClientMessageEvent c;
       
   347     memset(&c, 0, sizeof(c));
       
   348     c.type = ClientMessage;
       
   349     c.message_type = ATOM(_XEMBED);
       
   350     c.format = 32;
       
   351     c.display = display;
       
   352     c.window = window;
       
   353 
       
   354     c.data.l[0] = x11Time();
       
   355     c.data.l[1] = message;
       
   356     c.data.l[2] = detail;
       
   357     c.data.l[3] = data1;
       
   358     c.data.l[4] = data2;
       
   359 
       
   360     XSendEvent(display, window, false, NoEventMask, (XEvent *) &c);
       
   361 }
       
   362 
       
   363 // From qapplication_x11.cpp
       
   364 static XKeyEvent lastKeyEvent;
       
   365 
       
   366 static QCoreApplication::EventFilter oldX11EventFilter;
       
   367 
       
   368 // The purpose of this global x11 filter is for one to capture the key
       
   369 // events in their original state, but most importantly this is the
       
   370 // only way to get the WM_TAKE_FOCUS message from WM_PROTOCOLS.
       
   371 static bool x11EventFilter(void *message, long *result)
       
   372 {
       
   373     XEvent *event = reinterpret_cast<XEvent *>(message);
       
   374     if (event->type == XKeyPress || event->type == XKeyRelease)
       
   375 	lastKeyEvent = event->xkey;
       
   376 
       
   377     if (oldX11EventFilter && oldX11EventFilter != &x11EventFilter)
       
   378 	return oldX11EventFilter(message, result);
       
   379     else
       
   380 	return false;
       
   381 }
       
   382 
       
   383 //
       
   384 struct functorData
       
   385 {
       
   386     Window id, rootWindow;
       
   387     bool clearedWmState;
       
   388     bool reparentedToRoot;
       
   389 };
       
   390 
       
   391 static Bool functor(Display *display, XEvent *event, XPointer arg)
       
   392 {
       
   393     functorData *data = (functorData *) arg;
       
   394 
       
   395     if (!data->reparentedToRoot && event->type == ReparentNotify
       
   396         && event->xreparent.window == data->id
       
   397         && event->xreparent.parent == data->rootWindow) {
       
   398         data->reparentedToRoot = true;
       
   399         return true;
       
   400     }
       
   401 
       
   402     if (!data->clearedWmState
       
   403         && event->type == PropertyNotify
       
   404         && event->xproperty.window == data->id
       
   405         && event->xproperty.atom == ATOM(WM_STATE)) {
       
   406 	if (event->xproperty.state == PropertyDelete) {
       
   407             data->clearedWmState = true;
       
   408             return true;
       
   409         }
       
   410 
       
   411 	Atom ret;
       
   412 	int format, status;
       
   413 	unsigned char *retval;
       
   414 	unsigned long nitems, after;
       
   415 	status = XGetWindowProperty(display, data->id, ATOM(WM_STATE), 0, 2, False, ATOM(WM_STATE),
       
   416 				    &ret, &format, &nitems, &after, &retval );
       
   417 	if (status == Success && ret == ATOM(WM_STATE) && format == 32 && nitems > 0) {
       
   418             long *state = (long *)retval;
       
   419 	    if (state[0] == WithdrawnState) {
       
   420                 data->clearedWmState = true;
       
   421 		return true;
       
   422             }
       
   423 	}
       
   424     }
       
   425 
       
   426     return false;
       
   427 }
       
   428 
       
   429 class QX11EmbedWidgetPrivate : public QWidgetPrivate
       
   430 {
       
   431     Q_DECLARE_PUBLIC(QX11EmbedWidget)
       
   432 public:
       
   433     inline QX11EmbedWidgetPrivate()
       
   434     {
       
   435         lastError = QX11EmbedWidget::Unknown;
       
   436         container = 0;
       
   437     }
       
   438 
       
   439     void setEmbedded();
       
   440 
       
   441     void emitError(QX11EmbedWidget::Error error) {
       
   442         Q_Q(QX11EmbedWidget);
       
   443 
       
   444         lastError = error;
       
   445         emit q->error(error);
       
   446     }
       
   447 
       
   448     enum FocusWidgets {
       
   449         FirstFocusWidget,
       
   450         LastFocusWidget
       
   451     };
       
   452 
       
   453     int focusOriginator;
       
   454     QWidget *getFocusWidget(FocusWidgets fw);
       
   455     void checkActivateWindow(QObject *o);
       
   456     QX11EmbedWidget *xEmbedWidget(QObject *o) const;
       
   457     void clearFocus();
       
   458 
       
   459     WId container;
       
   460     QPointer<QWidget> currentFocus;
       
   461 
       
   462     QX11EmbedWidget::Error lastError;
       
   463 
       
   464 };
       
   465 
       
   466 /*!
       
   467     Constructs a QX11EmbedWidget object with the given \a parent.
       
   468 */
       
   469 QX11EmbedWidget::QX11EmbedWidget(QWidget *parent)
       
   470     : QWidget(*new QX11EmbedWidgetPrivate, parent, 0)
       
   471 {
       
   472     XSetErrorHandler(x11ErrorHandler);
       
   473 
       
   474     setAttribute(Qt::WA_NativeWindow);
       
   475     setAttribute(Qt::WA_DontCreateNativeAncestors);
       
   476     createWinId();
       
   477     XSelectInput(x11Info().display(), internalWinId(),
       
   478                  KeyPressMask | KeyReleaseMask | ButtonPressMask
       
   479                     | ButtonReleaseMask
       
   480                     | KeymapStateMask | ButtonMotionMask | PointerMotionMask
       
   481                     | FocusChangeMask
       
   482                     | ExposureMask | StructureNotifyMask
       
   483                     | SubstructureNotifyMask | PropertyChangeMask);
       
   484 
       
   485     long data[] = {XEMBED_VERSION, XEMBED_MAPPED};
       
   486     XChangeProperty(x11Info().display(), internalWinId(), ATOM(_XEMBED_INFO),
       
   487                     ATOM(_XEMBED_INFO), 32, PropModeReplace,
       
   488                     (unsigned char*) data, 2);
       
   489 
       
   490     setFocusPolicy(Qt::StrongFocus);
       
   491     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
       
   492     QApplication::instance()->installEventFilter(this);
       
   493 
       
   494 #ifdef QX11EMBED_DEBUG
       
   495     qDebug() << "QX11EmbedWidget::QX11EmbedWidget: constructed client"
       
   496              << (void *)this << "with winId" << winId();
       
   497 #endif
       
   498 }
       
   499 
       
   500 /*!
       
   501     Destructs the QX11EmbedWidget object. If the widget is embedded
       
   502     when deleted, it is hidden and then detached from its container,
       
   503     so that the container is free to embed a new widget.
       
   504 */
       
   505 QX11EmbedWidget::~QX11EmbedWidget()
       
   506 {
       
   507     Q_D(QX11EmbedWidget);
       
   508     if (d->container) {
       
   509 #ifdef QX11EMBED_DEBUG
       
   510         qDebug() << "QX11EmbedWidget::~QX11EmbedWidget: unmapping"
       
   511                  << (void *)this << "with winId" << winId()
       
   512                  << "from container with winId" << d->container;
       
   513 #endif
       
   514         XUnmapWindow(x11Info().display(), internalWinId());
       
   515         XReparentWindow(x11Info().display(), internalWinId(), x11Info().appRootWindow(), 0, 0);
       
   516     }
       
   517 
       
   518 #ifdef QX11EMBED_DEBUG
       
   519     qDebug() << "QX11EmbedWidget::~QX11EmbedWidget: destructed client"
       
   520              << (void *)this << "with winId" << winId();
       
   521 #endif
       
   522 }
       
   523 
       
   524 /*!
       
   525     Returns the type of error that occurred last. This is the same error code
       
   526     that is emitted by the error() signal.
       
   527 
       
   528     \sa Error
       
   529 */
       
   530 QX11EmbedWidget::Error QX11EmbedWidget::error() const
       
   531 {
       
   532     return d_func()->lastError;
       
   533 }
       
   534 
       
   535 /*!
       
   536     When this function is called, the widget embeds itself into the
       
   537     container whose window ID is \a id.
       
   538 
       
   539     If \a id is \e not the window ID of a container this function will
       
   540     behave unpredictably.
       
   541 */
       
   542 void QX11EmbedWidget::embedInto(WId id)
       
   543 {
       
   544     Q_D(QX11EmbedWidget);
       
   545 #ifdef QX11EMBED_DEBUG
       
   546     qDebug() << "QX11EmbedWidget::embedInto: embedding client"
       
   547              << (void *)this << "with winId" << winId() << "into container"
       
   548              << id;
       
   549 #endif
       
   550 
       
   551     d->container = id;
       
   552     switch (XReparentWindow(x11Info().display(), internalWinId(), d->container, 0, 0)) {
       
   553     case BadWindow:
       
   554         d->emitError(InvalidWindowID);
       
   555         break;
       
   556     case BadMatch:
       
   557         d->emitError(Internal);
       
   558         break;
       
   559     case Success:
       
   560     default:
       
   561         break;
       
   562     }
       
   563     QTLWExtra* x = d->extra ? d->extra->topextra : 0;
       
   564     if (x)
       
   565         x->frameStrut.setCoords(0, 0, 0, 0);
       
   566     d->data.fstrut_dirty = false;
       
   567 }
       
   568 
       
   569 /*! \internal
       
   570 
       
   571     Gets the first or last child widget that can get focus.
       
   572 */
       
   573 QWidget *QX11EmbedWidgetPrivate::getFocusWidget(FocusWidgets fw)
       
   574 {
       
   575     Q_Q(QX11EmbedWidget);
       
   576     QWidget *tlw = q;
       
   577     QWidget *w = tlw->nextInFocusChain();
       
   578 
       
   579     QWidget *last = tlw;
       
   580 
       
   581     extern bool qt_tab_all_widgets;
       
   582     uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus;
       
   583 
       
   584     while (w != tlw)
       
   585     {
       
   586         if (((w->focusPolicy() & focus_flag) == focus_flag)
       
   587             && w->isVisibleTo(q) && w->isEnabled())
       
   588         {
       
   589             last = w;
       
   590             if (fw == FirstFocusWidget)
       
   591                 break;
       
   592         }
       
   593         w = w->nextInFocusChain();
       
   594     }
       
   595 
       
   596     return last;
       
   597 }
       
   598 
       
   599 /*! \internal
       
   600 
       
   601     Returns the xembed widget that the widget is a child of
       
   602 */
       
   603 QX11EmbedWidget *QX11EmbedWidgetPrivate::xEmbedWidget(QObject *o) const
       
   604 {
       
   605     QX11EmbedWidget *xec = 0;
       
   606 
       
   607     // Check the widget itself, then its parents, and find the first
       
   608     // QX11EmbedWidget.
       
   609     do {
       
   610         if ((xec = qobject_cast<QX11EmbedWidget *>(o)))
       
   611             return xec;
       
   612     } while ((o = o->parent()));
       
   613     return 0;
       
   614 }
       
   615 
       
   616 /*! \internal
       
   617 
       
   618     Checks the active window.
       
   619 */
       
   620 void QX11EmbedWidgetPrivate::checkActivateWindow(QObject *o)
       
   621 {
       
   622     Q_Q(QX11EmbedWidget);
       
   623     QX11EmbedWidget *xec = xEmbedWidget(o);
       
   624 
       
   625     // check if we are in the right xembed client
       
   626     if (q != xec)
       
   627         return;
       
   628 
       
   629     QWidget *w = qobject_cast<QWidget *>(o);
       
   630 
       
   631     // if it is no active window, then don't do the change
       
   632     if (!(w && qApp->activeWindow()))
       
   633         return;
       
   634 
       
   635     // if it already is the active window, don't do anything
       
   636     if (w->window() != qApp->activeWindow())
       
   637     {
       
   638         qApp->setActiveWindow(w->window());
       
   639         currentFocus = w;
       
   640 
       
   641         sendXEmbedMessage(xec->containerWinId(), q->x11Info().display(), XEMBED_REQUEST_FOCUS);
       
   642     }
       
   643 }
       
   644 
       
   645 /*! \internal
       
   646 
       
   647     Clears the focus
       
   648 */
       
   649 void QX11EmbedWidgetPrivate::clearFocus()
       
   650 {
       
   651     Q_Q(QX11EmbedWidget);
       
   652     // Setting focus on the client itself removes Qt's
       
   653     // logical focus rectangle. We can't just do a
       
   654     // clearFocus here, because when we send the synthetic
       
   655     // FocusIn to ourselves on activation, Qt will set
       
   656     // focus on focusWidget() again. This way, we "hide"
       
   657     // focus rather than clearing it.
       
   658 
       
   659     if (!q->window()->hasFocus())
       
   660         q->window()->setFocus(Qt::OtherFocusReason);
       
   661 
       
   662     currentFocus = 0;
       
   663 }
       
   664 
       
   665 /*! \internal
       
   666 
       
   667     Sets the embedded flag on the client.
       
   668 */
       
   669 void QX11EmbedWidgetPrivate::setEmbedded()
       
   670 {
       
   671     Q_Q(QX11EmbedWidget);
       
   672     ((QHackWidget *)q->window())->topData()->embedded = 1;
       
   673 }
       
   674 
       
   675 /*! \internal
       
   676 
       
   677     Handles WindowActivate and FocusIn events for the client.
       
   678 */
       
   679 bool QX11EmbedWidget::eventFilter(QObject *o, QEvent *event)
       
   680 {
       
   681     Q_D(QX11EmbedWidget);
       
   682     switch (event->type()) {
       
   683     case QEvent::FocusIn:
       
   684         switch (((QFocusEvent *)event)->reason()) {
       
   685         case Qt::MouseFocusReason:
       
   686             // If the user clicks into one of the client widget's
       
   687             // children and we didn't have focus already, we request
       
   688             // focus from our container.
       
   689             if (d->xEmbedWidget(o) == this) {
       
   690                 if (d->currentFocus.isNull())
       
   691                     sendXEmbedMessage(d->container, x11Info().display(), XEMBED_REQUEST_FOCUS);
       
   692 
       
   693                 d->currentFocus = qobject_cast<QWidget *>(o);
       
   694             }
       
   695             break;
       
   696         case Qt::TabFocusReason:
       
   697             // If the xembed client receives a focus event because of
       
   698             // a Tab, then we are at the end of our focus chain and we
       
   699             // ask the container to move to its next focus widget.
       
   700             if (o == this) {
       
   701                 d->clearFocus();
       
   702                 sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_NEXT);
       
   703                 return true;
       
   704             } else {
       
   705                 // We're listening on events from qApp, so in order
       
   706                 // for us to know who to set focus on if we receive an
       
   707                 // activation event, we note the widget that got the
       
   708                 // focusin last.
       
   709                 if (d->xEmbedWidget(o) == this)
       
   710                     d->currentFocus = qobject_cast<QWidget *>(o);
       
   711             }
       
   712             break;
       
   713         case Qt::BacktabFocusReason:
       
   714             // If the window receives a focus event because of
       
   715             // a Backtab, then we are at the start of our focus chain
       
   716             // and we ask the container to move to its previous focus
       
   717             // widget.
       
   718             if (o == this) {
       
   719                 // See comment for Tab.
       
   720                 // If we receive a XEMBED_FOCUS_IN
       
   721                 // XEMBED_FOCUS_CURRENT, we will set focus in
       
   722                 // currentFocus. To avoid that in this case, we reset
       
   723                 // currentFocus.
       
   724                 d->clearFocus();
       
   725                 sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_PREV);
       
   726                 return true;
       
   727             } else {
       
   728                 if (d->xEmbedWidget(o) == this)
       
   729                     d->currentFocus = qobject_cast<QWidget *>(o);
       
   730             }
       
   731             break;
       
   732         case Qt::ActiveWindowFocusReason:
       
   733             if (isActiveWindow()) {
       
   734                 if (!d->currentFocus.isNull()) {
       
   735                     if (!d->currentFocus->hasFocus())
       
   736                         d->currentFocus->setFocus(Qt::OtherFocusReason);
       
   737                 } else {
       
   738                     d->clearFocus();
       
   739                     return true;
       
   740                 }
       
   741             }
       
   742 
       
   743             break;
       
   744         case Qt::PopupFocusReason:
       
   745         case Qt::ShortcutFocusReason:
       
   746         case Qt::OtherFocusReason:
       
   747             // If focus is received to any child widget because of any
       
   748             // other reason, remember the widget so that we can give
       
   749             // it focus again if we're activated.
       
   750             if (d->xEmbedWidget(o) == this) {
       
   751                d->currentFocus = qobject_cast<QWidget *>(o);
       
   752             }
       
   753             break;
       
   754         default:
       
   755             break;
       
   756         }
       
   757         break;
       
   758     case QEvent::MouseButtonPress:
       
   759         // If we get a mouse button press event inside a embedded widget
       
   760         // make sure this is the active window in qapp.
       
   761         d->checkActivateWindow(o);
       
   762         break;
       
   763     default:
       
   764         break;
       
   765     }
       
   766 
       
   767     return QWidget::eventFilter(o, event);
       
   768 }
       
   769 
       
   770 /*! \internal
       
   771 
       
   772     Handles some notification events and client messages. Client side
       
   773     XEmbed message receiving is also handled here.
       
   774 */
       
   775 bool QX11EmbedWidget::x11Event(XEvent *event)
       
   776 {
       
   777     Q_D(QX11EmbedWidget);
       
   778     switch (event->type) {
       
   779     case DestroyNotify:
       
   780 #ifdef QX11EMBED_DEBUG
       
   781         qDebug() << "QX11EmbedWidget::x11Event: client"
       
   782                  << (void *)this << "with winId" << winId()
       
   783                  << "received a DestroyNotify";
       
   784 #endif
       
   785         // If the container window is destroyed, we signal this to the user.
       
   786         d->container = 0;
       
   787         emit containerClosed();
       
   788         break;
       
   789     case ReparentNotify:
       
   790 #ifdef QX11EMBED_DEBUG
       
   791         qDebug() << "QX11EmbedWidget::x11Event: client"
       
   792                  << (void *)this << "with winId" << winId()
       
   793                  << "received a ReparentNotify to"
       
   794                  << ((event->xreparent.parent == x11Info().appRootWindow())
       
   795                      ? QString::fromLatin1("root") : QString::number(event->xreparent.parent));
       
   796 #endif
       
   797         // If the container shuts down, we will be reparented to the
       
   798         // root window. We must also consider the case that we may be
       
   799         // reparented from one container to another.
       
   800         if (event->xreparent.parent == x11Info().appRootWindow()) {
       
   801             if (((QHackWidget *)this)->topData()->embedded) {
       
   802                 d->container = 0;
       
   803                 emit containerClosed();
       
   804             }
       
   805             return true;
       
   806         } else {
       
   807             d->container = event->xreparent.parent;
       
   808         }
       
   809         break;
       
   810     case UnmapNotify:
       
   811         // Mapping and unmapping are handled by changes to the
       
   812         // _XEMBED_INFO property. Any default map/unmap requests are
       
   813         // ignored.
       
   814         return true;
       
   815     case PropertyNotify:
       
   816         // The container sends us map/unmap messages through the
       
   817         // _XEMBED_INFO property. We adhere to the XEMBED_MAPPED bit in
       
   818         // data2.
       
   819         if (event->xproperty.atom == ATOM(_XEMBED_INFO)) {
       
   820             Atom actual_type_return;
       
   821             int actual_format_return;
       
   822             unsigned long nitems_return;
       
   823             unsigned long bytes_after_return;
       
   824             unsigned char *prop_return = 0;
       
   825             if (XGetWindowProperty(x11Info().display(), internalWinId(), ATOM(_XEMBED_INFO), 0, 2,
       
   826                                    false, ATOM(_XEMBED_INFO), &actual_type_return,
       
   827                                    &actual_format_return, &nitems_return,
       
   828                                    &bytes_after_return, &prop_return) == Success) {
       
   829                 if (nitems_return > 1) {
       
   830                     if (((long * )prop_return)[1] & XEMBED_MAPPED) {
       
   831                         XMapWindow(x11Info().display(), internalWinId());
       
   832                     } else {
       
   833                         XUnmapWindow(x11Info().display(), internalWinId());
       
   834                     }
       
   835                 }
       
   836             }
       
   837         }
       
   838 
       
   839         break;
       
   840     case ClientMessage:
       
   841         // XEMBED messages have message_type _XEMBED
       
   842         if (event->xclient.message_type == ATOM(_XEMBED)) {
       
   843             // Discard XEMBED messages not to ourselves. (### dead code?)
       
   844             if (event->xclient.window != internalWinId())
       
   845                 break;
       
   846 
       
   847             // Update qt_x_time if necessary
       
   848             Time msgtime = (Time) event->xclient.data.l[0];
       
   849             if (msgtime > X11->time)
       
   850                 X11->time = msgtime;
       
   851 
       
   852             switch (event->xclient.data.l[1]) {
       
   853             case XEMBED_WINDOW_ACTIVATE: {
       
   854                 // When we receive an XEMBED_WINDOW_ACTIVATE, we simply send
       
   855                 // ourselves a WindowActivate event. Real activation happens
       
   856                 // when receive XEMBED_FOCUS_IN.
       
   857                 if (!isActiveWindow()) {
       
   858                     QEvent ev(QEvent::WindowActivate);
       
   859                     QApplication::sendEvent(this, &ev);
       
   860                 }
       
   861             }
       
   862                 break;
       
   863             case XEMBED_WINDOW_DEACTIVATE: {
       
   864                 // When we receive an XEMBED_WINDOW_DEACTIVATE, we simply send
       
   865                 // ourselves a WindowDeactivate event. Real activation happens
       
   866                 // when receive XEMBED_FOCUS_IN.
       
   867                 if (isActiveWindow()) {
       
   868                     if (!qApp->activePopupWidget())
       
   869                         QApplication::setActiveWindow(0);
       
   870                 } else {
       
   871                     QEvent ev(QEvent::WindowDeactivate);
       
   872                     QApplication::sendEvent(this, &ev);
       
   873                 }
       
   874             }
       
   875                 break;
       
   876             case XEMBED_EMBEDDED_NOTIFY: {
       
   877 #ifdef QX11EMBED_DEBUG
       
   878                 qDebug() << "QX11EmbedWidget::x11Event: client"
       
   879                          << (void *)this << "with winId" << winId()
       
   880                          << "received an XEMBED EMBEDDED NOTIFY message";
       
   881 #endif
       
   882                 // In this message's l[2] we have the max version
       
   883                 // supported by both the client and the
       
   884                 // container. QX11EmbedWidget does not use this field.
       
   885 
       
   886                 // We have been embedded, so we set our
       
   887                 // client's embedded flag.
       
   888                 d->setEmbedded();
       
   889                 emit embedded();
       
   890             }
       
   891                 break;
       
   892             case XEMBED_FOCUS_IN:
       
   893                 // don't set the focus if a modal dialog is open
       
   894                 if (qApp->activeModalWidget())
       
   895                     break;
       
   896 
       
   897                 // in case we embed more than one topLevel window inside the same
       
   898                 // host window.
       
   899                 if (window() != qApp->activeWindow())
       
   900                     qApp->setActiveWindow(this);
       
   901 
       
   902                 switch (event->xclient.data.l[2]) {
       
   903                 case XEMBED_FOCUS_CURRENT:
       
   904                     // The container sends us this message if it wants
       
   905                     // us to focus on the widget that last had focus.
       
   906                     // This is the reply when XEMBED_REQUEST_FOCUS is
       
   907                     // sent to the container.
       
   908                     if (!d->currentFocus.isNull()) {
       
   909                         if (!d->currentFocus->hasFocus())
       
   910                             d->currentFocus->setFocus(Qt::OtherFocusReason);
       
   911                     } else {
       
   912                         // No widget currently has focus. We set focus
       
   913                         // on the first widget next to the
       
   914                         // client widget. Since the setFocus will not work
       
   915                         // if the window is disabled, set the currentFocus
       
   916                         // directly so that it's set on window activate.
       
   917                         d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::FirstFocusWidget);
       
   918                         d->currentFocus->setFocus(Qt::OtherFocusReason);
       
   919                     }
       
   920                     break;
       
   921                 case XEMBED_FOCUS_FIRST:
       
   922                     // The container sends this message when it wants
       
   923                     // us to focus on the first widget in our focus
       
   924                     // chain (typically because of a tab).
       
   925                     d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::FirstFocusWidget);
       
   926                     d->currentFocus->setFocus(Qt::TabFocusReason);
       
   927                     break;
       
   928                 case XEMBED_FOCUS_LAST:
       
   929                     // The container sends this message when it wants
       
   930                     // us to focus on the last widget in our focus
       
   931                     // chain (typically because of a backtab).
       
   932                     d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::LastFocusWidget);
       
   933                     d->currentFocus->setFocus(Qt::BacktabFocusReason);
       
   934                     break;
       
   935                 default:
       
   936                     // Ignore any other XEMBED_FOCUS_IN details.
       
   937                     break;
       
   938                 }
       
   939                 break;
       
   940             case XEMBED_FOCUS_OUT:
       
   941                 // The container sends us this message when it wants us
       
   942                 // to lose focus and forget about the widget that last
       
   943                 // had focus. Typically sent by the container when it
       
   944                 // loses focus because of mouse or tab activity. We do
       
   945                 // then not want to set focus on anything if we're
       
   946                 // activated.
       
   947                 if (isActiveWindow())
       
   948                     d->clearFocus();
       
   949 
       
   950                 break;
       
   951             default:
       
   952                 // Ignore any other XEMBED messages.
       
   953                 break;
       
   954             };
       
   955         } else {
       
   956             // Non-XEMBED client messages are not interesting.
       
   957         }
       
   958 
       
   959         break;
       
   960     default:
       
   961         // Ignore all other x11 events.
       
   962         break;
       
   963     }
       
   964 
       
   965     // Allow default handling.
       
   966     return QWidget::x11Event(event);
       
   967 }
       
   968 
       
   969 /*!
       
   970     \reimp
       
   971 */
       
   972 bool QX11EmbedWidget::event(QEvent *event)
       
   973 {
       
   974     if (event->type() == QEvent::ParentChange) {
       
   975         XSelectInput(x11Info().display(), internalWinId(),
       
   976                      KeyPressMask | KeyReleaseMask | ButtonPressMask
       
   977                      | ButtonReleaseMask
       
   978                      | KeymapStateMask | ButtonMotionMask | PointerMotionMask
       
   979                      | FocusChangeMask
       
   980                      | ExposureMask | StructureNotifyMask
       
   981                      | SubstructureNotifyMask | PropertyChangeMask);
       
   982     }
       
   983     return QWidget::event(event);
       
   984 }
       
   985 
       
   986 /*!
       
   987     \reimp
       
   988 */
       
   989 void QX11EmbedWidget::resizeEvent(QResizeEvent *event)
       
   990 {
       
   991     if (layout())
       
   992         layout()->update();
       
   993     QWidget::resizeEvent(event);
       
   994 }
       
   995 
       
   996 /*!
       
   997     If the widget is embedded, returns the window ID of the
       
   998     container; otherwize returns 0.
       
   999 */
       
  1000 WId QX11EmbedWidget::containerWinId() const
       
  1001 {
       
  1002     Q_D(const QX11EmbedWidget);
       
  1003     return d->container;
       
  1004 }
       
  1005 
       
  1006 class QX11EmbedContainerPrivate : public QWidgetPrivate
       
  1007 {
       
  1008     Q_DECLARE_PUBLIC(QX11EmbedContainer)
       
  1009 public:
       
  1010     inline QX11EmbedContainerPrivate()
       
  1011     {
       
  1012         lastError = QX11EmbedContainer::Unknown;
       
  1013         client = 0;
       
  1014         focusProxy = 0;
       
  1015         clientIsXEmbed = false;
       
  1016         xgrab = false;
       
  1017     }
       
  1018 
       
  1019     bool isEmbedded() const;
       
  1020     void moveInputToProxy();
       
  1021 
       
  1022     void acceptClient(WId window);
       
  1023     void rejectClient(WId window);
       
  1024 
       
  1025     void checkGrab();
       
  1026 
       
  1027     WId topLevelParentWinId() const;
       
  1028 
       
  1029     void emitError(QX11EmbedContainer::Error error) {
       
  1030         Q_Q(QX11EmbedContainer);
       
  1031         lastError = error;
       
  1032         emit q->error(error);
       
  1033     }
       
  1034 
       
  1035     WId client;
       
  1036     QWidget *focusProxy;
       
  1037     bool clientIsXEmbed;
       
  1038     bool xgrab;
       
  1039     QRect clientOriginalRect;
       
  1040     QSize wmMinimumSizeHint;
       
  1041 
       
  1042     QX11EmbedContainer::Error lastError;
       
  1043 
       
  1044     static QX11EmbedContainer *activeContainer;
       
  1045 };
       
  1046 
       
  1047 QX11EmbedContainer *QX11EmbedContainerPrivate::activeContainer = 0;
       
  1048 
       
  1049 /*!
       
  1050     Creates a QX11EmbedContainer object with the given \a parent.
       
  1051 */
       
  1052 QX11EmbedContainer::QX11EmbedContainer(QWidget *parent)
       
  1053     : QWidget(*new QX11EmbedContainerPrivate, parent, 0)
       
  1054 {
       
  1055     Q_D(QX11EmbedContainer);
       
  1056     XSetErrorHandler(x11ErrorHandler);
       
  1057 
       
  1058     setAttribute(Qt::WA_NativeWindow);
       
  1059     setAttribute(Qt::WA_DontCreateNativeAncestors);
       
  1060     createWinId();
       
  1061 
       
  1062     setFocusPolicy(Qt::StrongFocus);
       
  1063     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
       
  1064     // ### PORT setKeyCompression(false);
       
  1065     setAcceptDrops(true);
       
  1066     setEnabled(false);
       
  1067 
       
  1068     // Everybody gets a focus proxy, but only one toplevel container's
       
  1069     // focus proxy is actually in use.
       
  1070     d->focusProxy = new QWidget(this);
       
  1071     d->focusProxy->setAttribute(Qt::WA_NativeWindow);
       
  1072     d->focusProxy->setAttribute(Qt::WA_DontCreateNativeAncestors);
       
  1073     d->focusProxy->setGeometry(-1, -1, 1, 1);
       
  1074 
       
  1075     // We need events from the window (activation status) and
       
  1076     // from qApp (keypress/release).
       
  1077     qApp->installEventFilter(this);
       
  1078 
       
  1079     // Install X11 event filter.
       
  1080     if (!oldX11EventFilter)
       
  1081         oldX11EventFilter = QCoreApplication::instance()->setEventFilter(x11EventFilter);
       
  1082 
       
  1083     XSelectInput(x11Info().display(), internalWinId(),
       
  1084                  KeyPressMask | KeyReleaseMask
       
  1085                  | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
       
  1086                  | KeymapStateMask
       
  1087                  | PointerMotionMask
       
  1088                  | EnterWindowMask | LeaveWindowMask
       
  1089                  | FocusChangeMask
       
  1090                  | ExposureMask
       
  1091                  | StructureNotifyMask
       
  1092                  | SubstructureNotifyMask);
       
  1093 
       
  1094     // Make sure our new event mask takes effect as soon as possible.
       
  1095     XFlush(x11Info().display());
       
  1096 
       
  1097     // Move input to our focusProxy if this widget is active, and not
       
  1098     // shaded by a modal dialog (in which case isActiveWindow() would
       
  1099     // still return true, but where we must not move input focus).
       
  1100     if (qApp->activeWindow() == window() && !d->isEmbedded())
       
  1101         d->moveInputToProxy();
       
  1102 
       
  1103 #ifdef QX11EMBED_DEBUG
       
  1104     qDebug() << "QX11EmbedContainer::QX11EmbedContainer: constructed container"
       
  1105              << (void *)this << "with winId" << winId();
       
  1106 #endif
       
  1107 }
       
  1108 
       
  1109 /*!
       
  1110     Destructs a QX11EmbedContainer.
       
  1111 */
       
  1112 QX11EmbedContainer::~QX11EmbedContainer()
       
  1113 {
       
  1114     Q_D(QX11EmbedContainer);
       
  1115     if (d->client) {
       
  1116 	XUnmapWindow(x11Info().display(), d->client);
       
  1117 	XReparentWindow(x11Info().display(), d->client, x11Info().appRootWindow(), 0, 0);
       
  1118     }
       
  1119 
       
  1120     if (d->xgrab)
       
  1121 	XUngrabButton(x11Info().display(), AnyButton, AnyModifier, internalWinId());
       
  1122 }
       
  1123 
       
  1124 
       
  1125 QX11EmbedContainer::Error QX11EmbedContainer::error() const {
       
  1126     return d_func()->lastError;
       
  1127 }
       
  1128 
       
  1129 
       
  1130 /*! \reimp
       
  1131 */
       
  1132 void QX11EmbedContainer::paintEvent(QPaintEvent *)
       
  1133 {
       
  1134 }
       
  1135 
       
  1136 /*! \internal
       
  1137 
       
  1138     Returns wether or not the windows' embedded flag is set.
       
  1139 */
       
  1140 bool QX11EmbedContainerPrivate::isEmbedded() const
       
  1141 {
       
  1142     Q_Q(const QX11EmbedContainer);
       
  1143     return ((QHackWidget *)q->window())->topData()->embedded == 1;
       
  1144 }
       
  1145 
       
  1146 /*! \internal
       
  1147 
       
  1148     Returns the parentWinId of the window.
       
  1149 */
       
  1150 WId QX11EmbedContainerPrivate::topLevelParentWinId() const
       
  1151 {
       
  1152     Q_Q(const QX11EmbedContainer);
       
  1153     return ((QHackWidget *)q->window())->topData()->parentWinId;
       
  1154 }
       
  1155 
       
  1156 /*!
       
  1157     If the container has an embedded widget, this function returns
       
  1158     the X11 window ID of the client; otherwise it returns 0.
       
  1159 */
       
  1160 WId QX11EmbedContainer::clientWinId() const
       
  1161 {
       
  1162     Q_D(const QX11EmbedContainer);
       
  1163     return d->client;
       
  1164 }
       
  1165 
       
  1166 /*!
       
  1167     Instructs the container to embed the X11 window with window ID \a
       
  1168     id. The client widget will then move on top of the container
       
  1169     window and be resized to fit into the container.
       
  1170 
       
  1171     The \a id should be the ID of a window controlled by an XEmbed
       
  1172     enabled application, but this is not mandatory. If \a id does not
       
  1173     belong to an XEmbed client widget, then focus handling,
       
  1174     activation, accelerators and other features will not work
       
  1175     properly.
       
  1176 */
       
  1177 void QX11EmbedContainer::embedClient(WId id)
       
  1178 {
       
  1179     Q_D(QX11EmbedContainer);
       
  1180 
       
  1181     if (id == 0) {
       
  1182 	d->emitError(InvalidWindowID);
       
  1183 	return;
       
  1184     }
       
  1185 
       
  1186     // Walk up the tree of parent windows to prevent embedding of ancestors.
       
  1187     WId thisId = internalWinId();
       
  1188     Window rootReturn;
       
  1189     Window parentReturn;
       
  1190     Window *childrenReturn = 0;
       
  1191     unsigned int nchildrenReturn;
       
  1192     do {
       
  1193         if (XQueryTree(x11Info().display(), thisId, &rootReturn,
       
  1194                        &parentReturn, &childrenReturn, &nchildrenReturn) == 0) {
       
  1195 	    d->emitError(InvalidWindowID);
       
  1196 	    return;
       
  1197         }
       
  1198         if (childrenReturn) {
       
  1199             XFree(childrenReturn);
       
  1200             childrenReturn = 0;
       
  1201         }
       
  1202 
       
  1203         thisId = parentReturn;
       
  1204         if (id == thisId) {
       
  1205 	    d->emitError(InvalidWindowID);
       
  1206 	    return;
       
  1207         }
       
  1208     } while (thisId != rootReturn);
       
  1209 
       
  1210     // watch for property notify events (see below)
       
  1211     XGrabServer(x11Info().display());
       
  1212     XWindowAttributes attrib;
       
  1213     if (!XGetWindowAttributes(x11Info().display(), id, &attrib)) {
       
  1214         XUngrabServer(x11Info().display());
       
  1215 	d->emitError(InvalidWindowID);
       
  1216 	return;
       
  1217     }
       
  1218     XSelectInput(x11Info().display(), id, attrib.your_event_mask | PropertyChangeMask | StructureNotifyMask);
       
  1219     XUngrabServer(x11Info().display());
       
  1220 
       
  1221     // Put the window into WithdrawnState
       
  1222     XUnmapWindow(x11Info().display(), id);
       
  1223     XSync(x11Info().display(), False); // make sure the window is hidden
       
  1224 
       
  1225     /*
       
  1226       Wait for notification from the window manager that the window is
       
  1227       in withdrawn state.  According to the ICCCM section 4.1.3.1,
       
  1228       we should wait for the WM_STATE property to either be deleted or
       
  1229       set to WithdrawnState.
       
  1230 
       
  1231       For safety, we will not wait more than 500 ms, so that we can
       
  1232       preemptively workaround buggy window managers.
       
  1233     */
       
  1234     QTime t;
       
  1235     t.start();
       
  1236 
       
  1237     functorData data;
       
  1238     data.id = id;
       
  1239     data.rootWindow = attrib.root;
       
  1240     data.clearedWmState = false;
       
  1241     data.reparentedToRoot = false;
       
  1242 
       
  1243     do {
       
  1244 	if (t.elapsed() > 500) // time-out after 500 ms
       
  1245 	    break;
       
  1246 
       
  1247 	XEvent event;
       
  1248 	if (!XCheckIfEvent(x11Info().display(), &event, functor, (XPointer) &data)) {
       
  1249 	    XSync(x11Info().display(), False);
       
  1250             usleep(50000);
       
  1251 	    continue;
       
  1252 	}
       
  1253 
       
  1254         qApp->x11ProcessEvent(&event);
       
  1255     } while (!data.clearedWmState || !data.reparentedToRoot);
       
  1256 
       
  1257     // restore the event mask
       
  1258     XSelectInput(x11Info().display(), id, attrib.your_event_mask);
       
  1259 
       
  1260     switch (XReparentWindow(x11Info().display(), id, internalWinId(), 0, 0)) {
       
  1261     case BadWindow:
       
  1262     case BadMatch:
       
  1263 	d->emitError(InvalidWindowID);
       
  1264 	break;
       
  1265     default:
       
  1266 	break;
       
  1267     }
       
  1268 }
       
  1269 
       
  1270 /*! \internal
       
  1271 
       
  1272     Handles key, activation and focus events for the container.
       
  1273 */
       
  1274 bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event)
       
  1275 {
       
  1276     Q_D(QX11EmbedContainer);
       
  1277     switch (event->type()) {
       
  1278     case QEvent::KeyPress:
       
  1279         // Forward any keypresses to our client.
       
  1280 	if (o == this && d->client) {
       
  1281 	    lastKeyEvent.window = d->client;
       
  1282 	    XSendEvent(x11Info().display(), d->client, false, KeyPressMask, (XEvent *) &lastKeyEvent);
       
  1283 	    return true;
       
  1284 	}
       
  1285 	break;
       
  1286     case QEvent::KeyRelease:
       
  1287 	// Forward any keyreleases to our client.
       
  1288 	if (o == this && d->client) {
       
  1289 	    lastKeyEvent.window = d->client;
       
  1290 	    XSendEvent(x11Info().display(), d->client, false, KeyReleaseMask, (XEvent *) &lastKeyEvent);
       
  1291 	    return true;
       
  1292 	}
       
  1293 	break;
       
  1294 
       
  1295     case QEvent::WindowActivate:
       
  1296 	// When our container window is activated, we pass the
       
  1297 	// activation message on to our client. Note that X input
       
  1298 	// focus is set to our focus proxy. We want to intercept all
       
  1299 	// keypresses.
       
  1300 	if (o == window() && d->client) {
       
  1301             if (d->clientIsXEmbed) {
       
  1302                 sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_ACTIVATE);
       
  1303             } else {
       
  1304                 d->checkGrab();
       
  1305                 if (hasFocus())
       
  1306                     XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
       
  1307             }
       
  1308             if (!d->isEmbedded())
       
  1309                 d->moveInputToProxy();
       
  1310 	}
       
  1311 	break;
       
  1312     case QEvent::WindowDeactivate:
       
  1313 	// When our container window is deactivated, we pass the
       
  1314 	// deactivation message to our client.
       
  1315 	if (o == window() && d->client) {
       
  1316 	    if (d->clientIsXEmbed)
       
  1317 		sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_DEACTIVATE);
       
  1318 	    else
       
  1319 		d->checkGrab();
       
  1320 	}
       
  1321 	break;
       
  1322     case QEvent::FocusIn:
       
  1323         // When receiving FocusIn events generated by Tab or Backtab,
       
  1324 	// we pass focus on to our client. Any mouse activity is sent
       
  1325 	// directly to the client, and it will ask us for focus with
       
  1326 	// XEMBED_REQUEST_FOCUS.
       
  1327 	if (o == this && d->client) {
       
  1328             if (!d->isEmbedded())
       
  1329                 d->activeContainer = this;
       
  1330 
       
  1331             if (d->clientIsXEmbed) {
       
  1332                 if (!d->isEmbedded())
       
  1333                     d->moveInputToProxy();
       
  1334 
       
  1335 		QFocusEvent *fe = (QFocusEvent *)event;
       
  1336 		switch (fe->reason()) {
       
  1337 		case Qt::TabFocusReason:
       
  1338 		    sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST);
       
  1339 		    break;
       
  1340 		case Qt::BacktabFocusReason:
       
  1341 		    sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_LAST);
       
  1342 		    break;
       
  1343 		default:
       
  1344 		    sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
       
  1345 		    break;
       
  1346 		}
       
  1347 	    } else {
       
  1348 		d->checkGrab();
       
  1349                 XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
       
  1350 	    }
       
  1351 	}
       
  1352 
       
  1353 	break;
       
  1354     case QEvent::FocusOut: {
       
  1355 	// When receiving a FocusOut, we ask our client to remove its
       
  1356 	// focus.
       
  1357 	if (o == this && d->client) {
       
  1358             if (!d->isEmbedded()) {
       
  1359                 d->activeContainer = 0;
       
  1360                 if (isActiveWindow())
       
  1361                     d->moveInputToProxy();
       
  1362             }
       
  1363 
       
  1364 	    if (d->clientIsXEmbed) {
       
  1365 		QFocusEvent *fe = (QFocusEvent *)event;
       
  1366 		if (o == this && d->client && fe->reason() != Qt::ActiveWindowFocusReason)
       
  1367 		    sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_OUT);
       
  1368 	    } else {
       
  1369 		d->checkGrab();
       
  1370 	    }
       
  1371 	}
       
  1372     }
       
  1373 	break;
       
  1374 
       
  1375     case QEvent::Close: {
       
  1376 	if (o == this && d->client) {
       
  1377 	    // Unmap the client and reparent it to the root window.
       
  1378 	    // Wait until the messages have been processed. Then ask
       
  1379 	    // the window manager to delete the window.
       
  1380 	    XUnmapWindow(x11Info().display(), d->client);
       
  1381 	    XReparentWindow(x11Info().display(), d->client, x11Info().appRootWindow(), 0, 0);
       
  1382 	    XSync(x11Info().display(), false);
       
  1383 
       
  1384 	    XEvent ev;
       
  1385 	    memset(&ev, 0, sizeof(ev));
       
  1386 	    ev.xclient.type = ClientMessage;
       
  1387 	    ev.xclient.window = d->client;
       
  1388 	    ev.xclient.message_type = ATOM(WM_PROTOCOLS);
       
  1389 	    ev.xclient.format = 32;
       
  1390 	    ev.xclient.data.s[0] = ATOM(WM_DELETE_WINDOW);
       
  1391 	    XSendEvent(x11Info().display(), d->client, false, NoEventMask, &ev);
       
  1392 
       
  1393 	    XFlush(x11Info().display());
       
  1394 	    d->client = 0;
       
  1395 	    d->clientIsXEmbed = false;
       
  1396             d->wmMinimumSizeHint = QSize();
       
  1397             updateGeometry();
       
  1398             setEnabled(false);
       
  1399 	    update();
       
  1400 
       
  1401 	    emit clientClosed();
       
  1402 	}
       
  1403     }
       
  1404     default:
       
  1405 	break;
       
  1406     }
       
  1407 
       
  1408     return QWidget::eventFilter(o, event);
       
  1409 }
       
  1410 
       
  1411 /*! \internal
       
  1412 
       
  1413     Handles X11 events for the container.
       
  1414 */
       
  1415 bool QX11EmbedContainer::x11Event(XEvent *event)
       
  1416 {
       
  1417     Q_D(QX11EmbedContainer);
       
  1418 
       
  1419     switch (event->type) {
       
  1420     case CreateNotify:
       
  1421 	// The client created an embedded window.
       
  1422 	if (d->client)
       
  1423 	    d->rejectClient(event->xcreatewindow.window);
       
  1424 	else
       
  1425 	    d->acceptClient(event->xcreatewindow.window);
       
  1426       break;
       
  1427     case DestroyNotify:
       
  1428 	if (event->xdestroywindow.window == d->client) {
       
  1429 	    // The client died.
       
  1430 	    d->client = 0;
       
  1431 	    d->clientIsXEmbed = false;
       
  1432             d->wmMinimumSizeHint = QSize();
       
  1433             updateGeometry();
       
  1434 	    update();
       
  1435             setEnabled(false);
       
  1436 	    emit clientClosed();
       
  1437 	}
       
  1438         break;
       
  1439     case ReparentNotify:
       
  1440 	// The client sends us this if it reparents itself out of our
       
  1441 	// widget.
       
  1442 	if (event->xreparent.window == d->client && event->xreparent.parent != internalWinId()) {
       
  1443 	    d->client = 0;
       
  1444 	    d->clientIsXEmbed = false;
       
  1445             d->wmMinimumSizeHint = QSize();
       
  1446             updateGeometry();
       
  1447 	    update();
       
  1448             setEnabled(false);
       
  1449 	    emit clientClosed();
       
  1450 	} else if (event->xreparent.parent == internalWinId()) {
       
  1451 	    // The client reparented itself into this window.
       
  1452 	    if (d->client)
       
  1453 		d->rejectClient(event->xreparent.window);
       
  1454 	    else
       
  1455 		d->acceptClient(event->xreparent.window);
       
  1456 	}
       
  1457 	break;
       
  1458     case ClientMessage: {
       
  1459 	if (event->xclient.message_type == ATOM(_XEMBED)) {
       
  1460 	    // Ignore XEMBED messages not to ourselves
       
  1461 	    if (event->xclient.window != internalWinId())
       
  1462 		break;
       
  1463 
       
  1464 	    // Receiving an XEmbed message means the client
       
  1465 	    // is an XEmbed client.
       
  1466 	    d->clientIsXEmbed = true;
       
  1467 
       
  1468 	    Time msgtime = (Time) event->xclient.data.l[0];
       
  1469 	    if (msgtime > X11->time)
       
  1470 		X11->time = msgtime;
       
  1471 
       
  1472 	    switch (event->xclient.data.l[1]) {
       
  1473 	    case XEMBED_REQUEST_FOCUS: {
       
  1474 		// This typically happens when the client gets focus
       
  1475 		// because of a mouse click.
       
  1476 		if (!hasFocus())
       
  1477 		    setFocus(Qt::OtherFocusReason);
       
  1478 
       
  1479 		// The message is passed along to the topmost container
       
  1480 		// that eventually responds with a XEMBED_FOCUS_IN
       
  1481 		// message. The focus in message is passed all the way
       
  1482 		// back until it reaches the original focus
       
  1483 		// requestor. In the end, not only the original client
       
  1484 		// has focus, but also all its ancestor containers.
       
  1485 		if (d->isEmbedded()) {
       
  1486                     // If our window's embedded flag is set, then
       
  1487 		    // that suggests that we are part of a client. The
       
  1488 		    // parentWinId will then point to an container to whom
       
  1489 		    // we must pass this message.
       
  1490 		    sendXEmbedMessage(d->topLevelParentWinId(), x11Info().display(), XEMBED_REQUEST_FOCUS);
       
  1491 		} else {
       
  1492                     // Our window's embedded flag is not set,
       
  1493 		    // so we are the topmost container. We respond to
       
  1494 		    // the focus request message with a focus in
       
  1495 		    // message. This message will pass on from client
       
  1496 		    // to container to client until it reaches the
       
  1497 		    // originator of the XEMBED_REQUEST_FOCUS message.
       
  1498 		    sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
       
  1499 		}
       
  1500 
       
  1501 		break;
       
  1502 	    }
       
  1503 	    case XEMBED_FOCUS_NEXT:
       
  1504 		// Client sends this event when it received a tab
       
  1505 		// forward and was at the end of its focus chain. If
       
  1506 		// we are the only widget in the focus chain, we send
       
  1507 		// ourselves a FocusIn event.
       
  1508                 if (d->focus_next != this) {
       
  1509 		    focusNextPrevChild(true);
       
  1510                 } else {
       
  1511                     QFocusEvent event(QEvent::FocusIn, Qt::TabFocusReason);
       
  1512                     qApp->sendEvent(this, &event);
       
  1513                 }
       
  1514 
       
  1515 		break;
       
  1516 	    case XEMBED_FOCUS_PREV:
       
  1517 		// Client sends this event when it received a backtab
       
  1518 		// and was at the start of its focus chain. If we are
       
  1519 		// the only widget in the focus chain, we send
       
  1520 		// ourselves a FocusIn event.
       
  1521                 if (d->focus_next != this) {
       
  1522 		    focusNextPrevChild(false);
       
  1523                 } else {
       
  1524                     QFocusEvent event(QEvent::FocusIn, Qt::BacktabFocusReason);
       
  1525                     qApp->sendEvent(this, &event);
       
  1526                 }
       
  1527 
       
  1528 		break;
       
  1529 	    default:
       
  1530 		break;
       
  1531 	    }
       
  1532 	}
       
  1533     }
       
  1534 	break;
       
  1535     case XButtonPress:
       
  1536 	if (!d->clientIsXEmbed) {
       
  1537             setFocus(Qt::MouseFocusReason);
       
  1538             XAllowEvents(x11Info().display(), ReplayPointer, CurrentTime);
       
  1539             return true;
       
  1540 	}
       
  1541 	break;
       
  1542     case XButtonRelease:
       
  1543 	if (!d->clientIsXEmbed)
       
  1544             XAllowEvents(x11Info().display(), SyncPointer, CurrentTime);
       
  1545 	break;
       
  1546     default:
       
  1547 	break;
       
  1548     }
       
  1549 
       
  1550     return QWidget::x11Event(event);
       
  1551 }
       
  1552 
       
  1553 /*! \internal
       
  1554 
       
  1555     Whenever the container is resized, we need to resize our client.
       
  1556 */
       
  1557 void QX11EmbedContainer::resizeEvent(QResizeEvent *)
       
  1558 {
       
  1559     Q_D(QX11EmbedContainer);
       
  1560     if (d->client)
       
  1561 	XResizeWindow(x11Info().display(), d->client, width(), height());
       
  1562 }
       
  1563 
       
  1564 /*! \internal
       
  1565 
       
  1566     We use the QShowEvent to signal to our client that we want it to
       
  1567     map itself. We do this by changing its window property
       
  1568     XEMBED_INFO. The client will get an X11 PropertyNotify.
       
  1569 */
       
  1570 void QX11EmbedContainer::showEvent(QShowEvent *)
       
  1571 {
       
  1572     Q_D(QX11EmbedContainer);
       
  1573     if (d->client) {
       
  1574         long data[] = {XEMBED_VERSION, XEMBED_MAPPED};
       
  1575 	XChangeProperty(x11Info().display(), d->client, ATOM(_XEMBED_INFO), ATOM(_XEMBED_INFO), 32,
       
  1576 			PropModeReplace, (unsigned char *) data, 2);
       
  1577     }
       
  1578 }
       
  1579 
       
  1580 /*! \internal
       
  1581 
       
  1582     We use the QHideEvent to signal to our client that we want it to
       
  1583     unmap itself. We do this by changing its window property
       
  1584     XEMBED_INFO. The client will get an X11 PropertyNotify.
       
  1585 */
       
  1586 void QX11EmbedContainer::hideEvent(QHideEvent *)
       
  1587 {
       
  1588     Q_D(QX11EmbedContainer);
       
  1589     if (d->client) {
       
  1590         long data[] = {XEMBED_VERSION, XEMBED_MAPPED};
       
  1591 	XChangeProperty(x11Info().display(), d->client, ATOM(_XEMBED_INFO), ATOM(_XEMBED_INFO), 32,
       
  1592 			PropModeReplace, (unsigned char *) data, 2);
       
  1593     }
       
  1594 }
       
  1595 
       
  1596 /*!
       
  1597     \reimp
       
  1598 */
       
  1599 bool QX11EmbedContainer::event(QEvent *event)
       
  1600 {
       
  1601     if (event->type() == QEvent::ParentChange) {
       
  1602         XSelectInput(x11Info().display(), internalWinId(),
       
  1603                      KeyPressMask | KeyReleaseMask
       
  1604                      | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
       
  1605                      | KeymapStateMask
       
  1606                      | PointerMotionMask
       
  1607                      | EnterWindowMask | LeaveWindowMask
       
  1608                      | FocusChangeMask
       
  1609                      | ExposureMask
       
  1610                      | StructureNotifyMask
       
  1611                      | SubstructureNotifyMask);
       
  1612     }
       
  1613     return QWidget::event(event);
       
  1614 }
       
  1615 
       
  1616 /*! \internal
       
  1617 
       
  1618     Rejects a client window by reparenting it to the root window.  The
       
  1619     client will receive a reparentnotify, and will most likely assume
       
  1620     that the container has shut down. The XEmbed protocol does not
       
  1621     define any way to reject a client window, but this is a clean way
       
  1622     to do it.
       
  1623 */
       
  1624 void QX11EmbedContainerPrivate::rejectClient(WId window)
       
  1625 {
       
  1626     Q_Q(QX11EmbedContainer);
       
  1627     q->setEnabled(false);
       
  1628     XRemoveFromSaveSet(q->x11Info().display(), client);
       
  1629     XReparentWindow(q->x11Info().display(), window, q->x11Info().appRootWindow(), 0, 0);
       
  1630 }
       
  1631 
       
  1632 /*! \internal
       
  1633 
       
  1634     Accepts a client by mapping it, resizing it and optionally
       
  1635     activating and giving it logical focusing through XEMBED messages.
       
  1636 */
       
  1637 void QX11EmbedContainerPrivate::acceptClient(WId window)
       
  1638 {
       
  1639     Q_Q(QX11EmbedContainer);
       
  1640     client = window;
       
  1641     q->setEnabled(true);
       
  1642 
       
  1643     // This tells Qt that we wish to forward DnD messages to
       
  1644     // our client.
       
  1645     if (!extra)
       
  1646         createExtra();
       
  1647     extraData()->xDndProxy = client;
       
  1648 
       
  1649     unsigned int version = XEmbedVersion();
       
  1650 
       
  1651     Atom actual_type_return;
       
  1652     int actual_format_return;
       
  1653     unsigned long nitems_return = 0;
       
  1654     unsigned long bytes_after_return;
       
  1655     unsigned char *prop_return = 0;
       
  1656     unsigned int clientversion = 0;
       
  1657 
       
  1658     // Add this client to our saveset, so if we crash, the client window
       
  1659     // doesn't get destroyed. This is useful for containers that restart
       
  1660     // automatically after a crash, because it can simply reembed its clients
       
  1661     // without having to restart them (KDE panel).
       
  1662     XAddToSaveSet(q->x11Info().display(), client);
       
  1663 
       
  1664     // XEmbed clients have an _XEMBED_INFO property in which we can
       
  1665     // fetch the version
       
  1666     if (XGetWindowProperty(q->x11Info().display(), client, ATOM(_XEMBED_INFO), 0, 2, false,
       
  1667                            ATOM(_XEMBED_INFO), &actual_type_return, &actual_format_return,
       
  1668                            &nitems_return, &bytes_after_return, &prop_return) == Success) {
       
  1669 
       
  1670 	if (actual_type_return != None && actual_format_return != 0) {
       
  1671 	    // Clients with the _XEMBED_INFO property are XEMBED clients.
       
  1672 	    clientIsXEmbed = true;
       
  1673 
       
  1674 	    long *p = (long *)prop_return;
       
  1675 	    if (nitems_return >= 2)
       
  1676 		clientversion = (unsigned int)p[0];
       
  1677 	}
       
  1678 
       
  1679 	XFree(prop_return);
       
  1680     }
       
  1681 
       
  1682     // Store client window's original size and placement.
       
  1683     Window root;
       
  1684     int x_return, y_return;
       
  1685     unsigned int width_return, height_return, border_width_return, depth_return;
       
  1686     XGetGeometry(q->x11Info().display(), client, &root, &x_return, &y_return,
       
  1687 		 &width_return, &height_return, &border_width_return, &depth_return);
       
  1688     clientOriginalRect.setCoords(x_return, y_return,
       
  1689 				 x_return + width_return - 1,
       
  1690 				 y_return + height_return - 1);
       
  1691 
       
  1692     // Ask the client for its minimum size.
       
  1693     XSizeHints size;
       
  1694     long msize;
       
  1695     if (XGetWMNormalHints(q->x11Info().display(), client, &size, &msize) && (size.flags & PMinSize)) {
       
  1696 	wmMinimumSizeHint = QSize(size.min_width, size.min_height);
       
  1697         q->updateGeometry();
       
  1698     }
       
  1699 
       
  1700     // The container should set the data2 field to the lowest of its
       
  1701     // supported version number and that of the client (from
       
  1702     // _XEMBED_INFO property).
       
  1703     unsigned int minversion = version > clientversion ? clientversion : version;
       
  1704     sendXEmbedMessage(client, q->x11Info().display(), XEMBED_EMBEDDED_NOTIFY, q->internalWinId(), minversion);
       
  1705     XMapWindow(q->x11Info().display(), client);
       
  1706 
       
  1707     // Resize it, but no smaller than its minimum size hint.
       
  1708     XResizeWindow(q->x11Info().display(),
       
  1709                   client,
       
  1710                   qMax(q->width(), wmMinimumSizeHint.width()),
       
  1711                   qMax(q->height(), wmMinimumSizeHint.height()));
       
  1712     q->update();
       
  1713 
       
  1714     // Not mentioned in the protocol is that if the container
       
  1715     // is already active, the client must be activated to work
       
  1716     // properly.
       
  1717     if (q->window()->isActiveWindow())
       
  1718 	sendXEmbedMessage(client, q->x11Info().display(), XEMBED_WINDOW_ACTIVATE);
       
  1719 
       
  1720     // Also, if the container already has focus, then it must
       
  1721     // send a focus in message to its new client; otherwise we ask
       
  1722     // it to remove focus.
       
  1723     if (q->focusWidget() == q && q->hasFocus())
       
  1724 	sendXEmbedMessage(client, q->x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST);
       
  1725     else
       
  1726 	sendXEmbedMessage(client, q->x11Info().display(), XEMBED_FOCUS_OUT);
       
  1727 
       
  1728     if (!clientIsXEmbed) {
       
  1729         checkGrab();
       
  1730         if (q->hasFocus()) {
       
  1731             XSetInputFocus(q->x11Info().display(), client, XRevertToParent, x11Time());
       
  1732         }
       
  1733     } else {
       
  1734         if (!isEmbedded())
       
  1735             moveInputToProxy();
       
  1736     }
       
  1737 
       
  1738     emit q->clientIsEmbedded();
       
  1739 }
       
  1740 
       
  1741 /*! \internal
       
  1742 
       
  1743     Moves X11 keyboard input focus to the focusProxy, unless the focus
       
  1744     is there already. When X11 keyboard input focus is on the
       
  1745     focusProxy, which is a child of the container and a sibling of the
       
  1746     client, X11 keypresses and keyreleases will always go to the proxy
       
  1747     and not to the client.
       
  1748 */
       
  1749 void QX11EmbedContainerPrivate::moveInputToProxy()
       
  1750 {
       
  1751     Q_Q(QX11EmbedContainer);
       
  1752     // Following Owen Taylor's advice from the XEmbed specification to
       
  1753     // always use CurrentTime when no explicit user action is involved.
       
  1754     XSetInputFocus(q->x11Info().display(), focusProxy->internalWinId(), XRevertToParent, CurrentTime);
       
  1755 }
       
  1756 
       
  1757 /*! \internal
       
  1758 
       
  1759     Ask the window manager to give us a default minimum size.
       
  1760 */
       
  1761 QSize QX11EmbedContainer::minimumSizeHint() const
       
  1762 {
       
  1763     Q_D(const QX11EmbedContainer);
       
  1764     if (!d->client || !d->wmMinimumSizeHint.isValid())
       
  1765 	return QWidget::minimumSizeHint();
       
  1766     return d->wmMinimumSizeHint;
       
  1767 }
       
  1768 
       
  1769 /*! \internal
       
  1770 
       
  1771 */
       
  1772 void QX11EmbedContainerPrivate::checkGrab()
       
  1773 {
       
  1774     Q_Q(QX11EmbedContainer);
       
  1775     if (!clientIsXEmbed && q->isActiveWindow() && !q->hasFocus()) {
       
  1776         if (!xgrab) {
       
  1777             XGrabButton(q->x11Info().display(), AnyButton, AnyModifier, q->internalWinId(),
       
  1778                         true, ButtonPressMask, GrabModeSync, GrabModeAsync,
       
  1779                         None, None);
       
  1780         }
       
  1781         xgrab = true;
       
  1782     } else {
       
  1783 	if (xgrab)
       
  1784 	    XUngrabButton(q->x11Info().display(), AnyButton, AnyModifier, q->internalWinId());
       
  1785         xgrab = false;
       
  1786     }
       
  1787 }
       
  1788 
       
  1789 /*!
       
  1790     Detaches the client from the embedder. The client will appear as a
       
  1791     standalone window on the desktop.
       
  1792 */
       
  1793 void QX11EmbedContainer::discardClient()
       
  1794 {
       
  1795     Q_D(QX11EmbedContainer);
       
  1796     if (d->client) {
       
  1797 	XResizeWindow(x11Info().display(), d->client, d->clientOriginalRect.width(),
       
  1798 		      d->clientOriginalRect.height());
       
  1799 
       
  1800 	d->rejectClient(d->client);
       
  1801     }
       
  1802 }
       
  1803 
       
  1804 QT_END_NAMESPACE