/****************************************************************************
    Implementation of QXEmbedCopy 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 QXEmbedCopy.  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:
//    - QXEmbedCopy 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: QXEmbedCopy 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 "qxembedcopy.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 QXEmbedCopy
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 QXEmbedCopy object.
//        This belongs to the embedder side.
class QXEmbedCopyData
{
public:
    QXEmbedCopyData(){ 
        autoDelete = true;
        xplain = false;
        xgrab = false;
        mapAfterRelease = false;
        lastPos = QPoint(0,0);
    }
    ~QXEmbedCopyData(){};

    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 QXEmbedCopyAppFilter : public QObject
    {
    public:
        QXEmbedCopyAppFilter()  { qApp->installEventFilter( this ); } 
        ~QXEmbedCopyAppFilter() { };
        bool eventFilter( QObject *, QEvent * );
    };
}

// L0201: See L0200, L0740
static QXEmbedCopyAppFilter* 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 QXEmbedCopy. 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 QXEmbedCopy 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 QXEmbedCopy 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 QXEmbedCopy
//        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 QXEmbedCopy widget looses the Qt focus, we clear the 
//        focus in the embedded client (L1570, L0688). Conversely, when
//        the QXEmbedCopy 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 QXEmbedCopy 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 QXEmbedCopy widget
//        when this happens (L2060).  This can be achieved without
//        cooperation from the client.

bool QXEmbedCopyAppFilter::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 QXEmbedCopy widget has the Qt focus.
                //        So we clear the Qt focus for now.  If indeed the QXEmbedCopy 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 QXEmbedCopy You may
//        have to call it manually for a client when using embedder-side
//        embedding, though.
void QXEmbedCopy::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 QXEmbedCopyAppFilter;

    is_initialized = true;
}





// ------------------------------------------------------------
// L0800: MOST OF WHAT FOLLOWS CONCERNS THE EMBEDDER SIDE.
//        Things that happen inside a Qt application that contain
//        a QXEmbedCopy widget for embedding other applications.
//        This applies to both the XEMBED and XPLAIN protocols.
//        Deviations are commented below.



// L0810: Class QXEmbedCopy.
//        A QXEmbedCopy 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
//        QXEmbedCopy, from the client side or from the embedder's side.


// L0900: Constructs a xembed widget.
QXEmbedCopy::QXEmbedCopy(QWidget *parent, const char *name, WFlags f)
  : QWidget(parent, name, f)
{
    // L0901: Create private data. See L0100.
    d = new QXEmbedCopyData;
    // L0902: Create focus proxy widget. See XEmbed specification.
    //        Each QXEmbedCopy widget has a focus proxy window. Every single
    //        QXEmbedCopy 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 QXEmbedCopy 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.
QXEmbedCopy::~QXEmbedCopy()
{
    // 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 QXEmbedCopy'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, QXEmbedCopy 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 QXEmbedCopy::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 QXEmbedCopy::setProtocol( Protocol proto )
{
    if (!window) {
        d->xplain = false;
        if (proto == XPLAIN)
            d->xplain = true;
    }
}

// L1150: Returns the protocol used for embedding the current window.
QXEmbedCopy::Protocol QXEmbedCopy::protocol()
{
  if (d->xplain)
    return XPLAIN;
  return XEMBED;
}


// L1200: QXEmbedCopy widget size changes: resize embedded window.
void QXEmbedCopy::resizeEvent(QResizeEvent*)
{
    if (window)
        XResizeWindow(qt_xdisplay(), window, width(), height());
}

// L1250: QXEmbedCopy widget is shown: make sure embedded window is visible.
void QXEmbedCopy::showEvent(QShowEvent*)
{
    if (window)
        XMapRaised(qt_xdisplay(), window);
}


// L1300: This event filter sees all application events (L0913).
bool QXEmbedCopy::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  QXEmbedCopy::event( QEvent * e)
{
    return QWidget::event( e );
}

// L1400: Forward keypress event to the client
//        Receiving a Qt key event indicates that
//        the QXEmbedCopy object has the Qt focus.
//        The X11 event that caused the Qt key event
//        must be forwarded to the client.
//        See L0660.
void QXEmbedCopy::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 QXEmbedCopy::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 QXEmbedCopy::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 QXEmbedCopy::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 QXEmbedCopy 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 QXEmbedCopy::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 QXEmbedCopy::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 QXEmbedCopy widget.
//        See doc in qxembed.h.
void QXEmbedCopy::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 QXEmbedCopy?]
    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 < 100000; ++i) {	// this section changed from original QXEmbed
                if (wstate_withdrawn(window)) {
                    Window parent = 0;
                    get_parent(w, &parent);
                    if (parent == qt_xrootwin()) break;
                    else if ((i%500) == 0) qDebug ("not really withdrawn, yet in loop #%d", i);
                }
                USLEEP(10);
            }
        }

        // 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);
        if (parent != qt_xrootwin()) {		// this if added to original QXEmbed
            kdDebug() << QString(" failure to withdraw window") << endl;
            window = 0;
            return;
        }
        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;
    }
}


// L1800: Returns the window identifier of the embedded window
WId QXEmbedCopy::embeddedWinId() const
{
    return window;
}


// L1900: Control Qt tab focus management.
//        See Qt documentation.
bool QXEmbedCopy::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 QXEmbedCopy 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 QXEmbedCopy window.
bool QXEmbedCopy::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 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()){
            // L2020: We got a window. Complete the embedding process.
            window = e->xreparent.window;
            // 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 );
            }
        }
        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 QXEmbedCopy 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 QXEmbedCopy). 
                //        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 QXEmbedCopy::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 QXEmbedCopy::windowChanged( WId )
{
}


// L2400: Utility function for clients that embed themselves.
//        This is client side code.
bool QXEmbedCopy::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 QXEmbedCopy::embedClientIntoWindow(QWidget* client, WId window)
{
    initialize();
    XReparentWindow(qt_xdisplay(), client->winId(), window, 0, 0);
    // L2451: These two lines are redundant. See L0680.
    ((QXEmbedCopy*)client)->topData()->embedded = true;
    ((QXEmbedCopy*)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 QXEmbedCopy::sizePolicy() const
{
    return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
}


// L2520: Returns a size sufficient for the embedded window
QSize QXEmbedCopy::sizeHint() const
{
    return minimumSizeHint();
}

// L2550: Returns the minimum size specified by the embedded window.
QSize QXEmbedCopy::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 QXEmbedCopy::setAutoDelete( bool b)
{
    d->autoDelete = b;
}

// L2650: See L2600.
bool QXEmbedCopy::autoDelete() const
{
    return d->autoDelete;
}

// L2700: See L2200.
bool QXEmbedCopy::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 QXEmbedCopy.  This passive
//        grab intercepts button clicks in the client window and
//        give us chance to request the Qt focus (L2060).
void QXEmbedCopy::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 QXEmbedCopy::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) {
        XConfigureEvent c;
        memset(&c, 0, sizeof(c));
        c.type = ConfigureNotify;
        c.display = qt_xdisplay();
        c.send_event = True;
        c.event = window;
        c.window = window;		// this line changed against the original version of QXEmbed!
        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 );
    }
}

// L3000: One should not call QWidget::reparent after embedding a window.
void QXEmbedCopy::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 QXEmbedCopy after reparenting is no longer the
    // parent of the embedded window.  I think reparenting of QXEmbedCopy can be
    // done only by a mistake, so just complain.
    Q_ASSERT( !window );
    QWidget::reparent( parent, f, p, showIt );
}

// for KDE
#include "qxembedcopy.moc"
#endif // Q_WS_X11
