src/gui/kernel/qx11embed_x11.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtGui module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "qx11embed_x11.h"
00025 #include <qapplication.h>
00026 #include <qevent.h>
00027 #include <qpainter.h>
00028 #include <qlayout.h>
00029 #include <qstyle.h>
00030 #include <qstyleoption.h>
00031 #include <qdatetime.h>
00032 #include <qpointer.h>
00033 #include <qdebug.h>
00034 #include <qx11info_x11.h>
00035 #include <private/qt_x11_p.h>
00036 #include <private/qwidget_p.h>
00037 
00038 #define XK_MISCELLANY
00039 #define XK_LATIN1
00040 #define None 0
00041 #include <X11/Xlib.h>
00042 #include <X11/Xatom.h>
00043 #include <X11/Xutil.h>
00044 #include <X11/keysymdef.h>
00045 #include <X11/X.h>
00046 
00047 #ifndef XK_ISO_Left_Tab
00048 #define XK_ISO_Left_Tab 0xFE20
00049 #endif
00050 
00246 const int XButtonPress = ButtonPress;
00247 const int XButtonRelease = ButtonRelease;
00248 #undef ButtonPress
00249 #undef ButtonRelease
00250 
00251 // This is a hack to move topData() out from QWidgetPrivate to public.  We
00252 // need to to inspect window()'s embedded state.
00253 class QHackWidget : public QWidget
00254 {
00255     Q_DECLARE_PRIVATE(QWidget)
00256 public:
00257     QTLWExtra* topData() { return d_func()->topData(); }
00258 };
00259 
00260 static unsigned int XEMBED_VERSION = 0;
00261 
00262 static Atom _XEMBED = None;
00263 static Atom _XEMBED_INFO = None;
00264 
00265 enum QX11EmbedMessageType {
00266     XEMBED_EMBEDDED_NOTIFY = 0,
00267     XEMBED_WINDOW_ACTIVATE = 1,
00268     XEMBED_WINDOW_DEACTIVATE = 2,
00269     XEMBED_REQUEST_FOCUS = 3,
00270     XEMBED_FOCUS_IN = 4,
00271     XEMBED_FOCUS_OUT = 5,
00272     XEMBED_FOCUS_NEXT = 6,
00273     XEMBED_FOCUS_PREV = 7,
00274     XEMBED_MODALITY_ON = 10,
00275     XEMBED_MODALITY_OFF = 11,
00276     XEMBED_REGISTER_ACCELERATOR = 12,
00277     XEMBED_UNREGISTER_ACCELERATOR = 13,
00278     XEMBED_ACTIVATE_ACCELERATOR = 14
00279 };
00280 
00281 enum QX11EmbedFocusInDetail {
00282     XEMBED_FOCUS_CURRENT = 0,
00283     XEMBED_FOCUS_FIRST = 1,
00284     XEMBED_FOCUS_LAST = 2
00285 };
00286 
00287 enum QX11EmbedFocusInFlags {
00288     XEMBED_FOCUS_OTHER = (0 << 0),
00289     XEMBED_FOCUS_WRAPAROUND = (1 << 0)
00290 };
00291 
00292 enum QX11EmbedInfoFlags {
00293     XEMBED_MAPPED = (1 << 0)
00294 };
00295 
00296 enum QX11EmbedAccelModifiers {
00297     XEMBED_MODIFIER_SHIFT = (1 << 0),
00298     XEMBED_MODIFIER_CONTROL = (1 << 1),
00299     XEMBED_MODIFIER_ALT = (1 << 2),
00300     XEMBED_MODIFIER_SUPER = (1 << 3),
00301     XEMBED_MODIFIER_HYPER = (1 << 4)
00302 };
00303 
00304 enum QX11EmbedAccelFlags {
00305     XEMBED_ACCELERATOR_OVERLOADED = (1 << 0)
00306 };
00307 
00308 // Silence the default X11 error handler.
00309 static int x11ErrorHandler(Display *, XErrorEvent *)
00310 {
00311     return 0;
00312 }
00313 
00314 // Initializes X11 atoms
00315 static void initXEmbedAtoms(Display *d)
00316 {
00317     if (_XEMBED == None)
00318         _XEMBED = XInternAtom(d, "_XEMBED", false);
00319 
00320     if (_XEMBED_INFO == None)
00321         _XEMBED_INFO = XInternAtom(d, "_XEMBED_INFO", false);
00322 }
00323 
00324 // Returns the X11 timestamp. Maintained mainly by qapplication
00325 // internals, but also updated by the XEmbed widgets.
00326 static Time x11Time()
00327 {
00328     return qt_x11Data->time;
00329 }
00330 
00331 // Gives the version and flags of the supported XEmbed protocol.
00332 static unsigned int XEmbedVersion()
00333 {
00334     return 0;
00335 }
00336 
00337 // Sends an XEmbed message.
00338 static void sendXEmbedMessage(WId window, Display *display, long message,
00339                   long detail = 0, long data1 = 0, long data2 = 0)
00340 {
00341     XClientMessageEvent c;
00342     memset(&c, 0, sizeof(c));
00343     c.type = ClientMessage;
00344     c.message_type = _XEMBED;
00345     c.format = 32;
00346     c.display = display;
00347     c.window = window;
00348 
00349     c.data.l[0] = x11Time();
00350     c.data.l[1] = message;
00351     c.data.l[2] = detail;
00352     c.data.l[3] = data1;
00353     c.data.l[4] = data2;
00354 
00355     XSendEvent(display, window, false, NoEventMask, (XEvent *) &c);
00356 }
00357 
00358 // From qapplication_x11.cpp
00359 static XKeyEvent lastKeyEvent;
00360 
00361 static QCoreApplication::EventFilter oldX11EventFilter;
00362 
00363 // The purpose of this global x11 filter is for one to capture the key
00364 // events in their original state, but most importantly this is the
00365 // only way to get the WM_TAKE_FOCUS message from WM_PROTOCOLS.
00366 static bool x11EventFilter(void *message, long *result)
00367 {
00368     XEvent *event = reinterpret_cast<XEvent *>(message);
00369     if (event->type == XKeyPress || event->type == XKeyRelease)
00370   lastKeyEvent = event->xkey;
00371 
00372     // Update qt_x_time when a focusin is received. If the widget that
00373     // receives this event is active, send a WindowActivate
00374     // event. This will cause that widget to call XSetInputFocus
00375     // immediately, in which case the timestamp will be correct.
00376     if (event->type == ClientMessage && event->xclient.message_type == ATOM(WM_PROTOCOLS)) {
00377   QWidget *w = QWidget::find(event->xclient.window);
00378   if (w) {
00379       Atom a = event->xclient.data.l[0];
00380       if (a == ATOM(WM_TAKE_FOCUS)) {
00381     if ((ulong) event->xclient.data.l[1] > X11->time )
00382         X11->time = event->xclient.data.l[1];
00383 
00384     if (w->isActiveWindow()) {
00385         QEvent e(QEvent::WindowActivate);
00386         QApplication::sendEvent(w, &e);
00387     }
00388       }
00389   }
00390     }
00391 
00392     if (oldX11EventFilter && oldX11EventFilter != &x11EventFilter)
00393   return oldX11EventFilter(message, result);
00394     else
00395   return false;
00396 }
00397 
00398 class QX11EmbedWidgetPrivate : public QWidgetPrivate
00399 {
00400     Q_DECLARE_PUBLIC(QX11EmbedWidget)
00401 public:
00402     inline QX11EmbedWidgetPrivate()
00403     {
00404         container = 0;
00405     }
00406 
00407     void setEmbedded();
00408 
00409     void emitError(QX11EmbedWidget::Error error) {
00410         Q_Q(QX11EmbedWidget);
00411 
00412         lastError = error;
00413         emit q->error(error);
00414     }
00415 
00416     enum FocusWidgets {
00417         FirstFocusWidget,
00418         LastFocusWidget
00419     };
00420 
00421     int focusOriginator;
00422     QWidget *getFocusWidget(FocusWidgets fw);
00423     void checkActivateWindow(QObject *o);
00424     QX11EmbedWidget *xEmbedWidget(QObject *o) const;
00425     void clearFocus();
00426 
00427     WId container;
00428     QPointer<QWidget> currentFocus;
00429 
00430     QX11EmbedWidget::Error lastError;
00431 
00432 };
00433 
00437 QX11EmbedWidget::QX11EmbedWidget(QWidget *parent)
00438     : QWidget(*new QX11EmbedWidgetPrivate, parent, 0)
00439 {
00440     XSetErrorHandler(x11ErrorHandler);
00441     initXEmbedAtoms(x11Info().display());
00442 
00443     createWinId();
00444     XSelectInput(x11Info().display(), internalWinId(),
00445                  KeyPressMask | KeyReleaseMask | ButtonPressMask
00446                     | ButtonReleaseMask
00447                     | KeymapStateMask | ButtonMotionMask | PointerMotionMask
00448                     | FocusChangeMask
00449                     | ExposureMask | StructureNotifyMask
00450                     | SubstructureNotifyMask | PropertyChangeMask);
00451 
00452     unsigned int data[] = {XEMBED_VERSION, XEMBED_MAPPED};
00453     XChangeProperty(x11Info().display(), internalWinId(), _XEMBED_INFO,
00454                     XA_CARDINAL, 32, PropModeReplace,
00455                     (unsigned char*) data, 2);
00456 
00457     setFocusPolicy(Qt::StrongFocus);
00458     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00459     QApplication::instance()->installEventFilter(this);
00460 }
00461 
00467 QX11EmbedWidget::~QX11EmbedWidget()
00468 {
00469     Q_D(QX11EmbedWidget);
00470     if (d->container) {
00471         XUnmapWindow(x11Info().display(), internalWinId());
00472         XReparentWindow(x11Info().display(), internalWinId(), x11Info().appRootWindow(), 0, 0);
00473     }
00474 }
00475 
00476 QX11EmbedWidget::Error QX11EmbedWidget::error() const {
00477     return d_func()->lastError;
00478 }
00479 
00487 void QX11EmbedWidget::embedInto(WId id)
00488 {
00489     Q_D(QX11EmbedWidget);
00490     d->container = id;
00491     switch (XReparentWindow(x11Info().display(), internalWinId(), d->container, 0, 0)) {
00492     case BadWindow:
00493         d->emitError(InvalidWindowID);
00494         break;
00495     case BadMatch:
00496         d->emitError(Internal);
00497         break;
00498     case Success:
00499     default:
00500         break;
00501     }
00502     QTLWExtra* x = d->extra ? d->extra->topextra : 0;
00503     if (x)
00504         x->frameStrut.setCoords(0, 0, 0, 0);
00505     d->data.fstrut_dirty = false;
00506 }
00507 
00512 QWidget *QX11EmbedWidgetPrivate::getFocusWidget(FocusWidgets fw)
00513 {
00514     Q_Q(QX11EmbedWidget);
00515     QWidget *tlw = q;
00516     QWidget *w = tlw->nextInFocusChain();
00517 
00518     QWidget *last = tlw;
00519 
00520     extern bool qt_tab_all_widgets;
00521     uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus;
00522 
00523     while (w != tlw)
00524     {
00525         if (((w->focusPolicy() & focus_flag) == focus_flag)
00526             && w->isVisibleTo(q) && w->isEnabled())
00527         {
00528             last = w;
00529             if (fw == FirstFocusWidget)
00530                 break;
00531         }
00532         w = w->nextInFocusChain();
00533     }
00534 
00535     return last;
00536 }
00537 
00542 QX11EmbedWidget *QX11EmbedWidgetPrivate::xEmbedWidget(QObject *o) const
00543 {
00544     QX11EmbedWidget *xec = 0;
00545 
00546     // Check the widget itself, then its parents, and find the first
00547     // QX11EmbedWidget.
00548     do {
00549         if ((xec = qobject_cast<QX11EmbedWidget *>(o)))
00550             return xec;
00551     } while ((o = o->parent()));
00552     return 0;
00553 }
00554 
00559 void QX11EmbedWidgetPrivate::checkActivateWindow(QObject *o)
00560 {
00561     Q_Q(QX11EmbedWidget);
00562     QX11EmbedWidget *xec = xEmbedWidget(o);
00563 
00564     // check if we are in the right xembed client
00565     if (q != xec)
00566         return;
00567 
00568     QWidget *w = qobject_cast<QWidget *>(o);
00569 
00570     // if it is no active window, then don't do the change
00571     if (!(w && qApp->activeWindow()))
00572         return;
00573 
00574     // if it already is the active window, don't do anything
00575     if (w->window() != qApp->activeWindow())
00576     {
00577         qApp->setActiveWindow(w->window());
00578         currentFocus = w;
00579 
00580         sendXEmbedMessage(xec->containerWinId(), q->x11Info().display(), XEMBED_REQUEST_FOCUS);
00581     }
00582 }
00583 
00588 void QX11EmbedWidgetPrivate::clearFocus()
00589 {
00590     Q_Q(QX11EmbedWidget);
00591     // Setting focus on the client itself removes Qt's
00592     // logical focus rectangle. We can't just do a
00593     // clearFocus here, because when we send the synthetic
00594     // FocusIn to ourselves on activation, Qt will set
00595     // focus on focusWidget() again. This way, we "hide"
00596     // focus rather than clearing it.
00597 
00598     if (!q->window()->hasFocus())
00599         q->window()->setFocus(Qt::OtherFocusReason);
00600 
00601     currentFocus = 0;
00602 }
00603 
00608 void QX11EmbedWidgetPrivate::setEmbedded()
00609 {
00610     Q_Q(QX11EmbedWidget);
00611     ((QHackWidget *)q->window())->topData()->embedded = 1;
00612 }
00613 
00618 bool QX11EmbedWidget::eventFilter(QObject *o, QEvent *event)
00619 {
00620     Q_D(QX11EmbedWidget);
00621     switch (event->type()) {
00622     case QEvent::FocusIn:
00623         switch (((QFocusEvent *)event)->reason()) {
00624         case Qt::MouseFocusReason:
00625             // If the user clicks into one of the client widget's
00626             // children and we didn't have focus already, we request
00627             // focus from our container.
00628             if (d->xEmbedWidget(o) == this) {
00629                 if (d->currentFocus.isNull())
00630                     sendXEmbedMessage(d->container, x11Info().display(), XEMBED_REQUEST_FOCUS);
00631 
00632                 d->currentFocus = qobject_cast<QWidget *>(o);
00633             }
00634             break;
00635         case Qt::TabFocusReason:
00636             // If the xembed client receives a focus event because of
00637             // a Tab, then we are at the end of our focus chain and we
00638             // ask the container to move to its next focus widget.
00639             if (o == this) {
00640                 d->clearFocus();
00641                 sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_NEXT);
00642                 return true;
00643             } else {
00644                 // We're listening on events from qApp, so in order
00645                 // for us to know who to set focus on if we receive an
00646                 // activation event, we note the widget that got the
00647                 // focusin last.
00648                 if (d->xEmbedWidget(o) == this)
00649                     d->currentFocus = qobject_cast<QWidget *>(o);
00650             }
00651             break;
00652         case Qt::BacktabFocusReason:
00653             // If the window receives a focus event because of
00654             // a Backtab, then we are at the start of our focus chain
00655             // and we ask the container to move to its previous focus
00656             // widget.
00657             if (o == this) {
00658                 // See comment for Tab.
00659                 // If we receive a XEMBED_FOCUS_IN
00660                 // XEMBED_FOCUS_CURRENT, we will set focus in
00661                 // currentFocus. To avoid that in this case, we reset
00662                 // currentFocus.
00663                 d->clearFocus();
00664                 sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_PREV);
00665                 return true;
00666             } else {
00667                 if (d->xEmbedWidget(o) == this)
00668                     d->currentFocus = qobject_cast<QWidget *>(o);
00669             }
00670             break;
00671         case Qt::ActiveWindowFocusReason:
00672             if (!d->currentFocus.isNull()) {
00673                 if (!d->currentFocus->hasFocus())
00674                     d->currentFocus->setFocus(Qt::OtherFocusReason);
00675             } else {
00676                 d->clearFocus();
00677                 return true;
00678             }
00679 
00680             break;
00681         case Qt::PopupFocusReason:
00682         case Qt::ShortcutFocusReason:
00683         case Qt::OtherFocusReason:
00684             // If focus is received to any child widget because of any
00685             // other reason, remember the widget so that we can give
00686             // it focus again if we're activated.
00687             if (d->xEmbedWidget(o) == this) {
00688                d->currentFocus = qobject_cast<QWidget *>(o);
00689             }
00690             break;
00691         default:
00692             break;
00693         }
00694         break;
00695     case QEvent::MouseButtonPress:
00696         // If we get a mouse button press event inside a embedded widget
00697         // make sure this is the active window in qapp.
00698         d->checkActivateWindow(o);
00699         break;
00700     default:
00701         break;
00702     }
00703 
00704     return QWidget::eventFilter(o, event);
00705 }
00706 
00712 bool QX11EmbedWidget::x11Event(XEvent *event)
00713 {
00714     Q_D(QX11EmbedWidget);
00715     switch (event->type) {
00716     case DestroyNotify:
00717         // If the container window is destroyed, we signal this to the user.
00718         emit containerClosed();
00719         break;
00720     case ReparentNotify:
00721         // If the container shuts down, we will be reparented to the
00722         // root window. We must also consider the case that we may be
00723         // reparented from one container to another.
00724         if (event->xreparent.parent == x11Info().appRootWindow()) {
00725             emit containerClosed();
00726             return true;
00727         } else {
00728             d->container = event->xreparent.parent;
00729         }
00730         break;
00731     case UnmapNotify:
00732         // Mapping and unmapping are handled by changes to the
00733         // _XEMBED_INFO property. Any default map/unmap requests are
00734         // ignored.
00735         return true;
00736     case PropertyNotify:
00737         // The container sends us map/unmap messages through the
00738         // _XEMBED_INFO property. We adhere to the XEMBED_MAPPED bit in
00739         // data2.
00740         if (event->xproperty.atom == _XEMBED_INFO) {
00741             Atom actual_type_return;
00742             int actual_format_return;
00743             unsigned long nitems_return;
00744             unsigned long bytes_after_return;
00745             unsigned char *prop_return = 0;
00746             if (XGetWindowProperty(x11Info().display(), internalWinId(), _XEMBED_INFO, 0, 2,
00747                                    false, XA_CARDINAL, &actual_type_return,
00748                                    &actual_format_return, &nitems_return,
00749                                    &bytes_after_return, &prop_return) == Success) {
00750                 if (nitems_return > 1) {
00751                     if (((int * )prop_return)[1] & XEMBED_MAPPED) {
00752                         XMapWindow(x11Info().display(), internalWinId());
00753                     } else {
00754                         XUnmapWindow(x11Info().display(), internalWinId());
00755                     }
00756                 }
00757             }
00758         }
00759 
00760         break;
00761     case ClientMessage:
00762         // XEMBED messages have message_type _XEMBED
00763         if (event->xclient.message_type == _XEMBED) {
00764             // Discard XEMBED messages not to ourselves. (### dead code?)
00765             if (event->xclient.window != internalWinId())
00766                 break;
00767 
00768             // Update qt_x_time if necessary
00769             Time msgtime = (Time) event->xclient.data.l[0];
00770             if (msgtime > X11->time)
00771                 X11->time = msgtime;
00772 
00773             switch (event->xclient.data.l[1]) {
00774             case XEMBED_WINDOW_ACTIVATE: {
00775                 // When we receive an XEMBED_WINDOW_ACTIVATE, we need
00776                 // to send ourselves a synthetic FocusIn X11 event for
00777                 // Qt to activate us.
00778                 XEvent ev;
00779                 memset(&ev, 0, sizeof(ev));
00780                 ev.xfocus.display = x11Info().display();
00781                 ev.xfocus.type = XFocusIn;
00782                 ev.xfocus.window = internalWinId();
00783                 ev.xfocus.mode = NotifyNormal;
00784                 ev.xfocus.detail = NotifyNonlinear;
00785                 ((QApplication *)QApplication::instance())->x11ProcessEvent(&ev);
00786             }
00787                 break;
00788             case XEMBED_WINDOW_DEACTIVATE: {
00789                 // When we receive an XEMBED_WINDOW_DEACTIVATE, we
00790                 // need to send ourselves a synthetic FocusOut event
00791                 // for Qt to deativate us.
00792                 XEvent ev;
00793                 memset(&ev, 0, sizeof(ev));
00794                 ev.xfocus.display = x11Info().display();
00795                 ev.xfocus.type = XFocusOut;
00796                 ev.xfocus.window = internalWinId();
00797                 ev.xfocus.mode = NotifyNormal;
00798                 ev.xfocus.detail = NotifyNonlinear;
00799                 ((QApplication *)QApplication::instance())->x11ProcessEvent(&ev);
00800             }
00801                 break;
00802             case XEMBED_EMBEDDED_NOTIFY: {
00803                 // In this message's l[2] we have the max version
00804                 // supported by both the client and the
00805                 // container. QX11EmbedWidget does not use this field.
00806 
00807                 // We have been embedded, so we set our
00808                 // client's embedded flag.
00809                 d->setEmbedded();
00810                 emit embedded();
00811             }
00812                 break;
00813             case XEMBED_FOCUS_IN:
00814                 // in case we embed more than one topLevel window inside the same
00815                 // host window.
00816                 if (window() != qApp->activeWindow())
00817                     qApp->setActiveWindow(this);
00818 
00819                 switch (event->xclient.data.l[2]) {
00820                 case XEMBED_FOCUS_CURRENT:
00821                     // The container sends us this message if it wants
00822                     // us to focus on the widget that last had focus.
00823                     // This is the reply when XEMBED_REQUEST_FOCUS is
00824                     // sent to the container.
00825                     if (!d->currentFocus.isNull()) {
00826                         if (!d->currentFocus->hasFocus())
00827                             d->currentFocus->setFocus(Qt::OtherFocusReason);
00828                     } else {
00829                         // No widget currently has focus. We set focus
00830                         // on the first widget next to the
00831                         // client widget. Since the setFocus will not work
00832                         // if the window is disabled, set the currentFocus
00833                         // directly so that it's set on window activate.
00834                         d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::FirstFocusWidget);
00835                         d->currentFocus->setFocus(Qt::OtherFocusReason);
00836                     }
00837                     break;
00838                 case XEMBED_FOCUS_FIRST:
00839                     // The container sends this message when it wants
00840                     // us to focus on the first widget in our focus
00841                     // chain (typically because of a tab).
00842                     d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::FirstFocusWidget);
00843                     d->currentFocus->setFocus(Qt::TabFocusReason);
00844                     break;
00845                 case XEMBED_FOCUS_LAST:
00846                     // The container sends this message when it wants
00847                     // us to focus on the last widget in our focus
00848                     // chain (typically because of a backtab).
00849                     d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::LastFocusWidget);
00850                     d->currentFocus->setFocus(Qt::BacktabFocusReason);
00851                     break;
00852                 default:
00853                     // Ignore any other XEMBED_FOCUS_IN details.
00854                     break;
00855                 }
00856                 break;
00857             case XEMBED_FOCUS_OUT:
00858                 // The container sends us this message when it wants us
00859                 // to lose focus and forget about the widget that last
00860                 // had focus. Typically sent by the container when it
00861                 // loses focus because of mouse or tab activity. We do
00862                 // then not want to set focus on anything if we're
00863                 // activated.
00864                 d->clearFocus();
00865 
00866                 break;
00867             default:
00868                 // Ignore any other XEMBED messages.
00869                 break;
00870             };
00871         } else {
00872             // Non-XEMBED client messages are not interesting.
00873         }
00874 
00875         break;
00876     default:
00877         // Ignore all other x11 events.
00878         break;
00879     }
00880 
00881     // Allow default handling.
00882     return QWidget::x11Event(event);
00883 }
00884 
00888 bool QX11EmbedWidget::event(QEvent *event)
00889 {
00890     if (event->type() == QEvent::ParentChange) {
00891         XSelectInput(x11Info().display(), internalWinId(),
00892                      KeyPressMask | KeyReleaseMask | ButtonPressMask
00893                      | ButtonReleaseMask
00894                      | KeymapStateMask | ButtonMotionMask | PointerMotionMask
00895                      | FocusChangeMask
00896                      | ExposureMask | StructureNotifyMask
00897                      | SubstructureNotifyMask | PropertyChangeMask);
00898     }
00899     return QWidget::event(event);
00900 }
00901 
00905 void QX11EmbedWidget::resizeEvent(QResizeEvent *event)
00906 {
00907     if (layout())
00908         layout()->update();
00909     QWidget::resizeEvent(event);
00910 }
00911 
00916 WId QX11EmbedWidget::containerWinId() const
00917 {
00918     Q_D(const QX11EmbedWidget);
00919     return d->container;
00920 }
00921 
00922 class QX11EmbedContainerPrivate : public QWidgetPrivate
00923 {
00924     Q_DECLARE_PUBLIC(QX11EmbedContainer)
00925 public:
00926     inline QX11EmbedContainerPrivate()
00927     {
00928         client = 0;
00929         focusProxy = 0;
00930         clientIsXEmbed = false;
00931     }
00932 
00933     bool isEmbedded() const;
00934     void moveInputToProxy();
00935 
00936     void acceptClient(WId window);
00937     void rejectClient(WId window);
00938 
00939     void checkGrab();
00940 
00941     WId topLevelParentWinId() const;
00942 
00943     void emitError(QX11EmbedContainer::Error error) {
00944         Q_Q(QX11EmbedContainer);
00945         lastError = error;
00946         emit q->error(error);
00947     }
00948 
00949     WId client;
00950     QWidget *focusProxy;
00951     bool clientIsXEmbed;
00952     bool xgrab;
00953     QRect clientOriginalRect;
00954     QSize wmMinimumSizeHint;
00955 
00956     QX11EmbedContainer::Error lastError;
00957 };
00958 
00962 QX11EmbedContainer::QX11EmbedContainer(QWidget *parent)
00963     : QWidget(*new QX11EmbedContainerPrivate, parent, 0)
00964 {
00965     Q_D(QX11EmbedContainer);
00966     XSetErrorHandler(x11ErrorHandler);
00967     initXEmbedAtoms(x11Info().display());
00968 
00969     createWinId();
00970 
00971     setFocusPolicy(Qt::StrongFocus);
00972     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00973     // ### PORT setKeyCompression(false);
00974     setAcceptDrops(true);
00975     setEnabled(false);
00976 
00977     // Everybody gets a focus proxy, but only one toplevel container's
00978     // focus proxy is actually in use.
00979     d->focusProxy = new QWidget(this);
00980     d->focusProxy->setGeometry(-1, -1, 1, 1);
00981 
00982     // We need events from the window (activation status) and
00983     // from qApp (keypress/release).
00984     qApp->installEventFilter(this);
00985     window()->installEventFilter(this);
00986 
00987     // Install X11 event filter.
00988     if (!oldX11EventFilter)
00989   oldX11EventFilter = QCoreApplication::instance()->setEventFilter(x11EventFilter);
00990 
00991     XSelectInput(x11Info().display(), internalWinId(),
00992                  KeyPressMask | KeyReleaseMask
00993                  | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
00994                  | KeymapStateMask
00995                  | PointerMotionMask
00996                  | EnterWindowMask | LeaveWindowMask
00997                  | FocusChangeMask
00998                  | ExposureMask
00999                  | StructureNotifyMask
01000                  | SubstructureNotifyMask);
01001 
01002     // Move input to our focusProxy if this widget is active, and not
01003     // shaded by a modal dialog (in which case isActiveWindow() would
01004     // still return true, but where we must not move input focus).
01005     if (qApp->activeWindow() == window() && !d->isEmbedded())
01006   d->moveInputToProxy();
01007 }
01008 
01012 QX11EmbedContainer::~QX11EmbedContainer()
01013 {
01014     Q_D(QX11EmbedContainer);
01015     if (d->client) {
01016   XUnmapWindow(x11Info().display(), d->client);
01017   XReparentWindow(x11Info().display(), d->client, x11Info().appRootWindow(), 0, 0);
01018     }
01019 
01020     if (d->xgrab)
01021   XUngrabButton(x11Info().display(), AnyButton, AnyModifier, internalWinId());
01022 }
01023 
01024 
01025 QX11EmbedContainer::Error QX11EmbedContainer::error() const {
01026     return d_func()->lastError;
01027 }
01028 
01029 
01032 void QX11EmbedContainer::paintEvent(QPaintEvent *)
01033 {
01034 }
01035 
01040 bool QX11EmbedContainerPrivate::isEmbedded() const
01041 {
01042     Q_Q(const QX11EmbedContainer);
01043     return ((QHackWidget *)q->window())->topData()->embedded == 1;
01044 }
01045 
01050 WId QX11EmbedContainerPrivate::topLevelParentWinId() const
01051 {
01052     Q_Q(const QX11EmbedContainer);
01053     return ((QHackWidget *)q->window())->topData()->parentWinId;
01054 }
01055 
01060 WId QX11EmbedContainer::clientWinId() const
01061 {
01062     Q_D(const QX11EmbedContainer);
01063     return d->client;
01064 }
01065 
01077 void QX11EmbedContainer::embedClient(WId id)
01078 {
01079     Q_D(QX11EmbedContainer);
01080 
01081     if (id == 0) {
01082   d->emitError(InvalidWindowID);
01083   return;
01084     }
01085 
01086     // Walk up the tree of parent windows to prevent embedding of ancestors.
01087     WId thisId = internalWinId();
01088     Window rootReturn;
01089     Window parentReturn;
01090     Window *childrenReturn = 0;
01091     unsigned int nchildrenReturn;
01092     do {
01093         if (XQueryTree(x11Info().display(), thisId, &rootReturn,
01094                        &parentReturn, &childrenReturn, &nchildrenReturn) == 0) {
01095       d->emitError(InvalidWindowID);
01096       return;
01097         }
01098         if (childrenReturn) {
01099             XFree(childrenReturn);
01100             childrenReturn = 0;
01101         }
01102 
01103         thisId = parentReturn;
01104         if (id == thisId) {
01105       d->emitError(InvalidWindowID);
01106       return;
01107         }
01108     } while (thisId != rootReturn);
01109 
01110     // watch for property notify events (see below)
01111     XGrabServer(x11Info().display());
01112     XWindowAttributes attrib;
01113     if (!XGetWindowAttributes(x11Info().display(), id, &attrib)) {
01114   d->emitError(InvalidWindowID);
01115   return;
01116     }
01117     XSelectInput(x11Info().display(), id, attrib.your_event_mask | PropertyChangeMask);
01118     XUngrabServer(x11Info().display());
01119 
01120     // Put the window into WithdrawnState
01121     XUnmapWindow(x11Info().display(), id);
01122     XSync(x11Info().display(), False); // make sure the window is hidden
01123 
01124     /*
01125       Wait for notification from the window manager that the window is
01126       not in withdrawn state.  According to the ICCCM section 4.1.3.1,
01127       we should wait for the WM_STATE property to either be deleted or
01128       set to WithdrawnState.
01129 
01130       For safety, we will not wait more than 500 ms, so that we can
01131       preemptively workaround buggy window managers.
01132     */
01133     QTime t;
01134     t.start();
01135     for (;;) {
01136   if (t.elapsed() > 500) // time-out after 500 ms
01137       break;
01138 
01139   XEvent event;
01140   if (!XCheckTypedWindowEvent(x11Info().display(), id, PropertyNotify, &event)) {
01141       XSync(x11Info().display(), False);
01142       continue;
01143   }
01144   if (event.xproperty.atom != ATOM(WM_STATE)) {
01145       qApp->x11ProcessEvent(&event);
01146       continue;
01147   }
01148 
01149   if (event.xproperty.state == PropertyDelete)
01150       break;
01151 
01152   Atom ret;
01153   int format, status;
01154   long *state;
01155   unsigned long nitems, after;
01156   status = XGetWindowProperty(x11Info().display(), id, ATOM(WM_STATE), 0, 2, False, ATOM(WM_STATE),
01157             &ret, &format, &nitems, &after, (unsigned char **) &state );
01158   if (status == Success && ret == ATOM(WM_STATE) && format == 32 && nitems > 0) {
01159       if (state[0] == WithdrawnState)
01160     break;
01161   }
01162     }
01163 
01164     // restore the event mask
01165     XSelectInput(x11Info().display(), id, attrib.your_event_mask);
01166 
01167     switch (XReparentWindow(x11Info().display(), id, internalWinId(), 0, 0)) {
01168     case BadWindow:
01169     case BadMatch:
01170   d->emitError(InvalidWindowID);
01171   break;
01172     default:
01173   break;
01174     }
01175 }
01176 
01181 bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event)
01182 {
01183     Q_D(QX11EmbedContainer);
01184     switch (event->type()) {
01185     case QEvent::KeyPress:
01186         // Forward any keypresses to our client.
01187   if (o == this && d->client) {
01188       lastKeyEvent.window = d->client;
01189       XSendEvent(x11Info().display(), d->client, false, KeyPressMask, (XEvent *) &lastKeyEvent);
01190       return true;
01191   }
01192   break;
01193     case QEvent::KeyRelease:
01194   // Forward any keyreleases to our client.
01195   if (o == this && d->client) {
01196       lastKeyEvent.window = d->client;
01197       XSendEvent(x11Info().display(), d->client, false, KeyReleaseMask, (XEvent *) &lastKeyEvent);
01198       return true;
01199   }
01200   break;
01201 
01202     case QEvent::WindowActivate:
01203   // When our container window is activated, we pass the
01204   // activation message on to our client. Note that X input
01205   // focus is set to our focus proxy. We want to intercept all
01206   // keypresses.
01207   if (o == window() && d->client) {
01208             if (!d->isEmbedded())
01209                 d->moveInputToProxy();
01210 
01211       if (d->clientIsXEmbed) {
01212     sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_ACTIVATE);
01213             } else {
01214     d->checkGrab();
01215                 if (hasFocus())
01216                     XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
01217             }
01218   }
01219   break;
01220     case QEvent::WindowDeactivate:
01221   // When our container window is deactivated, we pass the
01222   // deactivation message to our client.
01223   if (o == window() && d->client) {
01224       if (d->clientIsXEmbed)
01225     sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_DEACTIVATE);
01226       else
01227     d->checkGrab();
01228   }
01229   break;
01230     case QEvent::FocusIn:
01231         // When receiving FocusIn events generated by Tab or Backtab,
01232   // we pass focus on to our client. Any mouse activity is sent
01233   // directly to the client, and it will ask us for focus with
01234   // XEMBED_REQUEST_FOCUS.
01235   if (o == this && d->client) {
01236       if (d->clientIsXEmbed) {
01237                 if (!d->isEmbedded())
01238                     d->moveInputToProxy();
01239 
01240     QFocusEvent *fe = (QFocusEvent *)event;
01241     switch (fe->reason()) {
01242     case Qt::TabFocusReason:
01243         sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST);
01244         break;
01245     case Qt::BacktabFocusReason:
01246         sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_LAST);
01247         break;
01248     default:
01249         break;
01250     }
01251       } else {
01252     d->checkGrab();
01253                 XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
01254       }
01255   }
01256 
01257   break;
01258     case QEvent::FocusOut: {
01259   // When receiving a FocusOut, we ask our client to remove its
01260   // focus.
01261   if (o == this && d->client) {
01262             if (!d->isEmbedded())
01263                 d->moveInputToProxy();
01264 
01265       if (d->clientIsXEmbed) {
01266     QFocusEvent *fe = (QFocusEvent *)event;
01267     if (o == this && d->client && fe->reason() != Qt::ActiveWindowFocusReason)
01268         sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_OUT);
01269       } else {
01270     d->checkGrab();
01271       }
01272   }
01273     }
01274   break;
01275 
01276     case QEvent::Close: {
01277   if (o == this && d->client) {
01278       // Unmap the client and reparent it to the root window.
01279       // Wait until the messages have been processed. Then ask
01280       // the window manager to delete the window.
01281       XUnmapWindow(x11Info().display(), d->client);
01282       XReparentWindow(x11Info().display(), d->client, x11Info().appRootWindow(), 0, 0);
01283       XSync(x11Info().display(), false);
01284 
01285       XEvent ev;
01286       memset(&ev, 0, sizeof(ev));
01287       ev.xclient.type = ClientMessage;
01288       ev.xclient.window = d->client;
01289       ev.xclient.message_type = ATOM(WM_PROTOCOLS);
01290       ev.xclient.format = 32;
01291       ev.xclient.data.s[0] = ATOM(WM_DELETE_WINDOW);
01292       XSendEvent(x11Info().display(), d->client, false, NoEventMask, &ev);
01293 
01294       XFlush(x11Info().display());
01295       d->client = 0;
01296       d->clientIsXEmbed = false;
01297             d->wmMinimumSizeHint = QSize();
01298             updateGeometry();
01299             setEnabled(false);
01300       update();
01301 
01302       emit clientClosed();
01303   }
01304     }
01305     default:
01306   break;
01307     }
01308 
01309     return QObject::eventFilter(o, event);
01310 }
01311 
01316 bool QX11EmbedContainer::x11Event(XEvent *event)
01317 {
01318     Q_D(QX11EmbedContainer);
01319 
01320     switch (event->type) {
01321     case CreateNotify:
01322   // The client created an embedded window.
01323   if (d->client)
01324       d->rejectClient(event->xcreatewindow.window);
01325   else
01326       d->acceptClient(event->xcreatewindow.window);
01327       break;
01328     case DestroyNotify:
01329   if (event->xdestroywindow.window == d->client) {
01330       // The client died.
01331       d->client = 0;
01332       d->clientIsXEmbed = false;
01333             d->wmMinimumSizeHint = QSize();
01334             updateGeometry();
01335       update();
01336             setEnabled(false);
01337       emit clientClosed();
01338   }
01339         break;
01340     case ReparentNotify:
01341   // The client sends us this if it reparents itself out of our
01342   // widget.
01343   if (event->xreparent.window == d->client && event->xreparent.parent != internalWinId()) {
01344       d->client = 0;
01345       d->clientIsXEmbed = false;
01346             d->wmMinimumSizeHint = QSize();
01347             updateGeometry();
01348       update();
01349             setEnabled(false);
01350       emit clientClosed();
01351   } else if (event->xreparent.parent == internalWinId()) {
01352       // The client reparented itself into this window.
01353       if (d->client)
01354     d->rejectClient(event->xreparent.window);
01355       else
01356     d->acceptClient(event->xreparent.window);
01357   }
01358   break;
01359     case ClientMessage: {
01360   if (event->xclient.message_type == _XEMBED) {
01361       // Ignore XEMBED messages not to ourselves
01362       if (event->xclient.window != internalWinId())
01363     break;
01364 
01365       // Receiving an XEmbed message means the client
01366       // is an XEmbed client.
01367       d->clientIsXEmbed = true;
01368 
01369       Time msgtime = (Time) event->xclient.data.l[0];
01370       if (msgtime > X11->time)
01371     X11->time = msgtime;
01372 
01373       switch (event->xclient.data.l[1]) {
01374       case XEMBED_REQUEST_FOCUS: {
01375     // This typically happens when the client gets focus
01376     // because of a mouse click.
01377     if (!hasFocus())
01378         setFocus(Qt::OtherFocusReason);
01379 
01380     // The message is passed along to the topmost container
01381     // that eventually responds with a XEMBED_FOCUS_IN
01382     // message. The focus in message is passed all the way
01383     // back until it reaches the original focus
01384     // requestor. In the end, not only the original client
01385     // has focus, but also all its ancestor containers.
01386     if (d->isEmbedded()) {
01387                     // If our window's embedded flag is set, then
01388         // that suggests that we are part of a client. The
01389         // parentWinId will then point to an container to whom
01390         // we must pass this message.
01391         sendXEmbedMessage(d->topLevelParentWinId(), x11Info().display(), XEMBED_REQUEST_FOCUS);
01392     } else {
01393                     // Our window's embedded flag is not set,
01394         // so we are the topmost container. We respond to
01395         // the focus request message with a focus in
01396         // message. This message will pass on from client
01397         // to container to client until it reaches the
01398         // originator of the XEMBED_REQUEST_FOCUS message.
01399         sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
01400     }
01401 
01402     break;
01403       }
01404       case XEMBED_FOCUS_NEXT:
01405     // Client sends this event when it received a tab
01406     // forward and was at the end of its focus chain. If
01407     // we are the only widget in the focus chain, we send
01408     // ourselves a FocusIn event.
01409                 if (d->focus_next != this) {
01410         focusNextPrevChild(true);
01411                 } else {
01412                     QFocusEvent event(QEvent::FocusIn, Qt::TabFocusReason);
01413                     qApp->sendEvent(this, &event);
01414                 }
01415 
01416     break;
01417       case XEMBED_FOCUS_PREV:
01418     // Client sends this event when it received a backtab
01419     // and was at the start of its focus chain. If we are
01420     // the only widget in the focus chain, we send
01421     // ourselves a FocusIn event.
01422                 if (d->focus_next != this) {
01423         focusNextPrevChild(false);
01424                 } else {
01425                     QFocusEvent event(QEvent::FocusIn, Qt::BacktabFocusReason);
01426                     qApp->sendEvent(this, &event);
01427                 }
01428 
01429     break;
01430       default:
01431     break;
01432       }
01433   }
01434     }
01435   break;
01436     case XButtonPress:
01437   if (!d->clientIsXEmbed) {
01438             setFocus(Qt::MouseFocusReason);
01439             XAllowEvents(x11Info().display(), ReplayPointer, CurrentTime);
01440             return true;
01441   }
01442   break;
01443     case XButtonRelease:
01444   if (!d->clientIsXEmbed)
01445             XAllowEvents(x11Info().display(), SyncPointer, CurrentTime);
01446   break;
01447     default:
01448   break;
01449     }
01450 
01451     return QWidget::x11Event(event);
01452 }
01453 
01458 void QX11EmbedContainer::resizeEvent(QResizeEvent *)
01459 {
01460     Q_D(QX11EmbedContainer);
01461     if (d->client)
01462   XResizeWindow(x11Info().display(), d->client, width(), height());
01463 }
01464 
01471 void QX11EmbedContainer::showEvent(QShowEvent *)
01472 {
01473     Q_D(QX11EmbedContainer);
01474     if (d->client) {
01475   unsigned int data[] = {XEMBED_VERSION, XEMBED_MAPPED};
01476   XChangeProperty(x11Info().display(), d->client, _XEMBED_INFO, XA_CARDINAL, 32,
01477       PropModeReplace, (unsigned char *) data, 2);
01478     }
01479 }
01480 
01487 void QX11EmbedContainer::hideEvent(QHideEvent *)
01488 {
01489     Q_D(QX11EmbedContainer);
01490     if (d->client) {
01491   unsigned int data[] = {XEMBED_VERSION, XEMBED_MAPPED};
01492 
01493   XChangeProperty(x11Info().display(), d->client, _XEMBED_INFO, XA_CARDINAL, 32,
01494       PropModeReplace, (unsigned char *) data, 2);
01495     }
01496 }
01497 
01501 bool QX11EmbedContainer::event(QEvent *event)
01502 {
01503     if (event->type() == QEvent::ParentChange) {
01504         XSelectInput(x11Info().display(), internalWinId(),
01505                      KeyPressMask | KeyReleaseMask
01506                      | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
01507                      | KeymapStateMask
01508                      | PointerMotionMask
01509                      | EnterWindowMask | LeaveWindowMask
01510                      | FocusChangeMask
01511                      | ExposureMask
01512                      | StructureNotifyMask
01513                      | SubstructureNotifyMask);
01514     }
01515     return QWidget::event(event);
01516 }
01517 
01526 void QX11EmbedContainerPrivate::rejectClient(WId window)
01527 {
01528     Q_Q(QX11EmbedContainer);
01529     q->setEnabled(false);
01530     XRemoveFromSaveSet(q->x11Info().display(), client);
01531     XReparentWindow(q->x11Info().display(), window, q->x11Info().appRootWindow(), 0, 0);
01532 }
01533 
01539 void QX11EmbedContainerPrivate::acceptClient(WId window)
01540 {
01541     Q_Q(QX11EmbedContainer);
01542     client = window;
01543     q->setEnabled(true);
01544 
01545     // This tells Qt that we wish to forward DnD messages to
01546     // our client.
01547     if (!extra)
01548         createExtra();
01549     extraData()->xDndProxy = client;
01550 
01551     unsigned int version = XEmbedVersion();
01552 
01553     Atom actual_type_return;
01554     int actual_format_return;
01555     unsigned long nitems_return = 0;
01556     unsigned long bytes_after_return;
01557     unsigned char *prop_return = 0;
01558     unsigned int clientversion = 0;
01559 
01560     // Add this client to our saveset, so if we crash, the client window
01561     // doesn't get destroyed. This is useful for containers that restart
01562     // automatically after a crash, because it can simply reembed its clients
01563     // without having to restart them (KDE panel).
01564     XAddToSaveSet(q->x11Info().display(), client);
01565 
01566     // XEmbed clients have an _XEMBED_INFO property in which we can
01567     // fetch the version
01568     if (XGetWindowProperty(q->x11Info().display(), client, _XEMBED_INFO, 0, 2, false, XA_CARDINAL,
01569          &actual_type_return, &actual_format_return, &nitems_return,
01570          &bytes_after_return, &prop_return) == Success) {
01571 
01572   if (actual_type_return != None && actual_format_return != 0) {
01573       // Clients with the _XEMBED_INFO property are XEMBED clients.
01574       clientIsXEmbed = true;
01575 
01576       unsigned int *p = (unsigned int *)prop_return;
01577       if (nitems_return >= 2)
01578     clientversion = p[0];
01579   }
01580 
01581   XFree(prop_return);
01582     }
01583 
01584     // Store client window's original size and placement.
01585     Window root;
01586     int x_return, y_return;
01587     unsigned int width_return, height_return, border_width_return, depth_return;
01588     XGetGeometry(q->x11Info().display(), client, &root, &x_return, &y_return,
01589      &width_return, &height_return, &border_width_return, &depth_return);
01590     clientOriginalRect.setCoords(x_return, y_return,
01591          x_return + width_return - 1,
01592          y_return + height_return - 1);
01593 
01594     // Ask the client for its minimum size.
01595     XSizeHints size;
01596     long msize;
01597     if (XGetWMNormalHints(q->x11Info().display(), client, &size, &msize) && (size.flags & PMinSize)) {
01598   wmMinimumSizeHint = QSize(size.min_width, size.min_height);
01599         q->updateGeometry();
01600     }
01601 
01602     // The container should set the data2 field to the lowest of its
01603     // supported version number and that of the client (from
01604     // _XEMBED_INFO property).
01605     unsigned int minversion = version > clientversion ? clientversion : version;
01606     sendXEmbedMessage(client, q->x11Info().display(), XEMBED_EMBEDDED_NOTIFY, q->internalWinId(), minversion);
01607     XMapWindow(q->x11Info().display(), client);
01608 
01609     // Resize it, but no smaller than its minimum size hint.
01610     XResizeWindow(q->x11Info().display(), client,
01611                   qMax(q->width(), size.min_width), qMax(q->height(), size.min_height));
01612     q->update();
01613 
01614     // Not mentioned in the protocol is that if the container
01615     // is already active, the client must be activated to work
01616     // properly.
01617     if (q->window()->isActiveWindow())
01618   sendXEmbedMessage(client, q->x11Info().display(), XEMBED_WINDOW_ACTIVATE);
01619 
01620     // Also, if the container already has focus, then it must
01621     // send a focus in message to its new client; otherwise we ask
01622     // it to remove focus.
01623     if (q->focusWidget() == q && q->hasFocus())
01624   sendXEmbedMessage(client, q->x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST);
01625     else
01626   sendXEmbedMessage(client, q->x11Info().display(), XEMBED_FOCUS_OUT);
01627 
01628     if (!clientIsXEmbed) {
01629         checkGrab();
01630         if (q->hasFocus()) {
01631             XSetInputFocus(q->x11Info().display(), client, XRevertToParent, x11Time());
01632         } else {
01633             if (!isEmbedded())
01634                 moveInputToProxy();
01635         }
01636     }
01637 
01638     emit q->clientIsEmbedded();
01639 }
01640 
01649 void QX11EmbedContainerPrivate::moveInputToProxy()
01650 {
01651     Q_Q(QX11EmbedContainer);
01652     WId focus;
01653     int revert_to;
01654     XGetInputFocus(q->x11Info().display(), &focus, &revert_to);
01655     if (focus != focusProxy->internalWinId())
01656   XSetInputFocus(q->x11Info().display(), focusProxy->internalWinId(), XRevertToParent, x11Time());
01657 }
01658 
01663 QSize QX11EmbedContainer::minimumSizeHint() const
01664 {
01665     Q_D(const QX11EmbedContainer);
01666     if (!d->client || !d->wmMinimumSizeHint.isValid())
01667   return QWidget::minimumSizeHint();
01668     return d->wmMinimumSizeHint;
01669 }
01670 
01674 void QX11EmbedContainerPrivate::checkGrab()
01675 {
01676     Q_Q(QX11EmbedContainer);
01677     if (!clientIsXEmbed && q->isActiveWindow() && !q->hasFocus()) {
01678         if (!xgrab) {
01679             XGrabButton(q->x11Info().display(), AnyButton, AnyModifier, q->internalWinId(),
01680                         true, ButtonPressMask, GrabModeSync, GrabModeAsync,
01681                         None, None);
01682         }
01683         xgrab = true;
01684     } else {
01685   if (xgrab)
01686       XUngrabButton(q->x11Info().display(), AnyButton, AnyModifier, q->internalWinId());
01687         xgrab = false;
01688     }
01689 }
01690 
01695 void QX11EmbedContainer::discardClient()
01696 {
01697     Q_D(QX11EmbedContainer);
01698     if (d->client) {
01699   XResizeWindow(x11Info().display(), d->client, d->clientOriginalRect.width(),
01700           d->clientOriginalRect.height());
01701 
01702   d->rejectClient(d->client);
01703     }
01704 }

Generated on Thu Mar 15 11:55:19 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1