Fix Focus problem with QX11EmbedWidget
[qt:qt.git] / src / gui / kernel / qx11embed_x11.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 <qelapsedtimer.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             XFree(retval);
420             if (state == WithdrawnState) {
421                 data->clearedWmState = true;
422                 return true;
423             }
424         }
425     }
426
427     return false;
428 }
429
430 class QX11EmbedWidgetPrivate : public QWidgetPrivate
431 {
432     Q_DECLARE_PUBLIC(QX11EmbedWidget)
433 public:
434     inline QX11EmbedWidgetPrivate()
435     {
436         lastError = QX11EmbedWidget::Unknown;
437         container = 0;
438     }
439
440     void setEmbedded();
441
442     void emitError(QX11EmbedWidget::Error error) {
443         Q_Q(QX11EmbedWidget);
444
445         lastError = error;
446         emit q->error(error);
447     }
448
449     enum FocusWidgets {
450         FirstFocusWidget,
451         LastFocusWidget
452     };
453
454     int focusOriginator;
455     QWidget *getFocusWidget(FocusWidgets fw);
456     void checkActivateWindow(QObject *o);
457     QX11EmbedWidget *xEmbedWidget(QObject *o) const;
458     void clearFocus();
459
460     WId container;
461     QPointer<QWidget> currentFocus;
462
463     QX11EmbedWidget::Error lastError;
464
465 };
466
467 /*!
468     Constructs a QX11EmbedWidget object with the given \a parent.
469 */
470 QX11EmbedWidget::QX11EmbedWidget(QWidget *parent)
471     : QWidget(*new QX11EmbedWidgetPrivate, parent, 0)
472 {
473     XSetErrorHandler(x11ErrorHandler);
474
475     setAttribute(Qt::WA_NativeWindow);
476     setAttribute(Qt::WA_DontCreateNativeAncestors);
477     createWinId();
478     XSelectInput(x11Info().display(), internalWinId(),
479                  KeyPressMask | KeyReleaseMask | ButtonPressMask
480                     | ButtonReleaseMask
481                     | KeymapStateMask | ButtonMotionMask | PointerMotionMask
482                     | FocusChangeMask
483                     | ExposureMask | StructureNotifyMask
484                     | SubstructureNotifyMask | PropertyChangeMask);
485
486     long data[] = {XEMBED_VERSION, XEMBED_MAPPED};
487     XChangeProperty(x11Info().display(), internalWinId(), ATOM(_XEMBED_INFO),
488                     ATOM(_XEMBED_INFO), 32, PropModeReplace,
489                     (unsigned char*) data, 2);
490
491     setFocusPolicy(Qt::StrongFocus);
492     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
493     QApplication::instance()->installEventFilter(this);
494
495     // Focus itself at first.
496     qApp->setActiveWindow(this);
497
498 #ifdef QX11EMBED_DEBUG
499     qDebug() << "QX11EmbedWidget::QX11EmbedWidget: constructed client"
500              << (void *)this << "with winId" << winId();
501 #endif
502 }
503
504 /*!
505     Destructs the QX11EmbedWidget object. If the widget is embedded
506     when deleted, it is hidden and then detached from its container,
507     so that the container is free to embed a new widget.
508 */
509 QX11EmbedWidget::~QX11EmbedWidget()
510 {
511     Q_D(QX11EmbedWidget);
512     if (d->container) {
513 #ifdef QX11EMBED_DEBUG
514         qDebug() << "QX11EmbedWidget::~QX11EmbedWidget: unmapping"
515                  << (void *)this << "with winId" << winId()
516                  << "from container with winId" << d->container;
517 #endif
518         XUnmapWindow(x11Info().display(), internalWinId());
519         XReparentWindow(x11Info().display(), internalWinId(), x11Info().appRootWindow(x11Info().screen()), 0, 0);
520     }
521
522 #ifdef QX11EMBED_DEBUG
523     qDebug() << "QX11EmbedWidget::~QX11EmbedWidget: destructed client"
524              << (void *)this << "with winId" << winId();
525 #endif
526 }
527
528 /*!
529     Returns the type of error that occurred last. This is the same error code
530     that is emitted by the error() signal.
531
532     \sa Error
533 */
534 QX11EmbedWidget::Error QX11EmbedWidget::error() const
535 {
536     return d_func()->lastError;
537 }
538
539 /*!
540     When this function is called, the widget embeds itself into the
541     container whose window ID is \a id.
542
543     If \a id is \e not the window ID of a container this function will
544     behave unpredictably.
545 */
546 void QX11EmbedWidget::embedInto(WId id)
547 {
548     Q_D(QX11EmbedWidget);
549 #ifdef QX11EMBED_DEBUG
550     qDebug() << "QX11EmbedWidget::embedInto: embedding client"
551              << (void *)this << "with winId" << winId() << "into container"
552              << id;
553 #endif
554
555     d->container = id;
556     switch (XReparentWindow(x11Info().display(), internalWinId(), d->container, 0, 0)) {
557     case BadWindow:
558         d->emitError(InvalidWindowID);
559         break;
560     case BadMatch:
561         d->emitError(Internal);
562         break;
563     case Success:
564     default:
565         break;
566     }
567     QTLWExtra* x = d->extra ? d->extra->topextra : 0;
568     if (x)
569         x->frameStrut.setCoords(0, 0, 0, 0);
570     d->data.fstrut_dirty = false;
571 }
572
573 /*! \internal
574
575     Gets the first or last child widget that can get focus.
576 */
577 QWidget *QX11EmbedWidgetPrivate::getFocusWidget(FocusWidgets fw)
578 {
579     Q_Q(QX11EmbedWidget);
580     QWidget *tlw = q;
581     QWidget *w = tlw->nextInFocusChain();
582
583     QWidget *last = tlw;
584
585     extern bool qt_tab_all_widgets;
586     uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus;
587
588     while (w != tlw)
589     {
590         if (((w->focusPolicy() & focus_flag) == focus_flag)
591             && w->isVisibleTo(q) && w->isEnabled())
592         {
593             last = w;
594             if (fw == FirstFocusWidget)
595                 break;
596         }
597         w = w->nextInFocusChain();
598     }
599
600     return last;
601 }
602
603 /*! \internal
604
605     Returns the xembed widget that the widget is a child of
606 */
607 QX11EmbedWidget *QX11EmbedWidgetPrivate::xEmbedWidget(QObject *o) const
608 {
609     QX11EmbedWidget *xec = 0;
610
611     // Check the widget itself, then its parents, and find the first
612     // QX11EmbedWidget.
613     do {
614         if ((xec = qobject_cast<QX11EmbedWidget *>(o)))
615             return xec;
616     } while ((o = o->parent()));
617     return 0;
618 }
619
620 /*! \internal
621
622     Checks the active window.
623 */
624 void QX11EmbedWidgetPrivate::checkActivateWindow(QObject *o)
625 {
626     Q_Q(QX11EmbedWidget);
627     QX11EmbedWidget *xec = xEmbedWidget(o);
628
629     // check if we are in the right xembed client
630     if (q != xec)
631         return;
632
633     QWidget *w = qobject_cast<QWidget *>(o);
634
635     // if it is no active window, then don't do the change
636     if (!(w && qApp->activeWindow()))
637         return;
638
639     // if it already is the active window, don't do anything
640     if (w->window() != qApp->activeWindow())
641     {
642         qApp->setActiveWindow(w->window());
643         currentFocus = w;
644
645         sendXEmbedMessage(xec->containerWinId(), q->x11Info().display(), XEMBED_REQUEST_FOCUS);
646     }
647 }
648
649 /*! \internal
650
651     Clears the focus
652 */
653 void QX11EmbedWidgetPrivate::clearFocus()
654 {
655     Q_Q(QX11EmbedWidget);
656     // Setting focus on the client itself removes Qt's
657     // logical focus rectangle. We can't just do a
658     // clearFocus here, because when we send the synthetic
659     // FocusIn to ourselves on activation, Qt will set
660     // focus on focusWidget() again. This way, we "hide"
661     // focus rather than clearing it.
662
663     if (!q->window()->hasFocus())
664         q->window()->setFocus(Qt::OtherFocusReason);
665
666     currentFocus = 0;
667 }
668
669 /*! \internal
670
671     Sets the embedded flag on the client.
672 */
673 void QX11EmbedWidgetPrivate::setEmbedded()
674 {
675     Q_Q(QX11EmbedWidget);
676     ((QHackWidget *)q->window())->topData()->embedded = 1;
677 }
678
679 /*! \internal
680
681     Handles WindowActivate and FocusIn events for the client.
682 */
683 bool QX11EmbedWidget::eventFilter(QObject *o, QEvent *event)
684 {
685     Q_D(QX11EmbedWidget);
686     switch (event->type()) {
687     case QEvent::FocusIn:
688         switch (((QFocusEvent *)event)->reason()) {
689         case Qt::MouseFocusReason:
690             // If the user clicks into one of the client widget's
691             // children and we didn't have focus already, we request
692             // focus from our container.
693             if (d->xEmbedWidget(o) == this) {
694                 if (d->currentFocus.isNull())
695                     sendXEmbedMessage(d->container, x11Info().display(), XEMBED_REQUEST_FOCUS);
696
697                 d->currentFocus = qobject_cast<QWidget *>(o);
698             }
699             break;
700         case Qt::TabFocusReason:
701             // If the xembed client receives a focus event because of
702             // a Tab, then we are at the end of our focus chain and we
703             // ask the container to move to its next focus widget.
704             if (o == this) {
705                 d->clearFocus();
706                 sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_NEXT);
707                 return true;
708             } else {
709                 // We're listening on events from qApp, so in order
710                 // for us to know who to set focus on if we receive an
711                 // activation event, we note the widget that got the
712                 // focusin last.
713                 if (d->xEmbedWidget(o) == this)
714                     d->currentFocus = qobject_cast<QWidget *>(o);
715             }
716             break;
717         case Qt::BacktabFocusReason:
718             // If the window receives a focus event because of
719             // a Backtab, then we are at the start of our focus chain
720             // and we ask the container to move to its previous focus
721             // widget.
722             if (o == this) {
723                 // See comment for Tab.
724                 // If we receive a XEMBED_FOCUS_IN
725                 // XEMBED_FOCUS_CURRENT, we will set focus in
726                 // currentFocus. To avoid that in this case, we reset
727                 // currentFocus.
728                 d->clearFocus();
729                 sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_PREV);
730                 return true;
731             } else {
732                 if (d->xEmbedWidget(o) == this)
733                     d->currentFocus = qobject_cast<QWidget *>(o);
734             }
735             break;
736         case Qt::ActiveWindowFocusReason:
737             if (isActiveWindow()) {
738                 if (!d->currentFocus.isNull()) {
739                     if (!d->currentFocus->hasFocus())
740                         d->currentFocus->setFocus(Qt::OtherFocusReason);
741                 } else {
742                     d->clearFocus();
743                     return true;
744                 }
745             }
746
747             break;
748         case Qt::PopupFocusReason:
749         case Qt::ShortcutFocusReason:
750         case Qt::OtherFocusReason:
751             // If focus is received to any child widget because of any
752             // other reason, remember the widget so that we can give
753             // it focus again if we're activated.
754             if (d->xEmbedWidget(o) == this) {
755                d->currentFocus = qobject_cast<QWidget *>(o);
756             }
757             break;
758         default:
759             break;
760         }
761         break;
762     case QEvent::MouseButtonPress:
763         // If we get a mouse button press event inside a embedded widget
764         // make sure this is the active window in qapp.
765         d->checkActivateWindow(o);
766         break;
767     default:
768         break;
769     }
770
771     return QWidget::eventFilter(o, event);
772 }
773
774 /*! \internal
775
776     Handles some notification events and client messages. Client side
777     XEmbed message receiving is also handled here.
778 */
779 bool QX11EmbedWidget::x11Event(XEvent *event)
780 {
781     Q_D(QX11EmbedWidget);
782     switch (event->type) {
783     case DestroyNotify:
784 #ifdef QX11EMBED_DEBUG
785         qDebug() << "QX11EmbedWidget::x11Event: client"
786                  << (void *)this << "with winId" << winId()
787                  << "received a DestroyNotify";
788 #endif
789         // If the container window is destroyed, we signal this to the user.
790         d->container = 0;
791         emit containerClosed();
792         break;
793     case ReparentNotify:
794 #ifdef QX11EMBED_DEBUG
795         qDebug() << "QX11EmbedWidget::x11Event: client"
796                  << (void *)this << "with winId" << winId()
797                  << "received a ReparentNotify to"
798                  << ((event->xreparent.parent == x11Info().appRootWindow(x11Info().screen()))
799                      ? QString::fromLatin1("root") : QString::number(event->xreparent.parent));
800 #endif
801         // If the container shuts down, we will be reparented to the
802         // root window. We must also consider the case that we may be
803         // reparented from one container to another.
804         if (event->xreparent.parent == x11Info().appRootWindow(x11Info().screen())) {
805             if (((QHackWidget *)this)->topData()->embedded) {
806                 d->container = 0;
807                 emit containerClosed();
808             }
809             return true;
810         } else {
811             d->container = event->xreparent.parent;
812         }
813         break;
814     case UnmapNotify:
815         // Mapping and unmapping are handled by changes to the
816         // _XEMBED_INFO property. Any default map/unmap requests are
817         // ignored.
818         return true;
819     case PropertyNotify:
820         // The container sends us map/unmap messages through the
821         // _XEMBED_INFO property. We adhere to the XEMBED_MAPPED bit in
822         // data2.
823         if (event->xproperty.atom == ATOM(_XEMBED_INFO)) {
824             Atom actual_type_return;
825             int actual_format_return;
826             unsigned long nitems_return;
827             unsigned long bytes_after_return;
828             unsigned char *prop_return = 0;
829             if (XGetWindowProperty(x11Info().display(), internalWinId(), ATOM(_XEMBED_INFO), 0, 2,
830                                    false, ATOM(_XEMBED_INFO), &actual_type_return,
831                                    &actual_format_return, &nitems_return,
832                                    &bytes_after_return, &prop_return) == Success) {
833                 if (nitems_return > 1) {
834                     if (((long * )prop_return)[1] & XEMBED_MAPPED) {
835                         XMapWindow(x11Info().display(), internalWinId());
836                     } else {
837                         XUnmapWindow(x11Info().display(), internalWinId());
838                     }
839                 }
840                 if (prop_return)
841                     XFree(prop_return);
842             }
843         }
844
845         break;
846     case ClientMessage:
847         // XEMBED messages have message_type _XEMBED
848         if (event->xclient.message_type == ATOM(_XEMBED)) {
849             // Discard XEMBED messages not to ourselves. (### dead code?)
850             if (event->xclient.window != internalWinId())
851                 break;
852
853             // Update qt_x_time if necessary
854             Time msgtime = (Time) event->xclient.data.l[0];
855             if (msgtime > X11->time)
856                 X11->time = msgtime;
857
858             switch (event->xclient.data.l[1]) {
859             case XEMBED_WINDOW_ACTIVATE: {
860                 // When we receive an XEMBED_WINDOW_ACTIVATE, we simply send
861                 // ourselves a WindowActivate event. Real activation happens
862                 // when receive XEMBED_FOCUS_IN.
863                 if (!isActiveWindow()) {
864                     QEvent ev(QEvent::WindowActivate);
865                     QApplication::sendEvent(this, &ev);
866                 }
867             }
868                 break;
869             case XEMBED_WINDOW_DEACTIVATE: {
870                 // When we receive an XEMBED_WINDOW_DEACTIVATE, we simply send
871                 // ourselves a WindowDeactivate event. Real activation happens
872                 // when receive XEMBED_FOCUS_IN.
873                 if (isActiveWindow()) {
874                     if (!qApp->activePopupWidget())
875                         QApplication::setActiveWindow(0);
876                 } else {
877                     QEvent ev(QEvent::WindowDeactivate);
878                     QApplication::sendEvent(this, &ev);
879                 }
880             }
881                 break;
882             case XEMBED_EMBEDDED_NOTIFY: {
883 #ifdef QX11EMBED_DEBUG
884                 qDebug() << "QX11EmbedWidget::x11Event: client"
885                          << (void *)this << "with winId" << winId()
886                          << "received an XEMBED EMBEDDED NOTIFY message";
887 #endif
888                 // In this message's l[2] we have the max version
889                 // supported by both the client and the
890                 // container. QX11EmbedWidget does not use this field.
891
892                 // We have been embedded, so we set our
893                 // client's embedded flag.
894                 d->setEmbedded();
895                 emit embedded();
896             }
897                 break;
898             case XEMBED_FOCUS_IN:
899                 // don't set the focus if a modal dialog is open
900                 if (qApp->activeModalWidget())
901                     break;
902
903                 // in case we embed more than one topLevel window inside the same
904                 // host window.
905                 if (window() != qApp->activeWindow())
906                     qApp->setActiveWindow(this);
907
908                 switch (event->xclient.data.l[2]) {
909                 case XEMBED_FOCUS_CURRENT:
910                     // The container sends us this message if it wants
911                     // us to focus on the widget that last had focus.
912                     // This is the reply when XEMBED_REQUEST_FOCUS is
913                     // sent to the container.
914                     if (!d->currentFocus.isNull()) {
915                         if (!d->currentFocus->hasFocus())
916                             d->currentFocus->setFocus(Qt::OtherFocusReason);
917                     } else {
918                         // No widget currently has focus. We set focus
919                         // on the first widget next to the
920                         // client widget. Since the setFocus will not work
921                         // if the window is disabled, set the currentFocus
922                         // directly so that it's set on window activate.
923                         d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::FirstFocusWidget);
924                         d->currentFocus->setFocus(Qt::OtherFocusReason);
925                     }
926                     break;
927                 case XEMBED_FOCUS_FIRST:
928                     // The container sends this message when it wants
929                     // us to focus on the first widget in our focus
930                     // chain (typically because of a tab).
931                     d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::FirstFocusWidget);
932                     d->currentFocus->setFocus(Qt::TabFocusReason);
933                     break;
934                 case XEMBED_FOCUS_LAST:
935                     // The container sends this message when it wants
936                     // us to focus on the last widget in our focus
937                     // chain (typically because of a backtab).
938                     d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::LastFocusWidget);
939                     d->currentFocus->setFocus(Qt::BacktabFocusReason);
940                     break;
941                 default:
942                     // Ignore any other XEMBED_FOCUS_IN details.
943                     break;
944                 }
945                 break;
946             case XEMBED_FOCUS_OUT:
947                 // The container sends us this message when it wants us
948                 // to lose focus and forget about the widget that last
949                 // had focus. Typically sent by the container when it
950                 // loses focus because of mouse or tab activity. We do
951                 // then not want to set focus on anything if we're
952                 // activated.
953                 if (isActiveWindow())
954                     d->clearFocus();
955
956                 break;
957             default:
958                 // Ignore any other XEMBED messages.
959                 break;
960             };
961         } else {
962             // Non-XEMBED client messages are not interesting.
963         }
964
965         break;
966     default:
967         // Ignore all other x11 events.
968         break;
969     }
970
971     // Allow default handling.
972     return QWidget::x11Event(event);
973 }
974
975 /*!
976     \reimp
977 */
978 bool QX11EmbedWidget::event(QEvent *event)
979 {
980     if (event->type() == QEvent::ParentChange) {
981         XSelectInput(x11Info().display(), internalWinId(),
982                      KeyPressMask | KeyReleaseMask | ButtonPressMask
983                      | ButtonReleaseMask
984                      | KeymapStateMask | ButtonMotionMask | PointerMotionMask
985                      | FocusChangeMask
986                      | ExposureMask | StructureNotifyMask
987                      | SubstructureNotifyMask | PropertyChangeMask);
988     }
989     return QWidget::event(event);
990 }
991
992 /*!
993     \reimp
994 */
995 void QX11EmbedWidget::resizeEvent(QResizeEvent *event)
996 {
997     if (layout())
998         layout()->update();
999     QWidget::resizeEvent(event);
1000 }
1001
1002 /*!
1003     If the widget is embedded, returns the window ID of the
1004     container; otherwize returns 0.
1005 */
1006 WId QX11EmbedWidget::containerWinId() const
1007 {
1008     Q_D(const QX11EmbedWidget);
1009     return d->container;
1010 }
1011
1012 class QX11EmbedContainerPrivate : public QWidgetPrivate
1013 {
1014     Q_DECLARE_PUBLIC(QX11EmbedContainer)
1015 public:
1016     inline QX11EmbedContainerPrivate()
1017     {
1018         lastError = QX11EmbedContainer::Unknown;
1019         client = 0;
1020         focusProxy = 0;
1021         clientIsXEmbed = false;
1022         xgrab = false;
1023     }
1024
1025     bool isEmbedded() const;
1026     void moveInputToProxy();
1027
1028     void acceptClient(WId window);
1029     void rejectClient(WId window);
1030
1031     void checkGrab();
1032
1033     WId topLevelParentWinId() const;
1034
1035     void emitError(QX11EmbedContainer::Error error) {
1036         Q_Q(QX11EmbedContainer);
1037         lastError = error;
1038         emit q->error(error);
1039     }
1040
1041     WId client;
1042     QWidget *focusProxy;
1043     bool clientIsXEmbed;
1044     bool xgrab;
1045     QRect clientOriginalRect;
1046     QSize wmMinimumSizeHint;
1047
1048     QX11EmbedContainer::Error lastError;
1049
1050     static QX11EmbedContainer *activeContainer;
1051 };
1052
1053 QX11EmbedContainer *QX11EmbedContainerPrivate::activeContainer = 0;
1054
1055 /*!
1056     Creates a QX11EmbedContainer object with the given \a parent.
1057 */
1058 QX11EmbedContainer::QX11EmbedContainer(QWidget *parent)
1059     : QWidget(*new QX11EmbedContainerPrivate, parent, 0)
1060 {
1061     Q_D(QX11EmbedContainer);
1062     XSetErrorHandler(x11ErrorHandler);
1063
1064     setAttribute(Qt::WA_NativeWindow);
1065     setAttribute(Qt::WA_DontCreateNativeAncestors);
1066     createWinId();
1067
1068     setFocusPolicy(Qt::StrongFocus);
1069     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
1070     // ### PORT setKeyCompression(false);
1071     setAcceptDrops(true);
1072     setEnabled(false);
1073
1074     // Everybody gets a focus proxy, but only one toplevel container's
1075     // focus proxy is actually in use.
1076     d->focusProxy = new QWidget(this);
1077     d->focusProxy->setAttribute(Qt::WA_NativeWindow);
1078     d->focusProxy->setAttribute(Qt::WA_DontCreateNativeAncestors);
1079     d->focusProxy->createWinId();
1080     d->focusProxy->setGeometry(-1, -1, 1, 1);
1081
1082     // We need events from the window (activation status) and
1083     // from qApp (keypress/release).
1084     qApp->installEventFilter(this);
1085
1086     // Install X11 event filter.
1087     if (!oldX11EventFilter)
1088         oldX11EventFilter = QCoreApplication::instance()->setEventFilter(x11EventFilter);
1089
1090     XSelectInput(x11Info().display(), internalWinId(),
1091                  KeyPressMask | KeyReleaseMask
1092                  | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
1093                  | KeymapStateMask
1094                  | PointerMotionMask
1095                  | EnterWindowMask | LeaveWindowMask
1096                  | FocusChangeMask
1097                  | ExposureMask
1098                  | StructureNotifyMask
1099                  | SubstructureNotifyMask);
1100
1101     // Make sure our new event mask takes effect as soon as possible.
1102     XFlush(x11Info().display());
1103
1104     // Move input to our focusProxy if this widget is active, and not
1105     // shaded by a modal dialog (in which case isActiveWindow() would
1106     // still return true, but where we must not move input focus).
1107     if (qApp->activeWindow() == window() && !d->isEmbedded())
1108         d->moveInputToProxy();
1109
1110 #ifdef QX11EMBED_DEBUG
1111     qDebug() << "QX11EmbedContainer::QX11EmbedContainer: constructed container"
1112              << (void *)this << "with winId" << winId();
1113 #endif
1114 }
1115
1116 /*!
1117     Destructs a QX11EmbedContainer.
1118 */
1119 QX11EmbedContainer::~QX11EmbedContainer()
1120 {
1121     Q_D(QX11EmbedContainer);
1122     if (d->client) {
1123         XUnmapWindow(x11Info().display(), d->client);
1124         XReparentWindow(x11Info().display(), d->client, x11Info().appRootWindow(x11Info().screen()), 0, 0);
1125     }
1126
1127     if (d->xgrab)
1128         XUngrabButton(x11Info().display(), AnyButton, AnyModifier, internalWinId());
1129 }
1130
1131
1132 QX11EmbedContainer::Error QX11EmbedContainer::error() const {
1133     return d_func()->lastError;
1134 }
1135
1136
1137 /*! \reimp
1138 */
1139 void QX11EmbedContainer::paintEvent(QPaintEvent *)
1140 {
1141 }
1142
1143 /*! \internal
1144
1145     Returns whether or not the windows' embedded flag is set.
1146 */
1147 bool QX11EmbedContainerPrivate::isEmbedded() const
1148 {
1149     Q_Q(const QX11EmbedContainer);
1150     return ((QHackWidget *)q->window())->topData()->embedded == 1;
1151 }
1152
1153 /*! \internal
1154
1155     Returns the parentWinId of the window.
1156 */
1157 WId QX11EmbedContainerPrivate::topLevelParentWinId() const
1158 {
1159     Q_Q(const QX11EmbedContainer);
1160     return ((QHackWidget *)q->window())->topData()->parentWinId;
1161 }
1162
1163 /*!
1164     If the container has an embedded widget, this function returns
1165     the X11 window ID of the client; otherwise it returns 0.
1166 */
1167 WId QX11EmbedContainer::clientWinId() const
1168 {
1169     Q_D(const QX11EmbedContainer);
1170     return d->client;
1171 }
1172
1173 /*!
1174     Instructs the container to embed the X11 window with window ID \a
1175     id. The client widget will then move on top of the container
1176     window and be resized to fit into the container.
1177
1178     The \a id should be the ID of a window controlled by an XEmbed
1179     enabled application, but this is not mandatory. If \a id does not
1180     belong to an XEmbed client widget, then focus handling,
1181     activation, accelerators and other features will not work
1182     properly.
1183 */
1184 void QX11EmbedContainer::embedClient(WId id)
1185 {
1186     Q_D(QX11EmbedContainer);
1187
1188     if (id == 0) {
1189         d->emitError(InvalidWindowID);
1190         return;
1191     }
1192
1193     // Walk up the tree of parent windows to prevent embedding of ancestors.
1194     WId thisId = internalWinId();
1195     Window rootReturn;
1196     Window parentReturn;
1197     Window *childrenReturn = 0;
1198     unsigned int nchildrenReturn;
1199     do {
1200         if (XQueryTree(x11Info().display(), thisId, &rootReturn,
1201                        &parentReturn, &childrenReturn, &nchildrenReturn) == 0) {
1202             d->emitError(InvalidWindowID);
1203             return;
1204         }
1205         if (childrenReturn) {
1206             XFree(childrenReturn);
1207             childrenReturn = 0;
1208         }
1209
1210         thisId = parentReturn;
1211         if (id == thisId) {
1212             d->emitError(InvalidWindowID);
1213             return;
1214         }
1215     } while (thisId != rootReturn);
1216
1217     // watch for property notify events (see below)
1218     XGrabServer(x11Info().display());
1219     XWindowAttributes attrib;
1220     if (!XGetWindowAttributes(x11Info().display(), id, &attrib)) {
1221         XUngrabServer(x11Info().display());
1222         d->emitError(InvalidWindowID);
1223         return;
1224     }
1225     XSelectInput(x11Info().display(), id, attrib.your_event_mask | PropertyChangeMask | StructureNotifyMask);
1226     XUngrabServer(x11Info().display());
1227
1228     // Put the window into WithdrawnState
1229     XUnmapWindow(x11Info().display(), id);
1230     XSync(x11Info().display(), False); // make sure the window is hidden
1231
1232     /*
1233       Wait for notification from the window manager that the window is
1234       in withdrawn state.  According to the ICCCM section 4.1.3.1,
1235       we should wait for the WM_STATE property to either be deleted or
1236       set to WithdrawnState.
1237
1238       For safety, we will not wait more than 500 ms, so that we can
1239       preemptively workaround buggy window managers.
1240     */
1241     QElapsedTimer t;
1242     t.start();
1243
1244     functorData data;
1245     data.id = id;
1246     data.rootWindow = attrib.root;
1247     data.clearedWmState = false;
1248     data.reparentedToRoot = false;
1249
1250     do {
1251         if (t.elapsed() > 500) // time-out after 500 ms
1252             break;
1253
1254         XEvent event;
1255         if (!XCheckIfEvent(x11Info().display(), &event, functor, (XPointer) &data)) {
1256             XSync(x11Info().display(), False);
1257             usleep(50000);
1258             continue;
1259         }
1260
1261         qApp->x11ProcessEvent(&event);
1262     } while (!data.clearedWmState || !data.reparentedToRoot);
1263
1264     // restore the event mask
1265     XSelectInput(x11Info().display(), id, attrib.your_event_mask);
1266
1267     switch (XReparentWindow(x11Info().display(), id, internalWinId(), 0, 0)) {
1268     case BadWindow:
1269     case BadMatch:
1270         d->emitError(InvalidWindowID);
1271         break;
1272     default:
1273         break;
1274     }
1275 }
1276
1277 /*! \internal
1278
1279     Handles key, activation and focus events for the container.
1280 */
1281 bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event)
1282 {
1283     Q_D(QX11EmbedContainer);
1284     switch (event->type()) {
1285     case QEvent::KeyPress:
1286         // Forward any keypresses to our client.
1287         if (o == this && d->client) {
1288             lastKeyEvent.window = d->client;
1289             XSendEvent(x11Info().display(), d->client, false, KeyPressMask, (XEvent *) &lastKeyEvent);
1290             return true;
1291         }
1292         break;
1293     case QEvent::KeyRelease:
1294         // Forward any keyreleases to our client.
1295         if (o == this && d->client) {
1296             lastKeyEvent.window = d->client;
1297             XSendEvent(x11Info().display(), d->client, false, KeyReleaseMask, (XEvent *) &lastKeyEvent);
1298             return true;
1299         }
1300         break;
1301
1302     case QEvent::WindowActivate:
1303         // When our container window is activated, we pass the
1304         // activation message on to our client. Note that X input
1305         // focus is set to our focus proxy. We want to intercept all
1306         // keypresses.
1307         if (o == window() && d->client) {
1308             if (d->clientIsXEmbed) {
1309                 sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_ACTIVATE);
1310             } else {
1311                 d->checkGrab();
1312                 if (hasFocus())
1313                     XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
1314             }
1315             if (!d->isEmbedded())
1316                 d->moveInputToProxy();
1317         }
1318         break;
1319     case QEvent::WindowDeactivate:
1320         // When our container window is deactivated, we pass the
1321         // deactivation message to our client.
1322         if (o == window() && d->client) {
1323             if (d->clientIsXEmbed)
1324                 sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_DEACTIVATE);
1325             else
1326                 d->checkGrab();
1327         }
1328         break;
1329     case QEvent::FocusIn:
1330         // When receiving FocusIn events generated by Tab or Backtab,
1331         // we pass focus on to our client. Any mouse activity is sent
1332         // directly to the client, and it will ask us for focus with
1333         // XEMBED_REQUEST_FOCUS.
1334         if (o == this && d->client) {
1335             if (!d->isEmbedded())
1336                 d->activeContainer = this;
1337
1338             if (d->clientIsXEmbed) {
1339                 if (!d->isEmbedded())
1340                     d->moveInputToProxy();
1341
1342                 QFocusEvent *fe = (QFocusEvent *)event;
1343                 switch (fe->reason()) {
1344                 case Qt::TabFocusReason:
1345                     sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST);
1346                     break;
1347                 case Qt::BacktabFocusReason:
1348                     sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_LAST);
1349                     break;
1350                 default:
1351                     sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
1352                     break;
1353                 }
1354             } else {
1355                 d->checkGrab();
1356                 XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
1357             }
1358         }
1359
1360         break;
1361     case QEvent::FocusOut: {
1362         // When receiving a FocusOut, we ask our client to remove its
1363         // focus.
1364         if (o == this && d->client) {
1365             if (!d->isEmbedded()) {
1366                 d->activeContainer = 0;
1367                 if (isActiveWindow())
1368                     d->moveInputToProxy();
1369             }
1370
1371             if (d->clientIsXEmbed) {
1372                 QFocusEvent *fe = (QFocusEvent *)event;
1373                 if (o == this && d->client && fe->reason() != Qt::ActiveWindowFocusReason)
1374                     sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_OUT);
1375             } else {
1376                 d->checkGrab();
1377             }
1378         }
1379     }
1380         break;
1381
1382     case QEvent::Close: {
1383         if (o == this && d->client) {
1384             // Unmap the client and reparent it to the root window.
1385             // Wait until the messages have been processed. Then ask
1386             // the window manager to delete the window.
1387             XUnmapWindow(x11Info().display(), d->client);
1388             XReparentWindow(x11Info().display(), d->client, x11Info().appRootWindow(x11Info().screen()), 0, 0);
1389             XSync(x11Info().display(), false);
1390
1391             XEvent ev;
1392             memset(&ev, 0, sizeof(ev));
1393             ev.xclient.type = ClientMessage;
1394             ev.xclient.window = d->client;
1395             ev.xclient.message_type = ATOM(WM_PROTOCOLS);
1396             ev.xclient.format = 32;
1397             ev.xclient.data.s[0] = ATOM(WM_DELETE_WINDOW);
1398             XSendEvent(x11Info().display(), d->client, false, NoEventMask, &ev);
1399
1400             XFlush(x11Info().display());
1401             d->client = 0;
1402             d->clientIsXEmbed = false;
1403             d->wmMinimumSizeHint = QSize();
1404             updateGeometry();
1405             setEnabled(false);
1406             update();
1407
1408             emit clientClosed();
1409         }
1410     }
1411     default:
1412         break;
1413     }
1414
1415     return QWidget::eventFilter(o, event);
1416 }
1417
1418 /*! \internal
1419
1420     Handles X11 events for the container.
1421 */
1422 bool QX11EmbedContainer::x11Event(XEvent *event)
1423 {
1424     Q_D(QX11EmbedContainer);
1425
1426     switch (event->type) {
1427     case CreateNotify:
1428         // The client created an embedded window.
1429         if (d->client)
1430             d->rejectClient(event->xcreatewindow.window);
1431         else
1432             d->acceptClient(event->xcreatewindow.window);
1433       break;
1434     case DestroyNotify:
1435         if (event->xdestroywindow.window == d->client) {
1436             // The client died.
1437             d->client = 0;
1438             d->clientIsXEmbed = false;
1439             d->wmMinimumSizeHint = QSize();
1440             updateGeometry();
1441             update();
1442             setEnabled(false);
1443             emit clientClosed();
1444         }
1445         break;
1446     case ReparentNotify:
1447         // The client sends us this if it reparents itself out of our
1448         // widget.
1449         if (event->xreparent.window == d->client && event->xreparent.parent != internalWinId()) {
1450             d->client = 0;
1451             d->clientIsXEmbed = false;
1452             d->wmMinimumSizeHint = QSize();
1453             updateGeometry();
1454             update();
1455             setEnabled(false);
1456             emit clientClosed();
1457         } else if (event->xreparent.parent == internalWinId()) {
1458             // The client reparented itself into this window.
1459             if (d->client)
1460                 d->rejectClient(event->xreparent.window);
1461             else
1462                 d->acceptClient(event->xreparent.window);
1463         }
1464         break;
1465     case ClientMessage: {
1466         if (event->xclient.message_type == ATOM(_XEMBED)) {
1467             // Ignore XEMBED messages not to ourselves
1468             if (event->xclient.window != internalWinId())
1469                 break;
1470
1471             // Receiving an XEmbed message means the client
1472             // is an XEmbed client.
1473             d->clientIsXEmbed = true;
1474
1475             Time msgtime = (Time) event->xclient.data.l[0];
1476             if (msgtime > X11->time)
1477                 X11->time = msgtime;
1478
1479             switch (event->xclient.data.l[1]) {
1480             case XEMBED_REQUEST_FOCUS: {
1481                 // This typically happens when the client gets focus
1482                 // because of a mouse click.
1483                 if (!hasFocus())
1484                     setFocus(Qt::OtherFocusReason);
1485
1486                 // The message is passed along to the topmost container
1487                 // that eventually responds with a XEMBED_FOCUS_IN
1488                 // message. The focus in message is passed all the way
1489                 // back until it reaches the original focus
1490                 // requestor. In the end, not only the original client
1491                 // has focus, but also all its ancestor containers.
1492                 if (d->isEmbedded()) {
1493                     // If our window's embedded flag is set, then
1494                     // that suggests that we are part of a client. The
1495                     // parentWinId will then point to an container to whom
1496                     // we must pass this message.
1497                     sendXEmbedMessage(d->topLevelParentWinId(), x11Info().display(), XEMBED_REQUEST_FOCUS);
1498                 } else {
1499                     // Our window's embedded flag is not set,
1500                     // so we are the topmost container. We respond to
1501                     // the focus request message with a focus in
1502                     // message. This message will pass on from client
1503                     // to container to client until it reaches the
1504                     // originator of the XEMBED_REQUEST_FOCUS message.
1505                     sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
1506                 }
1507
1508                 break;
1509             }
1510             case XEMBED_FOCUS_NEXT:
1511                 // Client sends this event when it received a tab
1512                 // forward and was at the end of its focus chain. If
1513                 // we are the only widget in the focus chain, we send
1514                 // ourselves a FocusIn event.
1515                 if (d->focus_next != this) {
1516                     focusNextPrevChild(true);
1517                 } else {
1518                     QFocusEvent event(QEvent::FocusIn, Qt::TabFocusReason);
1519                     qApp->sendEvent(this, &event);
1520                 }
1521
1522                 break;
1523             case XEMBED_FOCUS_PREV:
1524                 // Client sends this event when it received a backtab
1525                 // and was at the start of its focus chain. If we are
1526                 // the only widget in the focus chain, we send
1527                 // ourselves a FocusIn event.
1528                 if (d->focus_next != this) {
1529                     focusNextPrevChild(false);
1530                 } else {
1531                     QFocusEvent event(QEvent::FocusIn, Qt::BacktabFocusReason);
1532                     qApp->sendEvent(this, &event);
1533                 }
1534
1535                 break;
1536             default:
1537                 break;
1538             }
1539         }
1540     }
1541         break;
1542     case XButtonPress:
1543         if (!d->clientIsXEmbed) {
1544             setFocus(Qt::MouseFocusReason);
1545             XAllowEvents(x11Info().display(), ReplayPointer, CurrentTime);
1546             return true;
1547         }
1548         break;
1549     case XButtonRelease:
1550         if (!d->clientIsXEmbed)
1551             XAllowEvents(x11Info().display(), SyncPointer, CurrentTime);
1552         break;
1553     default:
1554         break;
1555     }
1556
1557     return QWidget::x11Event(event);
1558 }
1559
1560 /*! \internal
1561
1562     Whenever the container is resized, we need to resize our client.
1563 */
1564 void QX11EmbedContainer::resizeEvent(QResizeEvent *)
1565 {
1566     Q_D(QX11EmbedContainer);
1567     if (d->client)
1568         XResizeWindow(x11Info().display(), d->client, width(), height());
1569 }
1570
1571 /*! \internal
1572
1573     We use the QShowEvent to signal to our client that we want it to
1574     map itself. We do this by changing its window property
1575     XEMBED_INFO. The client will get an X11 PropertyNotify.
1576 */
1577 void QX11EmbedContainer::showEvent(QShowEvent *)
1578 {
1579     Q_D(QX11EmbedContainer);
1580     if (d->client) {
1581         long data[] = {XEMBED_VERSION, XEMBED_MAPPED};
1582         XChangeProperty(x11Info().display(), d->client, ATOM(_XEMBED_INFO), ATOM(_XEMBED_INFO), 32,
1583                         PropModeReplace, (unsigned char *) data, 2);
1584     }
1585 }
1586
1587 /*! \internal
1588
1589     We use the QHideEvent to signal to our client that we want it to
1590     unmap itself. We do this by changing its window property
1591     XEMBED_INFO. The client will get an X11 PropertyNotify.
1592 */
1593 void QX11EmbedContainer::hideEvent(QHideEvent *)
1594 {
1595     Q_D(QX11EmbedContainer);
1596     if (d->client) {
1597         long data[] = {XEMBED_VERSION, XEMBED_MAPPED};
1598         XChangeProperty(x11Info().display(), d->client, ATOM(_XEMBED_INFO), ATOM(_XEMBED_INFO), 32,
1599                         PropModeReplace, (unsigned char *) data, 2);
1600     }
1601 }
1602
1603 /*!
1604     \reimp
1605 */
1606 bool QX11EmbedContainer::event(QEvent *event)
1607 {
1608     if (event->type() == QEvent::ParentChange) {
1609         XSelectInput(x11Info().display(), internalWinId(),
1610                      KeyPressMask | KeyReleaseMask
1611                      | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
1612                      | KeymapStateMask
1613                      | PointerMotionMask
1614                      | EnterWindowMask | LeaveWindowMask
1615                      | FocusChangeMask
1616                      | ExposureMask
1617                      | StructureNotifyMask
1618                      | SubstructureNotifyMask);
1619     }
1620     return QWidget::event(event);
1621 }
1622
1623 /*! \internal
1624
1625     Rejects a client window by reparenting it to the root window.  The
1626     client will receive a reparentnotify, and will most likely assume
1627     that the container has shut down. The XEmbed protocol does not
1628     define any way to reject a client window, but this is a clean way
1629     to do it.
1630 */
1631 void QX11EmbedContainerPrivate::rejectClient(WId window)
1632 {
1633     Q_Q(QX11EmbedContainer);
1634     q->setEnabled(false);
1635     XRemoveFromSaveSet(q->x11Info().display(), client);
1636     XReparentWindow(q->x11Info().display(), window, q->x11Info().appRootWindow(q->x11Info().screen()), 0, 0);
1637 }
1638
1639 /*! \internal
1640
1641     Accepts a client by mapping it, resizing it and optionally
1642     activating and giving it logical focusing through XEMBED messages.
1643 */
1644 void QX11EmbedContainerPrivate::acceptClient(WId window)
1645 {
1646     Q_Q(QX11EmbedContainer);
1647     client = window;
1648     q->setEnabled(true);
1649
1650     // This tells Qt that we wish to forward DnD messages to
1651     // our client.
1652     if (!extra)
1653         createExtra();
1654     extraData()->xDndProxy = client;
1655
1656     unsigned int version = XEmbedVersion();
1657
1658     Atom actual_type_return;
1659     int actual_format_return;
1660     unsigned long nitems_return = 0;
1661     unsigned long bytes_after_return;
1662     unsigned char *prop_return = 0;
1663     unsigned int clientversion = 0;
1664
1665     // Add this client to our saveset, so if we crash, the client window
1666     // doesn't get destroyed. This is useful for containers that restart
1667     // automatically after a crash, because it can simply reembed its clients
1668     // without having to restart them (KDE panel).
1669     XAddToSaveSet(q->x11Info().display(), client);
1670
1671     // XEmbed clients have an _XEMBED_INFO property in which we can
1672     // fetch the version
1673     if (XGetWindowProperty(q->x11Info().display(), client, ATOM(_XEMBED_INFO), 0, 2, false,
1674                            ATOM(_XEMBED_INFO), &actual_type_return, &actual_format_return,
1675                            &nitems_return, &bytes_after_return, &prop_return) == Success) {
1676
1677         if (actual_type_return != None && actual_format_return != 0) {
1678             // Clients with the _XEMBED_INFO property are XEMBED clients.
1679             clientIsXEmbed = true;
1680
1681             long *p = (long *)prop_return;
1682             if (nitems_return >= 2)
1683                 clientversion = (unsigned int)p[0];
1684         }
1685
1686         XFree(prop_return);
1687     }
1688
1689     // Store client window's original size and placement.
1690     Window root;
1691     int x_return, y_return;
1692     unsigned int width_return, height_return, border_width_return, depth_return;
1693     XGetGeometry(q->x11Info().display(), client, &root, &x_return, &y_return,
1694                  &width_return, &height_return, &border_width_return, &depth_return);
1695     clientOriginalRect.setCoords(x_return, y_return,
1696                                  x_return + width_return - 1,
1697                                  y_return + height_return - 1);
1698
1699     // Ask the client for its minimum size.
1700     XSizeHints size;
1701     long msize;
1702     if (XGetWMNormalHints(q->x11Info().display(), client, &size, &msize) && (size.flags & PMinSize)) {
1703         wmMinimumSizeHint = QSize(size.min_width, size.min_height);
1704         q->updateGeometry();
1705     }
1706
1707     // The container should set the data2 field to the lowest of its
1708     // supported version number and that of the client (from
1709     // _XEMBED_INFO property).
1710     unsigned int minversion = version > clientversion ? clientversion : version;
1711     sendXEmbedMessage(client, q->x11Info().display(), XEMBED_EMBEDDED_NOTIFY, q->internalWinId(), minversion);
1712     XMapWindow(q->x11Info().display(), client);
1713
1714     // Resize it, but no smaller than its minimum size hint.
1715     XResizeWindow(q->x11Info().display(),
1716                   client,
1717                   qMax(q->width(), wmMinimumSizeHint.width()),
1718                   qMax(q->height(), wmMinimumSizeHint.height()));
1719     q->update();
1720
1721     // Not mentioned in the protocol is that if the container
1722     // is already active, the client must be activated to work
1723     // properly.
1724     if (q->window()->isActiveWindow())
1725         sendXEmbedMessage(client, q->x11Info().display(), XEMBED_WINDOW_ACTIVATE);
1726
1727     // Also, if the container already has focus, then it must
1728     // send a focus in message to its new client; otherwise we ask
1729     // it to remove focus.
1730     if (q->focusWidget() == q && q->hasFocus())
1731         sendXEmbedMessage(client, q->x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST);
1732     else
1733         sendXEmbedMessage(client, q->x11Info().display(), XEMBED_FOCUS_OUT);
1734
1735     if (!clientIsXEmbed) {
1736         checkGrab();
1737         if (q->hasFocus()) {
1738             XSetInputFocus(q->x11Info().display(), client, XRevertToParent, x11Time());
1739         }
1740     } else {
1741         if (!isEmbedded())
1742             moveInputToProxy();
1743     }
1744
1745     emit q->clientIsEmbedded();
1746 }
1747
1748 /*! \internal
1749
1750     Moves X11 keyboard input focus to the focusProxy, unless the focus
1751     is there already. When X11 keyboard input focus is on the
1752     focusProxy, which is a child of the container and a sibling of the
1753     client, X11 keypresses and keyreleases will always go to the proxy
1754     and not to the client.
1755 */
1756 void QX11EmbedContainerPrivate::moveInputToProxy()
1757 {
1758     Q_Q(QX11EmbedContainer);
1759     // Following Owen Taylor's advice from the XEmbed specification to
1760     // always use CurrentTime when no explicit user action is involved.
1761     XSetInputFocus(q->x11Info().display(), focusProxy->internalWinId(), XRevertToParent, CurrentTime);
1762 }
1763
1764 /*! \internal
1765
1766     Ask the window manager to give us a default minimum size.
1767 */
1768 QSize QX11EmbedContainer::minimumSizeHint() const
1769 {
1770     Q_D(const QX11EmbedContainer);
1771     if (!d->client || !d->wmMinimumSizeHint.isValid())
1772         return QWidget::minimumSizeHint();
1773     return d->wmMinimumSizeHint;
1774 }
1775
1776 /*! \internal
1777
1778 */
1779 void QX11EmbedContainerPrivate::checkGrab()
1780 {
1781     Q_Q(QX11EmbedContainer);
1782     if (!clientIsXEmbed && q->isActiveWindow() && !q->hasFocus()) {
1783         if (!xgrab) {
1784             XGrabButton(q->x11Info().display(), AnyButton, AnyModifier, q->internalWinId(),
1785                         true, ButtonPressMask, GrabModeSync, GrabModeAsync,
1786                         None, None);
1787         }
1788         xgrab = true;
1789     } else {
1790         if (xgrab)
1791             XUngrabButton(q->x11Info().display(), AnyButton, AnyModifier, q->internalWinId());
1792         xgrab = false;
1793     }
1794 }
1795
1796 /*!
1797     Detaches the client from the embedder. The client will appear as a
1798     standalone window on the desktop.
1799 */
1800 void QX11EmbedContainer::discardClient()
1801 {
1802     Q_D(QX11EmbedContainer);
1803     if (d->client) {
1804         XResizeWindow(x11Info().display(), d->client, d->clientOriginalRect.width(),
1805                       d->clientOriginalRect.height());
1806
1807         d->rejectClient(d->client);
1808     }
1809 }
1810
1811 QT_END_NAMESPACE