summaryrefslogtreecommitdiffstats
path: root/kdeui/qxembed.cpp
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch)
tree5ac38a06f3dde268dc7927dc155896926aaf7012 /kdeui/qxembed.cpp
downloadtdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz
tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kdeui/qxembed.cpp')
-rw-r--r--kdeui/qxembed.cpp1385
1 files changed, 1385 insertions, 0 deletions
diff --git a/kdeui/qxembed.cpp b/kdeui/qxembed.cpp
new file mode 100644
index 000000000..19b4a3d19
--- /dev/null
+++ b/kdeui/qxembed.cpp
@@ -0,0 +1,1385 @@
+/****************************************************************************
+ Implementation of QXEmbed class
+
+ Copyright (C) 1999-2002 Trolltech AS
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*****************************************************************************/
+
+
+// L-000: About comments marked with Lxxxx.
+//
+// These comments represent an attempt to provide a more adequate
+// documentation to KDE developpers willing to modify QXEmbed. Keep in
+// mind that these comments were written long after most of the code.
+// Please improve them if you spot something wrong or missing
+// (Leon Bottou, 26-10-2003).
+//
+// Relevant documents:
+// - QXEmbed developper documentation
+// (see comments in qxembed.h)
+// - Xlib Reference Manual
+// (sections about focus, reparenting, window management)
+// - ICCCM Manual
+// (window management)
+// - XEMBED specification
+// (http://www.freedesktop.org/Standards/xembed-spec)
+// - XPLAIN and XEMBED.
+// <http://lists.kde.org/?w=2&r=1&s=qxembed+variants&q=t>
+// - Accumulated community knowledge.
+// <http://lists.kde.org/?w=2&r=1&s=qxembed&q=t>
+// <http://lists.kde.org/?l=kde-devel&w=2&r=1&s=qxembed&q=b>
+// <http://lists.kde.org/?l=kfm-devel&w=2&r=1&s=qxembed&q=b>
+//
+
+
+#include <qapplication.h>
+#include <qptrlist.h>
+#include <qptrdict.h>
+#include <qguardedptr.h>
+#include <qwhatsthis.h>
+#include <qfocusdata.h>
+
+// L0001: QXEmbed works only under X windows.
+#ifdef Q_WS_X11
+
+# include <X11/X.h>
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+# include <X11/Xatom.h>
+# define XK_MISCELLANY
+# define XK_LATIN1
+# include <X11/keysymdef.h>
+# include <kdebug.h>
+# include <kxerrorhandler.h>
+
+// L0002: Is file config.h KDE specific?
+# include <config.h>
+# ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# ifdef HAVE_USLEEP
+# define USLEEP(x) usleep(x)
+# else
+# define USLEEP(x) sleep(0)
+# endif
+# else
+# define USLEEP(x) sleep(0)
+# endif
+
+# include "qxembed.h"
+
+// L0003: This keysym is used for focus navigation.
+# ifndef XK_ISO_Left_Tab
+# define XK_ISO_Left_Tab 0xFE20
+# endif
+
+// L0004: Conflicts between X11 and Qt definitions.
+const int XFocusOut = FocusOut;
+const int XFocusIn = FocusIn;
+const int XKeyPress = KeyPress;
+const int XKeyRelease = KeyRelease;
+# undef KeyRelease
+# undef KeyPress
+# undef FocusOut
+# undef FocusIn
+
+// L0005: Variables defined in qapplication_x11.cpp
+extern Atom qt_wm_protocols;
+extern Atom qt_wm_delete_window;
+extern Atom qt_wm_take_focus;
+extern Atom qt_wm_state;
+extern Time qt_x_time;
+
+// L0006: X11 atoms private to QXEmbed
+static Atom xembed = 0;
+static Atom context_help = 0;
+
+// L0007: Xembed message codes (see XEmbed spec)
+#define XEMBED_EMBEDDED_NOTIFY 0
+#define XEMBED_WINDOW_ACTIVATE 1
+#define XEMBED_WINDOW_DEACTIVATE 2
+#define XEMBED_REQUEST_FOCUS 3
+#define XEMBED_FOCUS_IN 4
+#define XEMBED_FOCUS_OUT 5
+#define XEMBED_FOCUS_NEXT 6
+#define XEMBED_FOCUS_PREV 7
+
+// L0008: Xembed message details (see XEmbed spec)
+// -- XEMBED_FOCUS_IN:
+#define XEMBED_FOCUS_CURRENT 0
+#define XEMBED_FOCUS_FIRST 1
+#define XEMBED_FOCUS_LAST 2
+
+
+// L0100: Private data held by the QXEmbed object.
+// This belongs to the embedder side.
+class QXEmbedData
+{
+public:
+ QXEmbedData(){
+ autoDelete = true;
+ xplain = false;
+ xgrab = false;
+ mapAfterRelease = false;
+ lastPos = QPoint(0,0);
+ }
+ ~QXEmbedData(){}
+
+ bool autoDelete; // L0101: See L2600
+ bool xplain; // L0102: See L1100
+ bool xgrab; // L0103: See L2800
+ bool mapAfterRelease;
+ QWidget* focusProxy; // L0104: See XEmbed spec
+ QPoint lastPos; // L0105: See L1390
+};
+
+namespace
+{
+ // L0200: This application wide event filter handles focus
+ // issues in the embedded client.
+ class QXEmbedAppFilter : public QObject
+ {
+ public:
+ QXEmbedAppFilter() { qApp->installEventFilter( this ); }
+ ~QXEmbedAppFilter() { }
+ bool eventFilter( QObject *, QEvent * );
+ };
+}
+
+// L0201: See L0200, L0740
+static QXEmbedAppFilter* filter = 0;
+// L0202: See L0610, L0730
+static QPtrDict<QGuardedPtr<QWidget> > *focusMap = 0;
+// L0203: See L0660, L1400, L1450
+static XKeyEvent last_key_event;
+
+// L0300: This class gives access protected members of class QWidget.
+// Function focusData() is useful to reimplement tab focus management
+// (L0620) Function topData() returns a structure QTLWExtra containing
+// information unique to toplevel windows. This structure contains two
+// members for the sole use of QXEmbed. Flag `embedded' indicates whether
+// the toplevel window is embedded using the XEMBED protocol (L0680).
+// Handle `parentWinId' then records the id of the embedding window.
+
+class QPublicWidget : public QWidget
+{
+public:
+ QTLWExtra* topData() { return QWidget::topData(); }
+ QFocusData *focusData(){ return QWidget::focusData(); }
+ bool focusNextPrev(bool b) { return focusNextPrevChild(b); }
+};
+
+// L0400: This sets a very low level filter for X11 messages.
+// See qapplication_x11.cpp
+typedef int (*QX11EventFilter) (XEvent*);
+extern QX11EventFilter qt_set_x11_event_filter (QX11EventFilter filter);
+static QX11EventFilter oldFilter = 0;
+
+
+// L0500: Helper to send XEmbed messages.
+static void sendXEmbedMessage( WId window, long message, long detail = 0,
+ long data1 = 0, long data2 = 0)
+{
+ if (!window) return;
+ XEvent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = window;
+ ev.xclient.message_type = xembed;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = qt_x_time;
+ ev.xclient.data.l[1] = message;
+ ev.xclient.data.l[2] = detail;
+ ev.xclient.data.l[3] = data1;
+ ev.xclient.data.l[4] = data2;
+ XSendEvent(qt_xdisplay(), window, false, NoEventMask, &ev);
+}
+
+// L0501: Helper to send ICCCM Client messages.
+// See X11 ICCCM Specification.
+static void sendClientMessage(Window window, Atom a, long x)
+{
+ if (!window) return;
+ XEvent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.xclient.type = ClientMessage;
+ ev.xclient.window = window;
+ ev.xclient.message_type = a;
+ ev.xclient.format = 32;
+ ev.xclient.data.l[0] = x;
+ ev.xclient.data.l[1] = qt_x_time;
+ XSendEvent(qt_xdisplay(), window, false, NoEventMask, &ev);
+}
+
+// L0502: Helper to send fake X11 focus messages.
+// See X11 Reference Manual and Window Management stuff.
+static void sendFocusMessage(Window window, int type, int mode, int detail)
+{
+ if (!window) return;
+ XEvent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.xfocus.type = type;
+ ev.xfocus.window = window;
+ ev.xfocus.mode = mode;
+ ev.xfocus.detail = detail;
+ XSendEvent(qt_xdisplay(), window, false, FocusChangeMask, &ev);
+}
+
+
+// ------------------------------------------------------------
+// L0600: MOST OF WHAT FOLLOWS CONCERNS THE CLIENT SIDE.
+// The following code mostly executes inside a Qt application swallowed
+// by QXEmbed widget. It mostly consists of event filters that fight
+// the normal Qt mechanisms in order to implement the XEMBED protocol.
+// All this would be a lot simpler if it was implemented by Qt itself.
+
+
+
+// L0610: This event filter receives all Qt events. Its main purpose is to
+// capture the Qt focus events in the embedded client in order to
+// implement the XEMBED protocol.
+//
+// Let's start with a few reminders:
+//
+// - X11 only has the concept of the "X11 focus window". This window
+// basically receives all key events. The ICCCM conventions define
+// how the window manager and the applications must cooperate to
+// choose the X11 focus window.
+//
+// - Most toolkits, including Qt, maintain the concepts of 'active
+// widget' and 'Qt focus widget'. A toplevel widget is active when
+// the X11 focus is set to one of its children. By extension a
+// widget is active when its toplevel widget is active. There is one
+// Qt focus widget for each toplevel widget. When the toplevel
+// widget is active, all key events are sent to the Qt focus widget,
+// regardless of which descendant of the toplevel window has the X11
+// focus. Widgets can adjust their appearance according to both
+// their activation and focus states. The Qt FocusIn and FocusOut
+// events indicate when a widget simultaneously is active and has
+// the Qt focus.
+//
+// The XEMBED protocol defines ways to communicate abouth both
+// activation and focus. The embedded client is active as soon as the
+// embedding window is active (L0676, L0677). A widget in the embedded
+// client receives key events when (1) it has the Qt focus in the
+// embedded application, and (2) the QXEmbed widget in the embedding
+// application is active and has the Qt focus. The Qt library in the
+// embedded application is unaware of the focus status of the QXEmbed
+// widget. We must make sure it does the right thing regarding the
+// sending of focus events and the visual appearance of the focussed
+// widgets. When the QXEmbed widget looses the Qt focus, we clear the
+// focus in the embedded client (L1570, L0688). Conversely, when
+// the QXEmbed widget gains the Qt focus, we restore the Qt focus
+// window in the embedded client (L1530, L0680, L0683).
+// Variable focusMap is used to remember which was the Qt focus
+// widget in the embedded application. All this would be a lot
+// simpler if it was implemented inside Qt...
+//
+// The XPLAIN protocol is much less refined in this respect.
+// The activation status of the embedded client simply reflect
+// the focus status of the QXEmbed widget. This is achieved
+// by sending fake X11 focus message to the client (L1521, L1561).
+// A passive button grab (L2800) intercepts mouse activity in the
+// embedded client and sets the Qt focus to the QXEmbed widget
+// when this happens (L2060). This can be achieved without
+// cooperation from the client.
+
+bool QXEmbedAppFilter::eventFilter( QObject *o, QEvent * e)
+{
+ static bool obeyFocus = false;
+ switch ( e->type() ) {
+ case QEvent::MouseButtonPress:
+ // L0612: This will become clear with L0614
+ if ( !((QWidget*)o)->isActiveWindow() )
+ obeyFocus = true;
+ break;
+ case QEvent::FocusIn:
+ // L0613: FocusIn events either occur because the widget already was
+ // active and has just been given the Qt focus (L0614) or
+ // because the widget already had the Qt focus and just became
+ // active (L0615).
+ if ( qApp->focusWidget() == o &&
+ ((QPublicWidget*)qApp->focusWidget()->topLevelWidget())->topData()->embedded ) {
+ QFocusEvent* fe = (QFocusEvent*) e;
+ if ( obeyFocus || fe->reason() == QFocusEvent::Mouse ||
+ fe->reason() == QFocusEvent::Shortcut ) {
+ // L0614: A widget in the embedded client was just given the Qt focus.
+ // Variable `obeyFocus' suggests that this is the result of mouse
+ // activity in the client. The XEMBED_REQUEST_FOCUS message causes
+ // the embedding widget to take the Qt focus (L2085).
+ WId window = ((QPublicWidget*)qApp->focusWidget()->topLevelWidget())->topData()->parentWinId;
+ focusMap->remove( qApp->focusWidget()->topLevelWidget() );
+ sendXEmbedMessage( window, XEMBED_REQUEST_FOCUS );
+ } else if ( fe->reason() == QFocusEvent::ActiveWindow ) {
+ // L0615: Both the embedder and the embedded client became active.
+ // But we do not know whether the QXEmbed widget has the Qt focus.
+ // So we clear the Qt focus for now. If indeed the QXEmbed widget
+ // has the focus, it will receive a FocusIn message (L1530) and
+ // tell us to restore the focus (L0680, L0683).
+ focusMap->remove( qApp->focusWidget()->topLevelWidget() );
+ focusMap->insert( qApp->focusWidget()->topLevelWidget(),
+ new QGuardedPtr<QWidget>(qApp->focusWidget()->topLevelWidget()->focusWidget() ) );
+ // L0616: qApp->focusWidget() might belong to a modal dialog and not be
+ // equal to qApp->focusWidget()->topLevelWidget()->focusWidget() !
+ qApp->focusWidget()->clearFocus();
+ // L0617: ??? [why not {obeyFocus=false; return true;} here?]
+ }
+ obeyFocus = false;
+ }
+ break;
+ case QEvent::KeyPress:
+ if (qApp->focusWidget() == o &&
+ ((QPublicWidget*)qApp->focusWidget()->topLevelWidget())->topData()->embedded ) {
+ // L0620: The following code replaces the Qt code that
+ // handles focus focus changes with the tab key. See the
+ // XEMBED specification for details. The keypress event
+ // arrives here after an interesting itinerary. It is first
+ // saved in the embedding application (L0660). After being
+ // rejected for tab navigation in the embedding application
+ // (L1901), it gets forwarded to the embedded client
+ // (L1400) and arrives here. Depending on the status of
+ // the tab chain in the embedded client, focus navigation
+ // messages are sent back to the embedding application
+ // (L0653, L0654) which then performs tab navigation
+ // (L2081).
+ QKeyEvent *k = (QKeyEvent *)e;
+ QWidget *w = qApp->focusWidget();
+ // L0621: The following tests are copied from QWidget::event().
+ bool res = false;
+ bool tabForward = true;
+ if ( !(k->state() & ControlButton || k->state() & AltButton) ) {
+ if ( k->key() == Key_Backtab || (k->key() == Key_Tab && (k->state() & ShiftButton)) ) {
+ QFocusEvent::setReason( QFocusEvent::Backtab );
+ res = ((QPublicWidget*)w)->focusNextPrev( tabForward = false );
+ QFocusEvent::resetReason();
+ } else if ( k->key() == Key_Tab ) {
+ QFocusEvent::setReason( QFocusEvent::Tab );
+ res = ((QPublicWidget*)w)->focusNextPrev( tabForward = true );
+ QFocusEvent::resetReason();
+ }
+ }
+ if (res) {
+ // L0625: We changed the focus because of tab/backtab key
+ // Now check whether we have been looping around.
+ QFocusData *fd = ((QPublicWidget*)w)->focusData();
+ WId window = ((QPublicWidget*)w->topLevelWidget())->topData()->parentWinId;
+ QWidget *cw = 0;
+ QWidget *fw = fd->home();
+ if (tabForward && window) {
+ while (cw != w && cw != fw && cw != w->topLevelWidget())
+ cw = fd->prev();
+ if (cw != w)
+ sendXEmbedMessage( window, XEMBED_FOCUS_NEXT );
+ } else if (window) {
+ while (cw != w && cw != fw && cw != w->topLevelWidget())
+ cw = fd->next();
+ if (cw != w)
+ sendXEmbedMessage( window, XEMBED_FOCUS_PREV );
+ }
+ // L0628: Qt should no longer process this event.
+ return true;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ // L0640: Application gets to see the events anyway.
+ return false;
+}
+
+// L0650: This filter receives all XEvents in both the client and the embedder.
+// Most of it involves the embedded client (except L0660, L0671).
+static int qxembed_x11_event_filter( XEvent* e)
+{
+ switch ( e->type ) {
+ case XKeyPress:
+ case XKeyRelease: {
+ // L0660: This is for the embedding side (L1450).
+ last_key_event = e->xkey;
+ break;
+ }
+ case ClientMessage:
+ if ( e->xclient.message_type == xembed ) {
+ // L0670: This is where the XEmbed messages are
+ // processed on the client side.
+ Time msgtime = (Time) e->xclient.data.l[0];
+ long message = e->xclient.data.l[1];
+ long detail = e->xclient.data.l[2];
+ // L0671: Keep Qt message time up to date
+ if ( msgtime > qt_x_time )
+ qt_x_time = msgtime;
+ QWidget* w = QWidget::find( e->xclient.window );
+ if ( !w )
+ break;
+ switch ( message) {
+ case XEMBED_EMBEDDED_NOTIFY: {
+ // L0675: We just have been embedded into a XEMBED aware widget.
+ QTLWExtra *extra = ((QPublicWidget*)w->topLevelWidget())->topData();
+ extra->embedded = 1;
+ extra->parentWinId = e->xclient.data.l[3];
+ w->topLevelWidget()->show();
+ break;
+ }
+ case XEMBED_WINDOW_ACTIVATE: {
+ // L0676: Embedding window becomes active. Send a fake XFocusIn
+ // to convince Qt that we are active as well. Qt will send
+ // us a focus notification (L0615) that we will intercept to
+ // ensure that we have no Qt focus widget yet. The Qt focus
+ // widget might later be set in L0680.
+ XEvent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.xfocus.display = qt_xdisplay();
+ ev.xfocus.type = XFocusIn;
+ ev.xfocus.window = w->topLevelWidget()->winId();
+ ev.xfocus.mode = NotifyNormal;
+ ev.xfocus.detail = NotifyAncestor;
+ qApp->x11ProcessEvent( &ev );
+ }
+ break;
+ case XEMBED_WINDOW_DEACTIVATE: {
+ // L0677: Embedding window becomes inactive. Send a fake XFocusOut
+ // event to convince Qt that we no longer are active. We will
+ // receive extra Qt FocusOut events but we do not care.
+ XEvent ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.xfocus.display = qt_xdisplay();
+ ev.xfocus.type = XFocusOut;
+ ev.xfocus.window = w->topLevelWidget()->winId();
+ ev.xfocus.mode = NotifyNormal;
+ ev.xfocus.detail = NotifyAncestor;
+ qApp->x11ProcessEvent( &ev );
+ }
+ break;
+ case XEMBED_FOCUS_IN:
+ // L0680: Embedding application gives us the focus.
+ {
+ // L0681: Search saved focus widget.
+ QWidget* focusCurrent = 0;
+ QGuardedPtr<QWidget>* fw = focusMap->find( w->topLevelWidget() );
+ if ( fw ) {
+ focusCurrent = *fw;
+ // L0682: Remove it from the map
+ focusMap->remove( w->topLevelWidget() );
+ }
+ switch ( detail ) {
+ case XEMBED_FOCUS_CURRENT:
+ // L0683: Set focus on saved focus widget
+ if ( focusCurrent )
+ focusCurrent->setFocus();
+ else if ( !w->topLevelWidget()->focusWidget() )
+ w->topLevelWidget()->setFocus();
+ break;
+ case XEMBED_FOCUS_FIRST:
+ {
+ // L0684: Search first widget in tab chain
+ QFocusEvent::setReason( QFocusEvent::Tab );
+ w->topLevelWidget()->setFocus();
+ ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(true);
+ QFocusEvent::resetReason();
+ }
+ break;
+ case XEMBED_FOCUS_LAST:
+ {
+ // L0686: Search last widget in tab chain
+ QFocusEvent::setReason( QFocusEvent::Backtab );
+ w->topLevelWidget()->setFocus();
+ ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(false);
+ QFocusEvent::resetReason();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case XEMBED_FOCUS_OUT:
+ // L0688: Embedding application takes the focus away
+ // We first record what the focus widget was
+ // and clear the Qt focus.
+ if ( w->topLevelWidget()->focusWidget() ) {
+ focusMap->insert( w->topLevelWidget(),
+ new QGuardedPtr<QWidget>(w->topLevelWidget()->focusWidget() ) );
+ w->topLevelWidget()->focusWidget()->clearFocus();
+ }
+ break;
+ default:
+ break;
+ }
+ } else if ( e->xclient.format == 32 && e->xclient.message_type ) {
+ if ( e->xclient.message_type == qt_wm_protocols ) {
+ QWidget* w = QWidget::find( e->xclient.window );
+ if ( !w )
+ break;
+ // L0690: This is for the embedding side!
+ // See L0902 for more information about the focus proxy.
+ // Window manager may send WM_TAKE_FOCUS messages to the
+ // embedding application to indicate that it becomes active.
+ // But this also suggests that the window manager has
+ // changed the X11 focus. We want to make sure it goes
+ // to the focus proxy window eventually.
+ Atom a = e->xclient.data.l[0];
+ if ( a == qt_wm_take_focus ) {
+ // L0695: update Qt message time variable
+ if ( (ulong) e->xclient.data.l[1] > qt_x_time )
+ qt_x_time = e->xclient.data.l[1];
+ // L0696: There is no problem when the window is not active.
+ // Qt will generate a WindowActivate event that will
+ // do the job (L1310). This does not happen if the
+ // window is already active. So we simulate it.
+ if ( w->isActiveWindow() ) {
+ QEvent e( QEvent::WindowActivate );
+ QApplication::sendEvent( w, &e );
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ // L0698: The next x11 filter
+ if ( oldFilter )
+ return oldFilter( e );
+ // L0699: Otherwise process the event as usual.
+ return false;
+}
+
+
+
+// L0700: Install the xembed filters in both client and embedder sides.
+// This function is called automatically when using
+// embedClientIntoWindow() or creating an instance of QXEmbed You may
+// have to call it manually for a client when using embedder-side
+// embedding, though.
+void QXEmbed::initialize()
+{
+ static bool is_initialized = false;
+ if ( is_initialized )
+ return;
+
+ // L0710: Atom used by the XEMBED protocol.
+ xembed = XInternAtom( qt_xdisplay(), "_XEMBED", false );
+ // L0720: Install low level filter for X11 events (L0650)
+ oldFilter = qt_set_x11_event_filter( qxembed_x11_event_filter );
+ // L0730: See L0610 for an explanation about focusMap.
+ focusMap = new QPtrDict<QGuardedPtr<QWidget> >;
+ focusMap->setAutoDelete( true );
+ // L0740: Create client side application wide event filter (L0610)
+ filter = new QXEmbedAppFilter;
+
+ is_initialized = true;
+}
+
+
+
+
+
+// ------------------------------------------------------------
+// L0800: MOST OF WHAT FOLLOWS CONCERNS THE EMBEDDER SIDE.
+// Things that happen inside a Qt application that contain
+// a QXEmbed widget for embedding other applications.
+// This applies to both the XEMBED and XPLAIN protocols.
+// Deviations are commented below.
+
+
+
+// L0810: Class QXEmbed.
+// A QXEmbed widget serves as an embedder that can manage one single
+// embedded X-window. These so-called client windows can be arbitrary
+// Qt or non Qt applications. There are two different ways of using
+// QXEmbed, from the client side or from the embedder's side.
+
+
+// L0900: Constructs a xembed widget.
+QXEmbed::QXEmbed(QWidget *parent, const char *name, WFlags f)
+ : QWidget(parent, name, f)
+{
+ // L0901: Create private data. See L0100.
+ d = new QXEmbedData;
+ // L0902: Create focus proxy widget. See XEmbed specification.
+ // Each QXEmbed widget has a focus proxy window. Every single
+ // QXEmbed widget tries to force its focus proxy window onto the
+ // whole embedding application. They compete between themselves and
+ // against Qt (L0690, L0914, L1040, L1310, L1510, L1580).
+ // This would be much simpler if implemented within Qt.
+ d->focusProxy = new QWidget( topLevelWidget(), "xembed_focus" );
+ d->focusProxy->setGeometry( -1, -1, 1, 1 );
+ d->focusProxy->show();
+ // make sure it's shown - for XSetInputFocus
+ QApplication::sendPostedEvents( d->focusProxy, 0 );
+ // L0903: Install the client side event filters
+ // because they also provide services for the embedder side
+ // See L0660, L0671, L0685.
+ initialize();
+ window = 0;
+ setFocusPolicy(StrongFocus);
+ setKeyCompression( false );
+
+ // L0910: Trick Qt to create extraData();
+ (void) topData();
+
+ // L0912: We are mostly interested in SubstructureNotify
+ // This is sent when something happens to the children of
+ // the X11 window associated with the QXEmbed widget.
+ XSelectInput(qt_xdisplay(), winId(),
+ KeyPressMask | KeyReleaseMask |
+ ButtonPressMask | ButtonReleaseMask |
+ KeymapStateMask |
+ ButtonMotionMask |
+ PointerMotionMask | // may need this, too
+ EnterWindowMask | LeaveWindowMask |
+ FocusChangeMask |
+ ExposureMask |
+ StructureNotifyMask |
+ SubstructureRedirectMask |
+ SubstructureNotifyMask
+ );
+ // L0913: all application events pass through eventFilter().
+ // This is mostly used to force the X11 focus on the
+ // proxy focus window. See L1300.
+ topLevelWidget()->installEventFilter( this );
+ qApp->installEventFilter( this );
+
+ // L0914: Start moving the X11 focus on the focus proxy window.
+ // See L1581 to know why we do not use isActiveWindow().
+ if ( qApp->activeWindow() == topLevelWidget() )
+ if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
+ XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(),
+ RevertToParent, qt_x_time );
+ // L0915: ??? [drag&drop?]
+ setAcceptDrops( true );
+}
+
+// L1000: Destructor must dispose of the embedded client window.
+QXEmbed::~QXEmbed()
+{
+ // L1010: Make sure no pointer grab is left.
+ if ( d && d->xgrab)
+ XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() );
+ if ( window && ( autoDelete() || !d->xplain ))
+ {
+ // L1021: Hide the window and safely reparent it into the root,
+ // otherwise it would be destroyed by X11 together
+ // with this QXEmbed's window.
+#if 0
+// TODO: The proper XEmbed way would be to unmap the window, and the embedded
+// app would detect the embedding has ended, and do whatever it finds appropriate.
+// However, QXEmbed currently doesn't provide support for this detection,
+// so for the time being, it's better to leave the window mapped as toplevel window.
+// This will be ever more complicated with the systray windows, as the simple API
+// for them (KWin::setSystemTrayWindowFor()) doesn't make it possible to detect
+// themselves they have been released from systray, but KWin requires them
+// to be visible to allow next Kicker instance to swallow them.
+// See also below the L1022 comment.
+// XUnmapWindow( qt_xdisplay(), window );
+#else
+ if( autoDelete())
+ XUnmapWindow( qt_xdisplay(), window );
+#endif
+ XReparentWindow(qt_xdisplay(), window, qt_xrootwin(), 0, 0);
+ if( !d->xplain )
+ XRemoveFromSaveSet( qt_xdisplay(), window );
+ if( d->mapAfterRelease )
+ XMapWindow( qt_xdisplay(), window );
+ XSync(qt_xdisplay(), false);
+ // L1022: Send the WM_DELETE_WINDOW message
+ if( autoDelete() /*&& d->xplain*/ )
+ // This sendDelete should only apply to XPLAIN.
+ // XEMBED apps are supposed to detect when the embedding ends.
+ // ??? [We do not do this detection yet!
+ // So we sendDelete() instead.]
+ sendDelete();
+ }
+ window = 0;
+ // L01040: Our focus proxy window will be destroyed as well.
+ // Make sure that the X11 focus is not lost in the process.
+ Window focus;
+ int revert;
+ XGetInputFocus( qt_xdisplay(), &focus, &revert );
+ if( focus == d->focusProxy->winId())
+ XSetInputFocus( qt_xdisplay(), topLevelWidget()->winId(), RevertToParent, qt_x_time );
+ // L01045: Delete our private data.
+ delete d;
+}
+
+
+// L1050: Sends a WM_DELETE_WINDOW message to the embedded window. This is
+// what typically happens when you click on the close button of a
+// window manager decoration.
+void QXEmbed::sendDelete( void )
+{
+ if (window)
+ {
+ sendClientMessage(window, qt_wm_protocols, qt_wm_delete_window);
+ XFlush( qt_xdisplay() );
+ }
+}
+
+// L1100: Sets the protocol used for embedding windows.
+// This function must be called before embedding a window.
+// Protocol XEMBED provides maximal functionality (focus, tabs, etc)
+// but requires explicit cooperation from the embedded window.
+// Protocol XPLAIN provides maximal compatibility with
+// embedded applications that do not support the XEMBED protocol.
+// The default is XEMBED.
+void QXEmbed::setProtocol( Protocol proto )
+{
+ if (!window) {
+ d->xplain = false;
+ if (proto == XPLAIN)
+ d->xplain = true;
+ }
+}
+
+// L1150: Returns the protocol used for embedding the current window.
+QXEmbed::Protocol QXEmbed::protocol()
+{
+ if (d->xplain)
+ return XPLAIN;
+ return XEMBED;
+}
+
+
+// L1200: QXEmbed widget size changes: resize embedded window.
+void QXEmbed::resizeEvent(QResizeEvent*)
+{
+ if (window)
+ XResizeWindow(qt_xdisplay(), window, width(), height());
+}
+
+// L1250: QXEmbed widget is shown: make sure embedded window is visible.
+void QXEmbed::showEvent(QShowEvent*)
+{
+ if (window)
+ XMapRaised(qt_xdisplay(), window);
+}
+
+
+// L1300: This event filter sees all application events (L0913).
+bool QXEmbed::eventFilter( QObject *o, QEvent * e)
+{
+
+ switch ( e->type() ) {
+ case QEvent::WindowActivate:
+ if ( o == topLevelWidget() ) {
+ // L1310: Qt thinks the application window has just been activated.
+ // Make sure the X11 focus is on the focus proxy window. See L0686.
+ if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
+ if (! hasFocus() )
+ XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(),
+ RevertToParent, qt_x_time );
+ if (d->xplain)
+ // L1311: Activation has changed. Grab state might change. See L2800.
+ checkGrab();
+ else
+ // L1312: Let the client know that we just became active
+ sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE );
+ }
+ break;
+ case QEvent::WindowDeactivate:
+ if ( o == topLevelWidget() ) {
+ if (d->xplain)
+ // L1321: Activation has changed. Grab state might change. See L2800.
+ checkGrab();
+ else
+ // L1322: Let the client know that we are no longer active
+ sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE );
+ }
+ break;
+ case QEvent::Move:
+ {
+ QWidget* pos = this;
+ while( pos != o && pos != topLevelWidget())
+ pos = pos->parentWidget();
+ if( pos == o ) {
+ // L1390: Send fake configure notify events whenever the
+ // global position of the client changes. See L2900.
+ QPoint globalPos = mapToGlobal(QPoint(0,0));
+ if (globalPos != d->lastPos) {
+ d->lastPos = globalPos;
+ sendSyntheticConfigureNotifyEvent();
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+// L1350: ??? [why this?]
+bool QXEmbed::event( QEvent * e)
+{
+ return QWidget::event( e );
+}
+
+// L1400: Forward keypress event to the client
+// Receiving a Qt key event indicates that
+// the QXEmbed object has the Qt focus.
+// The X11 event that caused the Qt key event
+// must be forwarded to the client.
+// See L0660.
+void QXEmbed::keyPressEvent( QKeyEvent *)
+{
+ if (!window)
+ return;
+ last_key_event.window = window;
+ XSendEvent(qt_xdisplay(), window, false, KeyPressMask, (XEvent*)&last_key_event);
+
+}
+
+// L1450: Forward keyrelease event to the client.
+// See comment L1400.
+void QXEmbed::keyReleaseEvent( QKeyEvent *)
+{
+ if (!window)
+ return;
+ last_key_event.window = window;
+ XSendEvent(qt_xdisplay(), window, false, KeyReleaseMask, (XEvent*)&last_key_event);
+}
+
+// L1500: Handle Qt focus in event.
+void QXEmbed::focusInEvent( QFocusEvent * e ){
+ if (!window)
+ return;
+ // L1510: This is a good time to set the X11 focus on the focus proxy window.
+ // Except if the the embedding application itself is embedded into another.
+ if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
+ if ( qApp->activeWindow() == topLevelWidget() )
+ // L1511: Alter X focus only when window is active.
+ // This is dual safety here because FocusIn implies this.
+ // But see L1581 for an example where this really matters.
+ XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(),
+ RevertToParent, qt_x_time );
+ if (d->xplain) {
+ // L1520: Qt focus has changed. Grab state might change. See L2800.
+ checkGrab();
+ // L1521: Window managers activate applications by setting the X11 focus.
+ // We cannot do this (see L1510) but we can send a fake focus event
+ // and forward the X11 key events ourselves (see L1400, L1450).
+ sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
+ } else {
+ // L1530: No need for fake events with XEMBED.
+ // Just inform the client. It knows what to do.
+ int detail = XEMBED_FOCUS_CURRENT;
+ // L1531: When the focus change is caused by the tab key,
+ // the client must select the first (or last) widget of
+ // its own tab chain.
+ if ( e->reason() == QFocusEvent::Tab )
+ detail = XEMBED_FOCUS_FIRST;
+ else if ( e->reason() == QFocusEvent::Backtab )
+ detail = XEMBED_FOCUS_LAST;
+ sendXEmbedMessage( window, XEMBED_FOCUS_IN, detail);
+ }
+}
+
+// L1550: Handle Qt focus out event.
+void QXEmbed::focusOutEvent( QFocusEvent * ){
+ if (!window)
+ return;
+ if (d->xplain) {
+ // L1560: Qt focus has changed. Grab state might change. See L2800.
+ checkGrab();
+ // L1561: Send fake focus out message. See L1521.
+ sendFocusMessage(window, XFocusOut, NotifyNormal, NotifyPointer );
+ } else {
+ // L1570: Send XEMBED focus out message. See L1531.
+ sendXEmbedMessage( window, XEMBED_FOCUS_OUT );
+ }
+ // L1580: The QXEmbed object might loose the focus because its
+ // toplevel window looses the X11 focus and is no longer active,
+ // or simply because the Qt focus has been moved to another widget.
+ // In the latter case only, we want to make sure that the X11 focus
+ // is properly set to the X11 focus widget. We do this because
+ // the client application might have moved the X11 focus after
+ // receiving the fake focus messages.
+ if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
+ if ( qApp->activeWindow() == topLevelWidget() )
+ // L1581: Alter X focus only when window is active.
+ // The test above is not the same as isActiveWindow().
+ // Function isActiveWindow() also returns true when a modal
+ // dialog child of this window is active.
+ XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(),
+ RevertToParent, qt_x_time );
+}
+
+
+// L1600: Helper for QXEmbed::embed()
+// Check whether a window is in withdrawn state.
+static bool wstate_withdrawn( WId winid )
+{
+ Atom type;
+ int format;
+ unsigned long length, after;
+ unsigned char *data;
+ int r = XGetWindowProperty( qt_xdisplay(), winid, qt_wm_state, 0, 2,
+ false, AnyPropertyType, &type, &format,
+ &length, &after, &data );
+ bool withdrawn = true;
+ // L1610: Non managed windows have no WM_STATE property.
+ // Returning true ensures that the loop L1711 stops.
+ if ( r == Success && data && format == 32 ) {
+ Q_UINT32 *wstate = (Q_UINT32*)data;
+ withdrawn = (*wstate == WithdrawnState );
+ XFree( (char *)data );
+ }
+ return withdrawn;
+}
+
+// L1650: Helper for QXEmbed::embed()
+// Get the X11 id of the parent window.
+static int get_parent(WId winid, Window *out_parent)
+{
+ Window root, *children=0;
+ unsigned int nchildren;
+ int st = XQueryTree(qt_xdisplay(), winid, &root, out_parent, &children, &nchildren);
+ if (st && children)
+ XFree(children);
+ return st;
+}
+
+// L1700: Embeds the window w into this QXEmbed widget.
+// See doc in qxembed.h.
+void QXEmbed::embed(WId w)
+{
+ kdDebug() << "*** Embed " << w << " into " << winId() << ". window=" << window << endl;
+ if (!w)
+ return;
+ // L1701: The has_window variable prevents embedding a same window twice.
+ // ??? [what happens if one embed two windows into the same QXEmbed?]
+ bool has_window = (w == window);
+ window = w;
+ if ( !has_window ) {
+ KXErrorHandler errhandler; // make X BadWindow errors silent
+ // L1710: Try hard to withdraw the window.
+ // This makes sure that the window manager will
+ // no longer try to manage this window.
+ if ( !wstate_withdrawn(window) ) {
+ XWithdrawWindow(qt_xdisplay(), window, qt_xscreen());
+ QApplication::flushX();
+ // L1711: See L1610
+ for (int i=0; i < 10000; ++i) {
+ if (wstate_withdrawn(window)) {
+ Window parent = 0;
+ get_parent(w, &parent);
+ if (parent == qt_xrootwin()) break;
+ }
+ USLEEP(1000);
+ }
+ }
+ // L1710: It would be sufficient in principle to reparent
+ // window w into winId(). Everything else happens in L2020.
+ // The following code might be useful when the X11 server takes
+ // time to create the embedded application main window.
+ Window parent = 0;
+ get_parent(w, &parent);
+ kdDebug() << QString("> before reparent: parent=0x%1").arg(parent,0,16) << endl;
+ for (int i = 0; i < 50; i++) {
+ // this is done once more when finishing embedding, but it's done also here
+ // just in case we crash before reaching that place
+ if( !d->xplain )
+ XAddToSaveSet( qt_xdisplay(), w );
+ XReparentWindow(qt_xdisplay(), w, winId(), 0, 0);
+ if (get_parent(w, &parent) && parent == winId()) {
+ kdDebug() << QString("> Loop %1: ").arg(i)
+ << QString("> reparent of 0x%1").arg(w,0,16)
+ << QString(" into 0x%1").arg(winId(),0,16)
+ << QString(" successful") << endl;
+ break;
+ }
+ kdDebug() << QString("> Loop %1: ").arg(i)
+ << QString("> reparent of 0x%1").arg(w,0,16)
+ << QString(" into 0x%1").arg(winId(),0,16)
+ << QString(" failed") << endl;
+ USLEEP(1000);
+ }
+ if( parent != winId()) // failed
+ window = 0;
+ }
+}
+
+// When a window is reparented into QXEmbed (or created inside of it), this function
+// sets up the actual embedding.
+void QXEmbed::handleEmbed()
+{
+ // only XEMBED apps can survive crash,
+ // see http://lists.kde.org/?l=kfm-devel&m=106752026501968&w=2
+ if( !d->xplain )
+ XAddToSaveSet( qt_xdisplay(), window );
+ XResizeWindow(qt_xdisplay(), window, width(), height());
+ XMapRaised(qt_xdisplay(), window);
+ // L2024: see L2900.
+ sendSyntheticConfigureNotifyEvent();
+ // L2025: ??? [any idea about drag&drop?]
+ extraData()->xDndProxy = window;
+ if ( parent() ) {
+ // L2030: embedded window might have new size requirements.
+ // see L2500, L2520, L2550.
+ QEvent * layoutHint = new QEvent( QEvent::LayoutHint );
+ QApplication::postEvent( parent(), layoutHint );
+ }
+ windowChanged( window );
+ if (d->xplain) {
+ // L2040: Activation has changed. Grab state might change. See L2800.
+ checkGrab();
+ if ( hasFocus() )
+ // L2041: Send fake focus message to inform the client. See L1521.
+ sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
+ } else {
+ // L2050: Send XEMBED messages (see L0670, L1312, L1322, L1530)
+ sendXEmbedMessage( window, XEMBED_EMBEDDED_NOTIFY, 0, (long) winId() );
+ if (isActiveWindow())
+ sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE);
+ else
+ sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE);
+ if ( hasFocus() )
+ sendXEmbedMessage( window, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT );
+ }
+}
+
+// L1800: Returns the window identifier of the embedded window
+WId QXEmbed::embeddedWinId() const
+{
+ return window;
+}
+
+
+// L1900: Control Qt tab focus management.
+// See Qt documentation.
+bool QXEmbed::focusNextPrevChild( bool next )
+{
+ if ( window )
+ // L1901: Return false when there is an embedded window
+ // When the user presses TAB, Qt will not change
+ // the focus and pass the TAB key events to the QXEmbed widget.
+ // These key events will be forwarded to the client (L1400, L1450)
+ // who eventually will manage the tab focus (L0620) and possible
+ // instruct us to call QWidget::focusNextPrevChild (L2081).
+ return false;
+ else
+ // L1920: Default behavior otherwise.
+ return QWidget::focusNextPrevChild( next );
+}
+
+
+// L2000: Filter for X11 events sent to the QXEmbed window.
+bool QXEmbed::x11Event( XEvent* e)
+{
+ switch ( e->type ) {
+ case DestroyNotify:
+ if ( e->xdestroywindow.window == window ) {
+ // L2005: Client window is being destroyed.
+ window = 0;
+ windowChanged( window );
+ emit embeddedWindowDestroyed();
+ }
+ break;
+ case CreateNotify:
+ // A window was created inside of QXEmbed, handle it as embedded
+ if( window == 0 ) { // only one window
+ window = e->xcreatewindow.window;
+ handleEmbed();
+ }
+ break;
+ case ReparentNotify:
+ if ( e->xreparent.window == d->focusProxy->winId() )
+ break; // ignore proxy
+ if ( window && e->xreparent.window == window &&
+ e->xreparent.parent != winId() ) {
+ // L2010: We lost the window
+ window = 0;
+ windowChanged( window );
+ emit embeddedWindowDestroyed();
+ // L2011: Remove window from save set
+ // ??? [not sure it is good to touch this window since
+ // someone else has taken control of it already.]
+ if( !d->xplain )
+ XRemoveFromSaveSet( qt_xdisplay(), window );
+ } else if ( e->xreparent.parent == winId()){
+ if( window == 0 ) // something started embedding from the outside
+ window = e->xreparent.window;
+ // L2020: We got a window. Complete the embedding process.
+ if( e->xreparent.window == window )
+ handleEmbed();
+ }
+ break;
+ case ButtonPress:
+ if (d->xplain && d->xgrab) {
+ // L2060: The passive grab has intercepted a mouse click
+ // in the embedded client window. Take the focus.
+ QFocusEvent::setReason( QFocusEvent::Mouse );
+ setFocus();
+ QFocusEvent::resetReason();
+ // L2064: Resume X11 event processing.
+ XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime);
+ // L2065: Qt should not know about this.
+ return true;
+ }
+ break;
+ case ButtonRelease:
+ if (d->xplain && d->xgrab) {
+ // L2064: Resume X11 event processing after passive grab (see L2060)
+ XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime);
+ return true;
+ }
+ break;
+ case MapRequest:
+ // L2070: Behave like a window manager.
+ if ( window && e->xmaprequest.window == window )
+ XMapRaised(qt_xdisplay(), window );
+ break;
+ case ClientMessage:
+ // L2080: This is where the QXEmbed object receives XEMBED
+ // messaged from the client application.
+ if ( e->xclient.format == 32 && e->xclient.message_type == xembed ) {
+ long message = e->xclient.data.l[1];
+ switch ( message ) {
+ // L2081: Tab focus management. It is very important to call the
+ // focusNextPrevChild() defined by QWidget (not QXEmbed).
+ // See L1901.
+ case XEMBED_FOCUS_NEXT:
+ QWidget::focusNextPrevChild( true );
+ break;
+ case XEMBED_FOCUS_PREV:
+ QWidget::focusNextPrevChild( false );
+ break;
+ // L2085: The client asks for the focus.
+ case XEMBED_REQUEST_FOCUS:
+ if( ((QPublicWidget*)topLevelWidget())->topData()->embedded ) {
+ WId window = ((QPublicWidget*)topLevelWidget())->topData()->parentWinId;
+ sendXEmbedMessage( window, XEMBED_REQUEST_FOCUS );
+ } else {
+ QFocusEvent::setReason( QFocusEvent::Mouse );
+ setFocus();
+ QFocusEvent::resetReason();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case ConfigureRequest:
+ // L2090: Client wants to change its geometry.
+ // Just inform it that nothing has changed.
+ if (e->xconfigurerequest.window == window)
+ {
+ sendSyntheticConfigureNotifyEvent();
+ }
+ break;
+ case MotionNotify:
+ // fall through, workaround for Qt 3.0 < 3.0.3
+ case EnterNotify:
+ // L2095: See L2200.
+ if ( QWhatsThis::inWhatsThisMode() )
+ enterWhatsThisMode();
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+
+// L2200: Try to handle Qt's "what's this" mode. Broken.
+// "temporary, fix in Qt (Matthias, Mon Jul 17 15:20:55 CEST 2000"
+void QXEmbed::enterWhatsThisMode()
+{
+ // L2210: When the what-s-this pointer enters the embedded window (L2095)
+ // cancel what-s-this mode, and use a non stantard _NET_WM_ message
+ // to instruct the embedded client to enter the "what's this" mode.
+ // This works only one way...
+ QWhatsThis::leaveWhatsThisMode();
+ if ( !context_help )
+ context_help = XInternAtom( x11Display(), "_NET_WM_CONTEXT_HELP", false );
+ sendClientMessage(window , qt_wm_protocols, context_help );
+}
+
+
+// L2300: indicates that the embedded window has been changed.
+void QXEmbed::windowChanged( WId )
+{
+}
+
+
+// L2400: Utility function for clients that embed themselves.
+// This is client side code.
+bool QXEmbed::processClientCmdline( QWidget* client, int& argc, char ** argv )
+{
+ int myargc = argc;
+ WId window = 0;
+ int i, j;
+
+ j = 1;
+ for ( i=1; i<myargc; i++ ) {
+ if ( argv[i] && *argv[i] != '-' ) {
+ argv[j++] = argv[i];
+ continue;
+ }
+ QCString arg = argv[i];
+ if ( !strcmp(arg,"-embed") && i < myargc-1 ) {
+ QCString s = argv[++i];
+ window = s.toInt();
+ } else
+ argv[j++] = argv[i];
+ }
+ argc = j;
+
+ if ( window ) {
+ embedClientIntoWindow( client, window );
+ return true;
+ }
+
+ return false;
+}
+
+
+// L2450: Utility function for clients that embed themselves.
+// This is client side code.
+void QXEmbed::embedClientIntoWindow(QWidget* client, WId window)
+{
+ initialize();
+ XReparentWindow(qt_xdisplay(), client->winId(), window, 0, 0);
+ // L2451: These two lines are redundant. See L0680.
+ ((QXEmbed*)client)->topData()->embedded = true;
+ ((QXEmbed*)client)->topData()->parentWinId = window;
+ // L2452: This seems redundant because L2020 maps the window.
+ // But calling show() might also set Qt internal flags.
+ client->show();
+}
+
+
+
+// L2500: Specifies that this widget can use additional space,
+// and that it can survive on less than sizeHint().
+QSizePolicy QXEmbed::sizePolicy() const
+{
+ return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
+}
+
+
+// L2520: Returns a size sufficient for the embedded window
+QSize QXEmbed::sizeHint() const
+{
+ return minimumSizeHint();
+}
+
+// L2550: Returns the minimum size specified by the embedded window.
+QSize QXEmbed::minimumSizeHint() const
+{
+ int minw = 0;
+ int minh = 0;
+ if ( window ) {
+ XSizeHints size;
+ long msize;
+ if (XGetWMNormalHints(qt_xdisplay(), window, &size, &msize)
+ && ( size.flags & PMinSize) ) {
+ minw = size.min_width;
+ minh = size.min_height;
+ }
+ }
+
+ return QSize( minw, minh );
+}
+
+// L2600: Tells what shoud be done with the embedded window when
+// the embedding window is destroyed.
+void QXEmbed::setAutoDelete( bool b)
+{
+ d->autoDelete = b;
+}
+
+// L2650: See L2600.
+bool QXEmbed::autoDelete() const
+{
+ return d->autoDelete;
+}
+
+// L2700: See L2200.
+bool QXEmbed::customWhatsThis() const
+{
+ return true;
+}
+
+// L2800: When using the XPLAIN protocol, this function maintains
+// a passive button grab when (1) the application is active
+// and (2) the Qt focus is not on the QXEmbed. This passive
+// grab intercepts button clicks in the client window and
+// give us chance to request the Qt focus (L2060).
+void QXEmbed::checkGrab()
+{
+ if (d->xplain && isActiveWindow() && !hasFocus()) {
+ if (! d->xgrab)
+ XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, winId(),
+ false, ButtonPressMask, GrabModeSync, GrabModeAsync,
+ None, None );
+ d->xgrab = true;
+ } else {
+ if (d->xgrab)
+ XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() );
+ d->xgrab = false;
+ }
+}
+
+// L2900: This sends fake configure notify events to inform
+// the client about its window geometry. See L1390, L2024 and L2090.
+void QXEmbed::sendSyntheticConfigureNotifyEvent()
+{
+ // L2910: It seems that the x and y coordinates are global.
+ // But this is what ICCCM section 4.1.5 wants.
+ // See http://lists.kde.org/?l=kfm-devel&m=107090222032378
+ QPoint globalPos = mapToGlobal(QPoint(0,0));
+ if (window) {
+#if 0
+ XConfigureEvent c;
+ memset(&c, 0, sizeof(c));
+ c.type = ConfigureNotify;
+ c.display = qt_xdisplay();
+ c.send_event = True;
+ c.event = window;
+ c.window = window;
+ c.x = globalPos.x();
+ c.y = globalPos.y();
+ c.width = width();
+ c.height = height();
+ c.border_width = 0;
+ c.above = None;
+ c.override_redirect = 0;
+ XSendEvent( qt_xdisplay(), c.event, true, StructureNotifyMask, (XEvent*)&c );
+#endif
+ // Yes, this doesn't make sense at all. See the commit message.
+ XSetWindowBorderWidth( qt_xdisplay(), window, 1 );
+ XSetWindowBorderWidth( qt_xdisplay(), window, 0 );
+ }
+}
+
+// L3000: One should not call QWidget::reparent after embedding a window.
+void QXEmbed::reparent( QWidget * parent, WFlags f, const QPoint & p, bool showIt )
+{
+ // QWidget::reparent() destroys the old X Window for the widget, and
+ // creates a new one, thus QXEmbed after reparenting is no longer the
+ // parent of the embedded window. I think reparenting of QXEmbed can be
+ // done only by a mistake, so just complain.
+ Q_ASSERT( !window );
+ QWidget::reparent( parent, f, p, showIt );
+}
+
+// for KDE
+#include "qxembed.moc"
+#endif // Q_WS_X11