qxembed.cpp

00001 /****************************************************************************
00002     Implementation of QXEmbed class
00003 
00004     Copyright (C) 1999-2002 Trolltech AS
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Library General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Library General Public License for more details.
00015 
00016     You should have received a copy of the GNU Library General Public License
00017     along with this library; see the file COPYING.LIB.  If not, write to
00018     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019     Boston, MA 02110-1301, USA.
00020 *****************************************************************************/
00021 
00022 
00023 // L-000: About comments marked with Lxxxx.
00024 // 
00025 //    These comments represent an attempt to provide a more adequate
00026 //    documentation to KDE developpers willing to modify QXEmbed.  Keep in
00027 //    mind that these comments were written long after most of the code.
00028 //    Please improve them if you spot something wrong or missing 
00029 //    (Leon Bottou, 26-10-2003).
00030 //
00031 //    Relevant documents:
00032 //    - QXEmbed developper documentation
00033 //        (see comments in qxembed.h)
00034 //    - Xlib Reference Manual  
00035 //        (sections about focus, reparenting, window management)
00036 //    - ICCCM Manual
00037 //        (window management)
00038 //    - XEMBED specification 
00039 //        (http://www.freedesktop.org/Standards/xembed-spec)
00040 //    - XPLAIN and XEMBED.
00041 //        <http://lists.kde.org/?w=2&r=1&s=qxembed+variants&q=t>
00042 //    - Accumulated community knowledge.
00043 //        <http://lists.kde.org/?w=2&r=1&s=qxembed&q=t>
00044 //        <http://lists.kde.org/?l=kde-devel&w=2&r=1&s=qxembed&q=b>
00045 //        <http://lists.kde.org/?l=kfm-devel&w=2&r=1&s=qxembed&q=b>
00046 // 
00047 
00048 
00049 #include <qapplication.h>
00050 #include <qptrlist.h>
00051 #include <qptrdict.h>
00052 #include <qguardedptr.h>
00053 #include <qwhatsthis.h>
00054 #include <qfocusdata.h>
00055 
00056 // L0001: QXEmbed works only under X windows.
00057 #ifdef Q_WS_X11
00058 
00059 # include <X11/X.h>
00060 # include <X11/Xlib.h>
00061 # include <X11/Xutil.h>
00062 # include <X11/Xatom.h>
00063 # define XK_MISCELLANY
00064 # define XK_LATIN1
00065 # include <X11/keysymdef.h>
00066 # include <kdebug.h>
00067 # include <kxerrorhandler.h>
00068 
00069 // L0002: Is file config.h KDE specific?
00070 # include <config.h>
00071 # ifdef HAVE_UNISTD_H
00072 #  include <unistd.h>
00073 #  ifdef HAVE_USLEEP
00074 #   define USLEEP(x) usleep(x)
00075 #  else
00076 #   define USLEEP(x) sleep(0)
00077 #  endif
00078 # else
00079 #  define USLEEP(x) sleep(0)
00080 # endif
00081 
00082 # include "qxembed.h"
00083 
00084 // L0003: This keysym is used for focus navigation.
00085 # ifndef XK_ISO_Left_Tab
00086 #  define XK_ISO_Left_Tab 0xFE20
00087 # endif
00088 
00089 // L0004: Conflicts between X11 and Qt definitions.
00090 const int XFocusOut = FocusOut;
00091 const int XFocusIn = FocusIn;
00092 const int XKeyPress = KeyPress;
00093 const int XKeyRelease = KeyRelease;
00094 # undef KeyRelease
00095 # undef KeyPress
00096 # undef FocusOut
00097 # undef FocusIn
00098 
00099 // L0005: Variables defined in qapplication_x11.cpp
00100 extern Atom qt_wm_protocols;
00101 extern Atom qt_wm_delete_window;
00102 extern Atom qt_wm_take_focus;
00103 extern Atom qt_wm_state;
00104 extern Time qt_x_time;
00105 
00106 // L0006: X11 atoms private to QXEmbed
00107 static Atom xembed = 0;
00108 static Atom context_help = 0;
00109 
00110 // L0007: Xembed message codes (see XEmbed spec)
00111 #define XEMBED_EMBEDDED_NOTIFY          0
00112 #define XEMBED_WINDOW_ACTIVATE          1
00113 #define XEMBED_WINDOW_DEACTIVATE        2
00114 #define XEMBED_REQUEST_FOCUS            3
00115 #define XEMBED_FOCUS_IN                 4
00116 #define XEMBED_FOCUS_OUT                5
00117 #define XEMBED_FOCUS_NEXT               6
00118 #define XEMBED_FOCUS_PREV               7
00119 
00120 // L0008: Xembed message details (see XEmbed spec)
00121 // -- XEMBED_FOCUS_IN:
00122 #define XEMBED_FOCUS_CURRENT            0
00123 #define XEMBED_FOCUS_FIRST              1
00124 #define XEMBED_FOCUS_LAST               2
00125 
00126 
00127 // L0100: Private data held by the QXEmbed object.
00128 //        This belongs to the embedder side.
00129 class QXEmbedData
00130 {
00131 public:
00132     QXEmbedData(){ 
00133         autoDelete = true;
00134         xplain = false;
00135         xgrab = false;
00136         mapAfterRelease = false;
00137         lastPos = QPoint(0,0);
00138     }
00139     ~QXEmbedData(){};
00140 
00141     bool autoDelete;      // L0101: See L2600
00142     bool xplain;          // L0102: See L1100
00143     bool xgrab;           // L0103: See L2800
00144     bool mapAfterRelease;
00145     QWidget* focusProxy;  // L0104: See XEmbed spec
00146     QPoint lastPos;       // L0105: See L1390
00147 };
00148 
00149 namespace
00150 {
00151     // L0200: This application wide event filter handles focus
00152     //        issues in the embedded client.
00153     class QXEmbedAppFilter : public QObject
00154     {
00155     public:
00156         QXEmbedAppFilter()  { qApp->installEventFilter( this ); } 
00157         ~QXEmbedAppFilter() { };
00158         bool eventFilter( QObject *, QEvent * );
00159     };
00160 }
00161 
00162 // L0201: See L0200, L0740
00163 static QXEmbedAppFilter* filter = 0;
00164 // L0202: See L0610, L0730
00165 static QPtrDict<QGuardedPtr<QWidget> > *focusMap = 0;
00166 // L0203: See L0660, L1400, L1450
00167 static XKeyEvent last_key_event;
00168 
00169 // L0300: This class gives access protected members of class QWidget.
00170 //        Function focusData() is useful to reimplement tab focus management
00171 //        (L0620) Function topData() returns a structure QTLWExtra containing
00172 //        information unique to toplevel windows.  This structure contains two
00173 //        members for the sole use of QXEmbed. Flag `embedded' indicates whether
00174 //        the toplevel window is embedded using the XEMBED protocol (L0680). 
00175 //        Handle `parentWinId' then records the id of the embedding window.
00176 
00177 class QPublicWidget : public QWidget
00178 {
00179 public:
00180     QTLWExtra* topData() { return QWidget::topData(); }
00181     QFocusData *focusData(){ return QWidget::focusData(); }
00182     bool focusNextPrev(bool b) { return focusNextPrevChild(b); }
00183 };
00184 
00185 // L0400: This sets a very low level filter for X11 messages.
00186 //        See qapplication_x11.cpp
00187 typedef int (*QX11EventFilter) (XEvent*);
00188 extern QX11EventFilter qt_set_x11_event_filter (QX11EventFilter filter);
00189 static QX11EventFilter oldFilter = 0;
00190 
00191 
00192 // L0500: Helper to send XEmbed messages.
00193 static void sendXEmbedMessage( WId window, long message, long detail = 0,
00194                                long data1 = 0, long data2 = 0)
00195 {
00196     if (!window) return;
00197     XEvent ev;
00198     memset(&ev, 0, sizeof(ev));
00199     ev.xclient.type = ClientMessage;
00200     ev.xclient.window = window;
00201     ev.xclient.message_type = xembed;
00202     ev.xclient.format = 32;
00203     ev.xclient.data.l[0] = qt_x_time;
00204     ev.xclient.data.l[1] = message;
00205     ev.xclient.data.l[2] = detail;
00206     ev.xclient.data.l[3] = data1;
00207     ev.xclient.data.l[4] = data2;
00208     XSendEvent(qt_xdisplay(), window, false, NoEventMask, &ev);
00209 }
00210 
00211 // L0501: Helper to send ICCCM Client messages. 
00212 //        See X11 ICCCM Specification.
00213 static void sendClientMessage(Window window, Atom a, long x)
00214 {
00215   if (!window) return;
00216   XEvent ev;
00217   memset(&ev, 0, sizeof(ev));
00218   ev.xclient.type = ClientMessage;
00219   ev.xclient.window = window;
00220   ev.xclient.message_type = a;
00221   ev.xclient.format = 32;
00222   ev.xclient.data.l[0] = x;
00223   ev.xclient.data.l[1] = qt_x_time;
00224   XSendEvent(qt_xdisplay(), window, false, NoEventMask, &ev);
00225 }
00226 
00227 // L0502: Helper to send fake X11 focus messages.
00228 //        See X11 Reference Manual and Window Management stuff.
00229 static void sendFocusMessage(Window window, int type, int mode, int detail)
00230 {
00231   if (!window) return;
00232   XEvent ev;
00233   memset(&ev, 0, sizeof(ev));
00234   ev.xfocus.type = type;
00235   ev.xfocus.window = window;
00236   ev.xfocus.mode = mode;
00237   ev.xfocus.detail = detail;
00238   XSendEvent(qt_xdisplay(), window, false, FocusChangeMask, &ev);
00239 }
00240 
00241 
00242 // ------------------------------------------------------------
00243 // L0600: MOST OF WHAT FOLLOWS CONCERNS THE CLIENT SIDE.
00244 //        The following code mostly executes inside a Qt application swallowed
00245 //        by QXEmbed widget.  It mostly consists of event filters that fight
00246 //        the normal Qt mechanisms in order to implement the XEMBED protocol.
00247 //        All this would be a lot simpler if it was implemented by Qt itself.
00248 
00249 
00250 
00251 // L0610: This event filter receives all Qt events.  Its main purpose is to
00252 //        capture the Qt focus events in the embedded client in order to
00253 //        implement the XEMBED protocol. 
00254 //
00255 //        Let's start with a few reminders:
00256 //
00257 //        - X11 only has the concept of the "X11 focus window".  This window
00258 //          basically receives all key events.  The ICCCM conventions define
00259 //          how the window manager and the applications must cooperate to
00260 //          choose the X11 focus window.
00261 //
00262 //        - Most toolkits, including Qt, maintain the concepts of 'active
00263 //          widget' and 'Qt focus widget'.  A toplevel widget is active when
00264 //          the X11 focus is set to one of its children.  By extension a
00265 //          widget is active when its toplevel widget is active.  There is one
00266 //          Qt focus widget for each toplevel widget.  When the toplevel
00267 //          widget is active, all key events are sent to the Qt focus widget,
00268 //          regardless of which descendant of the toplevel window has the X11
00269 //          focus.  Widgets can adjust their appearance according to both 
00270 //          their activation and focus states.  The Qt FocusIn and FocusOut 
00271 //          events indicate when a widget simultaneously is active and has
00272 //          the Qt focus. 
00273 //
00274 //        The XEMBED protocol defines ways to communicate abouth both
00275 //        activation and focus. The embedded client is active as soon as the
00276 //        embedding window is active (L0676, L0677).  A widget in the embedded
00277 //        client receives key events when (1) it has the Qt focus in the
00278 //        embedded application, and (2) the QXEmbed widget in the embedding
00279 //        application is active and has the Qt focus.  The Qt library in the
00280 //        embedded application is unaware of the focus status of the QXEmbed
00281 //        widget.  We must make sure it does the right thing regarding the
00282 //        sending of focus events and the visual appearance of the focussed 
00283 //        widgets.  When the QXEmbed widget looses the Qt focus, we clear the 
00284 //        focus in the embedded client (L1570, L0688). Conversely, when
00285 //        the QXEmbed widget gains the Qt focus, we restore the Qt focus 
00286 //        window in the embedded client (L1530, L0680, L0683). 
00287 //        Variable focusMap is used to remember which was the Qt focus
00288 //        widget in the embedded application.  All this would be a lot
00289 //        simpler if it was implemented inside Qt...
00290 //
00291 //        The XPLAIN protocol is much less refined in this respect.
00292 //        The activation status of the embedded client simply reflect
00293 //        the focus status of the QXEmbed widget. This is achieved
00294 //        by sending fake X11 focus message to the client (L1521, L1561).
00295 //        A passive button grab (L2800) intercepts mouse activity in the
00296 //        embedded client and sets the Qt focus to the QXEmbed widget
00297 //        when this happens (L2060).  This can be achieved without
00298 //        cooperation from the client.
00299 
00300 bool QXEmbedAppFilter::eventFilter( QObject *o, QEvent * e)
00301 {
00302     static bool obeyFocus = false;
00303     switch ( e->type() ) {
00304     case QEvent::MouseButtonPress:
00305         // L0612: This will become clear with L0614
00306         if ( !((QWidget*)o)->isActiveWindow() )
00307             obeyFocus = true;
00308         break;
00309     case QEvent::FocusIn:
00310         // L0613: FocusIn events either occur because the widget already was
00311         //        active and has just been given the Qt focus (L0614) or
00312         //        because the widget already had the Qt focus and just became
00313         //        active (L0615).
00314         if ( qApp->focusWidget() == o &&
00315              ((QPublicWidget*)qApp->focusWidget()->topLevelWidget())->topData()->embedded ) {
00316             QFocusEvent* fe = (QFocusEvent*) e;
00317             if ( obeyFocus || fe->reason() != QFocusEvent::ActiveWindow /*|| fe->reason() == QFocusEvent::Mouse ||
00318                  fe->reason() == QFocusEvent::Shortcut*/ ) {
00319                 // L0614: A widget in the embedded client was just given the Qt focus.
00320                 //        Variable `obeyFocus' suggests that this is the result of mouse
00321                 //        activity in the client.  The XEMBED_REQUEST_FOCUS message causes
00322                 //        the embedding widget to take the Qt focus (L2085).
00323                 WId window = ((QPublicWidget*)qApp->focusWidget()->topLevelWidget())->topData()->parentWinId;
00324                 focusMap->remove( qApp->focusWidget()->topLevelWidget() );
00325                 sendXEmbedMessage( window, XEMBED_REQUEST_FOCUS );
00326             } else if ( fe->reason() == QFocusEvent::ActiveWindow ) {
00327                 // L0615: Both the embedder and the embedded client became active.
00328                 //        But we do not know whether the QXEmbed widget has the Qt focus.
00329                 //        So we clear the Qt focus for now.  If indeed the QXEmbed widget
00330                 //        has the focus, it will receive a FocusIn message (L1530) and
00331                 //        tell us to restore the focus (L0680, L0683).
00332                 focusMap->remove( qApp->focusWidget()->topLevelWidget() );
00333                 focusMap->insert( qApp->focusWidget()->topLevelWidget(),
00334                                   new QGuardedPtr<QWidget>(qApp->focusWidget()->topLevelWidget()->focusWidget() ) );
00335                 // L0616: qApp->focusWidget() might belong to a modal dialog and not be 
00336                 //        equal to qApp->focusWidget()->topLevelWidget()->focusWidget() !
00337                 qApp->focusWidget()->clearFocus();
00338                 // L0617: ??? [why not {obeyFocus=false; return true;} here?]
00339             }
00340             obeyFocus = false;
00341         }
00342         break;
00343     case QEvent::KeyPress: 
00344         if (qApp->focusWidget() == o &&
00345             ((QPublicWidget*)qApp->focusWidget()->topLevelWidget())->topData()->embedded ) {
00346             // L0620: The following code replaces the Qt code that 
00347             //        handles focus focus changes with the tab key. See the
00348             //        XEMBED specification for details.  The keypress event
00349             //        arrives here after an interesting itinerary. It is first
00350             //        saved in the embedding application (L0660). After being
00351             //        rejected for tab navigation in the embedding application
00352             //        (L1901), it gets forwarded to the embedded client
00353             //        (L1400) and arrives here.  Depending on the status of
00354             //        the tab chain in the embedded client, focus navigation
00355             //        messages are sent back to the embedding application
00356             //        (L0653, L0654) which then performs tab navigation
00357             //        (L2081).
00358             QKeyEvent *k = (QKeyEvent *)e;
00359             QWidget *w = qApp->focusWidget();
00360             // L0621: The following tests are copied from QWidget::event().
00361             bool res = false;
00362             bool tabForward = true;
00363             if ( !(k->state() & ControlButton || k->state() & AltButton) ) {
00364                 if ( k->key() == Key_Backtab || (k->key() == Key_Tab && (k->state() & ShiftButton)) ) {
00365                     QFocusEvent::setReason( QFocusEvent::Backtab );
00366                     res = ((QPublicWidget*)w)->focusNextPrev( tabForward = false );
00367                     QFocusEvent::resetReason();
00368                 } else if ( k->key() == Key_Tab ) {
00369                     QFocusEvent::setReason( QFocusEvent::Tab );
00370                     res = ((QPublicWidget*)w)->focusNextPrev( tabForward = true );
00371                     QFocusEvent::resetReason();
00372                 }
00373             }
00374             if (res) {
00375                 // L0625: We changed the focus because of tab/backtab key
00376                 //        Now check whether we have been looping around.
00377                 QFocusData *fd = ((QPublicWidget*)w)->focusData();
00378                 WId window = ((QPublicWidget*)w->topLevelWidget())->topData()->parentWinId;
00379                 QWidget *cw = 0;
00380                 QWidget *fw = fd->home();
00381                 if (tabForward && window) {
00382                     while (cw != w && cw != fw && cw != w->topLevelWidget()) 
00383                         cw = fd->prev();
00384                     if (cw != w)
00385                         sendXEmbedMessage( window, XEMBED_FOCUS_NEXT );
00386                 } else if (window) {
00387                     while (cw != w && cw != fw && cw != w->topLevelWidget()) 
00388                         cw = fd->next();
00389                     if (cw != w)
00390                         sendXEmbedMessage( window, XEMBED_FOCUS_PREV );
00391                 }
00392                 // L0628: Qt should no longer process this event.
00393                 return true;
00394             }
00395         }
00396         break;
00397     default:
00398         break;
00399     }
00400     // L0640: Application gets to see the events anyway.
00401     return false;
00402 }
00403 
00404 // L0650: This filter receives all XEvents in both the client and the embedder.  
00405 //        Most of it involves the embedded client (except L0660, L0671).
00406 static int qxembed_x11_event_filter( XEvent* e)
00407 {
00408     switch ( e->type ) {
00409     case XKeyPress:
00410     case XKeyRelease: {
00411         // L0660: This is for the embedding side (L1450).
00412         last_key_event = e->xkey;
00413         break;
00414     }
00415     case ClientMessage:
00416         if ( e->xclient.message_type == xembed ) {
00417             // L0670: This is where the XEmbed messages are 
00418             //        processed on the client side.
00419             Time msgtime = (Time) e->xclient.data.l[0];
00420             long message = e->xclient.data.l[1];
00421             long detail = e->xclient.data.l[2];
00422             // L0671: Keep Qt message time up to date
00423             if ( msgtime > qt_x_time )
00424                 qt_x_time = msgtime;
00425             QWidget* w = QWidget::find( e->xclient.window );
00426             if ( !w )
00427                 break;
00428             switch ( message) {
00429             case XEMBED_EMBEDDED_NOTIFY: {
00430                 // L0675: We just have been embedded into a XEMBED aware widget.
00431                 QTLWExtra *extra = ((QPublicWidget*)w->topLevelWidget())->topData();
00432                 extra->embedded = 1;
00433                 extra->parentWinId = e->xclient.data.l[3];
00434                 w->topLevelWidget()->show();
00435                 break;
00436             }
00437             case XEMBED_WINDOW_ACTIVATE: {
00438                 // L0676: Embedding window becomes active. Send a fake XFocusIn
00439                 //        to convince Qt that we are active as well.  Qt will send
00440                 //        us a focus notification (L0615) that we will intercept to
00441                 //        ensure that we have no Qt focus widget yet.  The Qt focus
00442                 //        widget might later be set in L0680.
00443                 XEvent ev;
00444                 memset(&ev, 0, sizeof(ev));
00445                 ev.xfocus.display = qt_xdisplay();
00446                 ev.xfocus.type = XFocusIn;
00447                 ev.xfocus.window = w->topLevelWidget()->winId();
00448                 ev.xfocus.mode = NotifyNormal;
00449                 ev.xfocus.detail = NotifyAncestor;
00450                 qApp->x11ProcessEvent( &ev );
00451             }
00452             break;
00453             case XEMBED_WINDOW_DEACTIVATE: {
00454                 // L0677: Embedding window becomes inactive. Send a fake XFocusOut
00455                 //        event to convince Qt that we no longer are active.  We will
00456                 //        receive extra Qt FocusOut events but we do not care.
00457                 XEvent ev;
00458                 memset(&ev, 0, sizeof(ev));
00459                 ev.xfocus.display = qt_xdisplay();
00460                 ev.xfocus.type = XFocusOut;
00461                 ev.xfocus.window = w->topLevelWidget()->winId();
00462                 ev.xfocus.mode = NotifyNormal;
00463                 ev.xfocus.detail = NotifyAncestor;
00464                 qApp->x11ProcessEvent( &ev );
00465             }
00466             break;
00467             case XEMBED_FOCUS_IN:
00468                 // L0680: Embedding application gives us the focus.
00469                 {
00470                     // L0681: Search saved focus widget.
00471                     QWidget* focusCurrent = 0;
00472                     QGuardedPtr<QWidget>* fw = focusMap->find( w->topLevelWidget() );
00473                     if ( fw ) {
00474                         focusCurrent = *fw;
00475                         // L0682: Remove it from the map
00476                         focusMap->remove( w->topLevelWidget() );
00477                     }
00478                     switch ( detail ) {
00479                     case XEMBED_FOCUS_CURRENT:
00480                         // L0683: Set focus on saved focus widget
00481                         if ( focusCurrent ) {
00482                             focusCurrent->setFocus();
00483                             if( QXEmbed* emb = dynamic_cast< QXEmbed* >( focusCurrent ))
00484                                 emb->updateEmbeddedFocus( true );
00485                         }
00486                         else if ( !w->topLevelWidget()->focusWidget() )
00487                             w->topLevelWidget()->setFocus();
00488                         break;
00489                     case XEMBED_FOCUS_FIRST:
00490                         {
00491                             // L0684: Search first widget in tab chain
00492                             QFocusEvent::setReason( QFocusEvent::Tab );
00493                             w->topLevelWidget()->setFocus();
00494                             ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(true);
00495                             QFocusEvent::resetReason();
00496                         }
00497                         break;
00498                     case XEMBED_FOCUS_LAST:
00499                         {
00500                             // L0686: Search last widget in tab chain
00501                             QFocusEvent::setReason( QFocusEvent::Backtab );
00502                             w->topLevelWidget()->setFocus();
00503                             ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(false);
00504                             QFocusEvent::resetReason();
00505                         }
00506                         break;
00507                     default:
00508                         break;
00509                     }
00510                 }
00511                 break;
00512             case XEMBED_FOCUS_OUT:
00513                 // L0688: Embedding application takes the focus away
00514                 //        We first record what the focus widget was
00515                 //        and clear the Qt focus.
00516                 if ( w->topLevelWidget()->focusWidget() ) {
00517                     if( QXEmbed* emb = dynamic_cast< QXEmbed* >( w->topLevelWidget()->focusWidget()))
00518                         emb->updateEmbeddedFocus( false );
00519                     focusMap->insert( w->topLevelWidget(),
00520                         new QGuardedPtr<QWidget>(w->topLevelWidget()->focusWidget() ) );
00521                     w->topLevelWidget()->focusWidget()->clearFocus();
00522                 }
00523             break;
00524             default:
00525                 break;
00526             }
00527         } else if ( e->xclient.format == 32 && e->xclient.message_type ) {
00528             if ( e->xclient.message_type == qt_wm_protocols ) {
00529                 QWidget* w = QWidget::find( e->xclient.window );
00530                 if ( !w )
00531                     break;
00532                 // L0690: This is for the embedding side!
00533                 //        See L0902 for more information about the focus proxy.
00534                 //        Window manager may send WM_TAKE_FOCUS messages to the 
00535                 //        embedding application to indicate that it becomes active. 
00536                 //        But this also suggests that the window manager has
00537                 //        changed the X11 focus. We want to make sure it goes
00538                 //        to the focus proxy window eventually.
00539                 Atom a = e->xclient.data.l[0];
00540                 if ( a == qt_wm_take_focus ) {
00541                     // L0695: update Qt message time variable
00542                     if ( (ulong) e->xclient.data.l[1] > qt_x_time )
00543                         qt_x_time = e->xclient.data.l[1];
00544                     // L0696: There is no problem when the window is not active.
00545                     //        Qt will generate a WindowActivate event that will
00546                     //        do the job (L1310).  This does not happen if the
00547                     //        window is already active.  So we simulate it.
00548                     if ( w->isActiveWindow() ) {
00549                         QEvent e( QEvent::WindowActivate );
00550                         QApplication::sendEvent( w, &e );
00551                     }
00552                 }
00553             }
00554         }
00555         break;
00556     default:
00557         break;
00558     }
00559     // L0698: The next x11 filter 
00560     if ( oldFilter )
00561         return oldFilter( e );
00562     // L0699: Otherwise process the event as usual.
00563     return false;
00564 }
00565 
00566 
00567 
00568 // L0700: Install the xembed filters in both client and embedder sides.
00569 //        This function is called automatically when using
00570 //        embedClientIntoWindow() or creating an instance of QXEmbed You may
00571 //        have to call it manually for a client when using embedder-side
00572 //        embedding, though.
00573 void QXEmbed::initialize()
00574 {
00575     static bool is_initialized = false;
00576     if ( is_initialized )
00577         return;
00578 
00579     // L0710: Atom used by the XEMBED protocol.
00580     xembed = XInternAtom( qt_xdisplay(), "_XEMBED", false );
00581     // L0720: Install low level filter for X11 events (L0650)
00582     oldFilter = qt_set_x11_event_filter( qxembed_x11_event_filter );
00583     // L0730: See L0610 for an explanation about focusMap.
00584     focusMap = new QPtrDict<QGuardedPtr<QWidget> >;
00585     focusMap->setAutoDelete( true );
00586     // L0740: Create client side application wide event filter (L0610)
00587     filter = new QXEmbedAppFilter;
00588 
00589     is_initialized = true;
00590 }
00591 
00592 
00593 
00594 
00595 
00596 // ------------------------------------------------------------
00597 // L0800: MOST OF WHAT FOLLOWS CONCERNS THE EMBEDDER SIDE.
00598 //        Things that happen inside a Qt application that contain
00599 //        a QXEmbed widget for embedding other applications.
00600 //        This applies to both the XEMBED and XPLAIN protocols.
00601 //        Deviations are commented below.
00602 
00603 
00604 
00605 // L0810: Class QXEmbed.
00606 //        A QXEmbed widget serves as an embedder that can manage one single
00607 //        embedded X-window. These so-called client windows can be arbitrary
00608 //        Qt or non Qt applications.  There are two different ways of using
00609 //        QXEmbed, from the client side or from the embedder's side.
00610 
00611 
00612 // L0900: Constructs a xembed widget.
00613 QXEmbed::QXEmbed(QWidget *parent, const char *name, WFlags f)
00614   : QWidget(parent, name, f)
00615 {
00616     // L0901: Create private data. See L0100.
00617     d = new QXEmbedData;
00618     // L0902: Create focus proxy widget. See XEmbed specification.
00619     //        Each QXEmbed widget has a focus proxy window. Every single
00620     //        QXEmbed widget tries to force its focus proxy window onto the
00621     //        whole embedding application. They compete between themselves and
00622     //        against Qt (L0690, L0914, L1040, L1310, L1510, L1580). 
00623     //        This would be much simpler if implemented within Qt.
00624     d->focusProxy = new QWidget( topLevelWidget(), "xembed_focus" );
00625     d->focusProxy->setGeometry( -1, -1, 1, 1 );
00626     d->focusProxy->show();
00627     // make sure it's shown - for XSetInputFocus
00628     QApplication::sendPostedEvents( d->focusProxy, 0 );
00629     // L0903: Install the client side event filters
00630     //        because they also provide services for the embedder side
00631     //        See L0660, L0671, L0685.
00632     initialize();
00633     window = 0;
00634     setFocusPolicy(StrongFocus);
00635     setKeyCompression( false );
00636 
00637     // L0910: Trick Qt to create extraData();
00638     (void) topData();
00639 
00640     // L0912: We are mostly interested in SubstructureNotify
00641     //        This is sent when something happens to the children of
00642     //        the X11 window associated with the QXEmbed widget.
00643     XSelectInput(qt_xdisplay(), winId(),
00644                  KeyPressMask | KeyReleaseMask |
00645                  ButtonPressMask | ButtonReleaseMask |
00646                  KeymapStateMask |
00647                  ButtonMotionMask |
00648                  PointerMotionMask | // may need this, too
00649                  EnterWindowMask | LeaveWindowMask |
00650                  FocusChangeMask |
00651                  ExposureMask |
00652                  StructureNotifyMask |
00653                  SubstructureRedirectMask |
00654                  SubstructureNotifyMask
00655                  );
00656     // L0913: all application events pass through eventFilter().
00657     //        This is mostly used to force the X11 focus on the 
00658     //        proxy focus window. See L1300.
00659     topLevelWidget()->installEventFilter( this );
00660     qApp->installEventFilter( this );
00661 
00662     // L0914: Start moving the X11 focus on the focus proxy window.
00663     //        See L1581 to know why we do not use isActiveWindow().
00664     if ( qApp->activeWindow() == topLevelWidget() )
00665         if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00666             XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00667                             RevertToParent, qt_x_time );
00668     // L0915: ??? [drag&drop?]
00669     setAcceptDrops( true );
00670 }
00671 
00672 // L1000: Destructor must dispose of the embedded client window.
00673 QXEmbed::~QXEmbed()
00674 {
00675     // L1010: Make sure no pointer grab is left.
00676     if ( d && d->xgrab)
00677         XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() );
00678     if ( window && ( autoDelete() || !d->xplain ))
00679         {
00680             // L1021: Hide the window and safely reparent it into the root,
00681             //        otherwise it would be destroyed by X11 together 
00682             //        with this QXEmbed's window.
00683 #if 0
00684 // TODO: The proper XEmbed way would be to unmap the window, and the embedded
00685 // app would detect the embedding has ended, and do whatever it finds appropriate.
00686 // However, QXEmbed currently doesn't provide support for this detection,
00687 // so for the time being, it's better to leave the window mapped as toplevel window.
00688 // This will be ever more complicated with the systray windows, as the simple API
00689 // for them (KWin::setSystemTrayWindowFor()) doesn't make it possible to detect
00690 // themselves they have been released from systray, but KWin requires them
00691 // to be visible to allow next Kicker instance to swallow them.
00692 // See also below the L1022 comment.
00693 //            XUnmapWindow( qt_xdisplay(), window );
00694 #else
00695             if( autoDelete())
00696                 XUnmapWindow( qt_xdisplay(), window );
00697 #endif
00698             XReparentWindow(qt_xdisplay(), window, qt_xrootwin(), 0, 0);
00699             if( !d->xplain )
00700                 XRemoveFromSaveSet( qt_xdisplay(), window );
00701             if( d->mapAfterRelease )
00702                 XMapWindow( qt_xdisplay(), window );
00703             XSync(qt_xdisplay(), false);
00704             // L1022: Send the WM_DELETE_WINDOW message
00705             if( autoDelete() /*&& d->xplain*/ ) 
00706                 // This sendDelete should only apply to XPLAIN.
00707                 // XEMBED apps are supposed to detect when the embedding ends.
00708                 // ??? [We do not do this detection yet! 
00709                 //      So we sendDelete() instead.]
00710                 sendDelete();
00711       }
00712     window = 0;
00713     // L01040: Our focus proxy window will be destroyed as well.
00714     //         Make sure that the X11 focus is not lost in the process.
00715     Window focus;
00716     int revert;
00717     XGetInputFocus( qt_xdisplay(), &focus, &revert );
00718     if( focus == d->focusProxy->winId())
00719         XSetInputFocus( qt_xdisplay(), topLevelWidget()->winId(), RevertToParent, qt_x_time );
00720     // L01045: Delete our private data.
00721     delete d;
00722 }
00723 
00724 
00725 // L1050: Sends a WM_DELETE_WINDOW message to the embedded window.  This is
00726 //        what typically happens when you click on the close button of a 
00727 //        window manager decoration.
00728 void QXEmbed::sendDelete( void )
00729 {
00730   if (window)
00731     {
00732       sendClientMessage(window, qt_wm_protocols, qt_wm_delete_window);
00733       XFlush( qt_xdisplay() );
00734     }
00735 }
00736 
00737 // L1100: Sets the protocol used for embedding windows.
00738 //        This function must be called before embedding a window.
00739 //        Protocol XEMBED provides maximal functionality (focus, tabs, etc)
00740 //        but requires explicit cooperation from the embedded window.  
00741 //        Protocol XPLAIN provides maximal compatibility with 
00742 //        embedded applications that do not support the XEMBED protocol.
00743 //        The default is XEMBED.  
00744 void QXEmbed::setProtocol( Protocol proto )
00745 {
00746     if (!window) {
00747         d->xplain = false;
00748         if (proto == XPLAIN)
00749             d->xplain = true;
00750     }
00751 }
00752 
00753 // L1150: Returns the protocol used for embedding the current window.
00754 QXEmbed::Protocol QXEmbed::protocol()
00755 {
00756   if (d->xplain)
00757     return XPLAIN;
00758   return XEMBED;
00759 }
00760 
00761 
00762 // L1200: QXEmbed widget size changes: resize embedded window.
00763 void QXEmbed::resizeEvent(QResizeEvent*)
00764 {
00765     if (window)
00766         XResizeWindow(qt_xdisplay(), window, width(), height());
00767 }
00768 
00769 // L1250: QXEmbed widget is shown: make sure embedded window is visible.
00770 void QXEmbed::showEvent(QShowEvent*)
00771 {
00772     if (window)
00773         XMapRaised(qt_xdisplay(), window);
00774 }
00775 
00776 
00777 // L1300: This event filter sees all application events (L0913).
00778 bool QXEmbed::eventFilter( QObject *o, QEvent * e)
00779 {
00780 
00781     switch ( e->type() ) {
00782     case QEvent::WindowActivate:
00783         if ( o == topLevelWidget() ) {
00784             // L1310: Qt thinks the application window has just been activated.
00785             //        Make sure the X11 focus is on the focus proxy window. See L0686.
00786             if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00787                 if (! hasFocus() )
00788                     XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00789                                     RevertToParent, qt_x_time );
00790             if (d->xplain)
00791                 // L1311: Activation has changed. Grab state might change. See L2800.
00792                 checkGrab();
00793             else
00794                 // L1312: Let the client know that we just became active
00795                 sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE );
00796         }
00797         break;
00798     case QEvent::WindowDeactivate:
00799         if ( o == topLevelWidget() ) {
00800             if (d->xplain)
00801                 // L1321: Activation has changed. Grab state might change. See L2800.
00802                 checkGrab();
00803             else
00804                 // L1322: Let the client know that we are no longer active
00805                 sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE );
00806         }
00807         break;
00808     case QEvent::Move:
00809         {
00810             QWidget* pos = this;
00811             while( pos != o && pos != topLevelWidget())
00812                 pos = pos->parentWidget();
00813             if( pos == o ) {
00814                 // L1390: Send fake configure notify events whenever the
00815                 //        global position of the client changes. See L2900.
00816                 QPoint globalPos = mapToGlobal(QPoint(0,0));
00817                 if (globalPos != d->lastPos) {
00818                     d->lastPos = globalPos;
00819                     sendSyntheticConfigureNotifyEvent();
00820                 }
00821             }
00822         }                    
00823         break;
00824     default:
00825         break;
00826    }
00827    return false;
00828 }
00829 
00830 // L1350: ??? [why this?]
00831 bool  QXEmbed::event( QEvent * e)
00832 {
00833     return QWidget::event( e );
00834 }
00835 
00836 // L1400: Forward keypress event to the client
00837 //        Receiving a Qt key event indicates that
00838 //        the QXEmbed object has the Qt focus.
00839 //        The X11 event that caused the Qt key event
00840 //        must be forwarded to the client.
00841 //        See L0660.
00842 void QXEmbed::keyPressEvent( QKeyEvent *)
00843 {
00844     if (!window)
00845         return;
00846     last_key_event.window = window;
00847     XSendEvent(qt_xdisplay(), window, false, KeyPressMask, (XEvent*)&last_key_event);
00848 
00849 }
00850 
00851 // L1450: Forward keyrelease event to the client.
00852 //        See comment L1400.
00853 void QXEmbed::keyReleaseEvent( QKeyEvent *)
00854 {
00855     if (!window)
00856         return;
00857     last_key_event.window = window;
00858     XSendEvent(qt_xdisplay(), window, false, KeyReleaseMask, (XEvent*)&last_key_event);
00859 }
00860 
00861 // L1500: Handle Qt focus in event.
00862 void QXEmbed::focusInEvent( QFocusEvent * e ){
00863     if (!window)
00864         return;
00865     // L1510: This is a good time to set the X11 focus on the focus proxy window.
00866     //        Except if the the embedding application itself is embedded into another.
00867     if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00868       if ( qApp->activeWindow() == topLevelWidget() )
00869           // L1511: Alter X focus only when window is active. 
00870           //        This is dual safety here because FocusIn implies this.
00871           //        But see L1581 for an example where this really matters.
00872           XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00873                           RevertToParent, qt_x_time );
00874     if (d->xplain) {
00875         // L1520: Qt focus has changed. Grab state might change. See L2800.
00876         checkGrab();
00877         // L1521: Window managers activate applications by setting the X11 focus.
00878         //        We cannot do this (see L1510) but we can send a fake focus event
00879         //        and forward the X11 key events ourselves (see L1400, L1450).
00880         sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
00881     } else {
00882         // L1530: No need for fake events with XEMBED.
00883         //        Just inform the client. It knows what to do.
00884         int detail = XEMBED_FOCUS_CURRENT;
00885         // L1531: When the focus change is caused by the tab key,
00886         //        the client must select the first (or last) widget of
00887         //        its own tab chain.
00888         if ( e->reason() == QFocusEvent::Tab )
00889             detail = XEMBED_FOCUS_FIRST;
00890         else if ( e->reason() == QFocusEvent::Backtab )
00891             detail = XEMBED_FOCUS_LAST;
00892         sendXEmbedMessage( window, XEMBED_FOCUS_IN, detail);
00893     }
00894 }
00895 
00896 // L1550: Handle Qt focus out event.
00897 void QXEmbed::focusOutEvent( QFocusEvent * ){
00898     if (!window)
00899         return;
00900     if (d->xplain) {
00901         // L1560: Qt focus has changed. Grab state might change. See L2800.
00902         checkGrab();
00903         // L1561: Send fake focus out message. See L1521.
00904         sendFocusMessage(window, XFocusOut, NotifyNormal, NotifyPointer );
00905     } else {
00906         // L1570: Send XEMBED focus out message. See L1531.
00907         sendXEmbedMessage( window, XEMBED_FOCUS_OUT );
00908     }
00909     // L1580: The QXEmbed object might loose the focus because its
00910     //        toplevel window looses the X11 focus and is no longer active, 
00911     //        or simply because the Qt focus has been moved to another widget.
00912     //        In the latter case only, we want to make sure that the X11 focus
00913     //        is properly set to the X11 focus widget.  We do this because
00914     //        the client application might have moved the X11 focus after
00915     //        receiving the fake focus messages.
00916     if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00917         if ( qApp->activeWindow() == topLevelWidget() )
00918             // L1581: Alter X focus only when window is active.
00919             //        The test above is not the same as isActiveWindow().
00920             //        Function isActiveWindow() also returns true when a modal
00921             //        dialog child of this window is active.
00922             XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00923                             RevertToParent, qt_x_time );
00924 }
00925 
00926 
00927 // When QXEmbed has Qt focus and gets/loses X focus, make sure the client knows
00928 // about the state of the focus.
00929 void QXEmbed::updateEmbeddedFocus( bool hasfocus ){
00930     if (!window || d->xplain)
00931         return;
00932     if( hasfocus )
00933         sendXEmbedMessage( window, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
00934     else
00935         sendXEmbedMessage( window, XEMBED_FOCUS_OUT);
00936 }
00937 
00938 // L1600: Helper for QXEmbed::embed()
00939 //        Check whether a window is in withdrawn state.
00940 static bool wstate_withdrawn( WId winid )
00941 {
00942     Atom type;
00943     int format;
00944     unsigned long length, after;
00945     unsigned char *data;
00946     int r = XGetWindowProperty( qt_xdisplay(), winid, qt_wm_state, 0, 2,
00947                                 false, AnyPropertyType, &type, &format,
00948                                 &length, &after, &data );
00949     bool withdrawn = true;
00950     // L1610: Non managed windows have no WM_STATE property.
00951     //        Returning true ensures that the loop L1711 stops.
00952     if ( r == Success && data && format == 32 ) {
00953         Q_UINT32 *wstate = (Q_UINT32*)data;
00954         withdrawn  = (*wstate == WithdrawnState );
00955         XFree( (char *)data );
00956     }
00957     return withdrawn;
00958 }
00959 
00960 // L1650: Helper for QXEmbed::embed()
00961 //        Get the X11 id of the parent window.
00962 static int get_parent(WId winid, Window *out_parent)
00963 {
00964     Window root, *children=0;
00965     unsigned int nchildren;
00966     int st = XQueryTree(qt_xdisplay(), winid, &root, out_parent, &children, &nchildren);
00967     if (st && children) 
00968         XFree(children);
00969     return st;
00970 }
00971 
00972 // L1700: Embeds the window w into this QXEmbed widget.
00973 //        See doc in qxembed.h.
00974 void QXEmbed::embed(WId w)
00975 {
00976     kdDebug() << "*** Embed " << w << " into " << winId() << ". window=" << window << endl;
00977     if (!w)
00978         return;
00979     // L1701: The has_window variable prevents embedding a same window twice.
00980     //        ??? [what happens if one embed two windows into the same QXEmbed?]
00981     bool has_window =  (w == window);
00982     window = w;
00983     if ( !has_window ) {
00984         KXErrorHandler errhandler; // make X BadWindow errors silent
00985         // L1710: Try hard to withdraw the window.
00986         //        This makes sure that the window manager will
00987         //        no longer try to manage this window.
00988         if ( !wstate_withdrawn(window) ) {
00989             XWithdrawWindow(qt_xdisplay(), window, qt_xscreen());
00990             QApplication::flushX();
00991             // L1711: See L1610
00992             for (int i=0; i < 10000; ++i) {
00993                 if (wstate_withdrawn(window)) {
00994                     Window parent = 0;
00995                     get_parent(w, &parent);
00996                     if (parent == qt_xrootwin()) break;
00997                 }
00998                 USLEEP(1000);
00999             }
01000         }
01001         // L1710: It would be sufficient in principle to reparent
01002         //        window w into winId(). Everything else happens in L2020.
01003         //        The following code might be useful when the X11 server takes 
01004         //        time to create the embedded application main window.
01005         Window parent = 0;
01006         get_parent(w, &parent);
01007         kdDebug() << QString("> before reparent: parent=0x%1").arg(parent,0,16) << endl;
01008         for (int i = 0; i < 50; i++) {
01009             // this is done once more when finishing embedding, but it's done also here
01010             // just in case we crash before reaching that place
01011             if( !d->xplain )
01012                 XAddToSaveSet( qt_xdisplay(), w );
01013             XReparentWindow(qt_xdisplay(), w, winId(), 0, 0);
01014             if (get_parent(w, &parent) && parent == winId()) {
01015                kdDebug() << QString("> Loop %1: ").arg(i)
01016                          << QString("> reparent of 0x%1").arg(w,0,16)
01017                          << QString(" into 0x%1").arg(winId(),0,16)
01018                          << QString(" successful") << endl;
01019                 break;
01020             }
01021             kdDebug() << QString("> Loop %1: ").arg(i)
01022                       << QString("> reparent of 0x%1").arg(w,0,16)
01023                       << QString(" into 0x%1").arg(winId(),0,16)
01024                       << QString(" failed") << endl;
01025             USLEEP(1000);
01026         }
01027         if( parent != winId()) // failed
01028             window = 0;
01029     }
01030 }
01031 
01032 
01033 // L1800: Returns the window identifier of the embedded window
01034 WId QXEmbed::embeddedWinId() const
01035 {
01036     return window;
01037 }
01038 
01039 
01040 // L1900: Control Qt tab focus management.
01041 //        See Qt documentation.
01042 bool QXEmbed::focusNextPrevChild( bool next )
01043 {
01044     if ( window )
01045         // L1901: Return false when there is an embedded window
01046         //        When the user presses TAB, Qt will not change 
01047         //        the focus and pass the TAB key events to the QXEmbed widget.
01048         //        These key events will be forwarded to the client (L1400, L1450)
01049         //        who eventually will manage the tab focus (L0620) and possible
01050         //        instruct us to call QWidget::focusNextPrevChild (L2081).
01051         return false;
01052     else
01053         // L1920: Default behavior otherwise.
01054         return QWidget::focusNextPrevChild( next );
01055 }
01056 
01057 
01058 // L2000: Filter for X11 events sent to the QXEmbed window.
01059 bool QXEmbed::x11Event( XEvent* e)
01060 {
01061     switch ( e->type ) {
01062     case DestroyNotify:
01063         if ( e->xdestroywindow.window == window ) {
01064             // L2005: Client window is being destroyed.
01065             window = 0;
01066             windowChanged( window );
01067             emit embeddedWindowDestroyed();
01068         }
01069         break;
01070     case ReparentNotify:
01071         if ( e->xreparent.window == d->focusProxy->winId() )
01072             break; // ignore proxy
01073         if ( window && e->xreparent.window == window &&
01074              e->xreparent.parent != winId() ) {
01075             // L2010: We lost the window
01076             window = 0;
01077             windowChanged( window );
01078             emit embeddedWindowDestroyed();
01079             // L2011: Remove window from save set
01080             //        ??? [not sure it is good to touch this window since
01081             //             someone else has taken control of it already.]
01082             if( !d->xplain )
01083                 XRemoveFromSaveSet( qt_xdisplay(), window );
01084         } else if ( e->xreparent.parent == winId()){
01085             // L2020: We got a window. Complete the embedding process.
01086             window = e->xreparent.window;
01087             // only XEMBED apps can survive crash,
01088             // see http://lists.kde.org/?l=kfm-devel&m=106752026501968&w=2
01089             if( !d->xplain )
01090                 XAddToSaveSet( qt_xdisplay(), window );
01091             XResizeWindow(qt_xdisplay(), window, width(), height());
01092             XMapRaised(qt_xdisplay(), window);
01093             // L2024: see L2900.
01094             sendSyntheticConfigureNotifyEvent();
01095             // L2025: ??? [any idea about drag&drop?] 
01096             extraData()->xDndProxy = window;
01097             if ( parent() ) {
01098                 // L2030: embedded window might have new size requirements.
01099                 //        see L2500, L2520, L2550.
01100                 QEvent * layoutHint = new QEvent( QEvent::LayoutHint );
01101                 QApplication::postEvent( parent(), layoutHint );
01102             }
01103             windowChanged( window );
01104             if (d->xplain) {
01105                 // L2040: Activation has changed. Grab state might change. See L2800.
01106                 checkGrab();
01107                 if ( hasFocus() )
01108                     // L2041: Send fake focus message to inform the client. See L1521.
01109                     sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
01110             } else {
01111                 // L2050: Send XEMBED messages (see L0670, L1312, L1322, L1530)
01112                 sendXEmbedMessage( window, XEMBED_EMBEDDED_NOTIFY, 0, (long) winId() );
01113                 if (isActiveWindow())
01114                     sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE);
01115                 else
01116                     sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE);
01117                 if ( hasFocus() )
01118                     sendXEmbedMessage( window, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT );
01119                 else
01120                     sendXEmbedMessage( window, XEMBED_FOCUS_OUT );
01121             }
01122         }
01123         break;
01124     case ButtonPress:
01125         if (d->xplain && d->xgrab) {
01126             // L2060: The passive grab has intercepted a mouse click
01127             //        in the embedded client window. Take the focus.
01128             QFocusEvent::setReason( QFocusEvent::Mouse );
01129             setFocus();
01130             QFocusEvent::resetReason();
01131             // L2064: Resume X11 event processing.
01132             XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime);
01133             // L2065: Qt should not know about this.
01134             return true;
01135         }
01136         break;
01137     case ButtonRelease:
01138         if (d->xplain && d->xgrab) {
01139             // L2064: Resume X11 event processing after passive grab (see L2060)
01140             XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime);
01141             return true;
01142         }
01143         break;
01144     case MapRequest:
01145         // L2070: Behave like a window manager.
01146         if ( window && e->xmaprequest.window == window )
01147             XMapRaised(qt_xdisplay(), window );
01148         break;
01149     case ClientMessage:
01150         // L2080: This is where the QXEmbed object receives XEMBED 
01151         //        messaged from the client application.
01152         if ( e->xclient.format == 32 && e->xclient.message_type == xembed ) {
01153             long message = e->xclient.data.l[1];
01154             switch ( message ) {
01155                 // L2081: Tab focus management. It is very important to call the 
01156                 //        focusNextPrevChild() defined by QWidget (not QXEmbed). 
01157                 //        See L1901.
01158             case XEMBED_FOCUS_NEXT:
01159                 QWidget::focusNextPrevChild( true );
01160                 break;
01161             case XEMBED_FOCUS_PREV:
01162                 QWidget::focusNextPrevChild( false );
01163                 break;
01164                 // L2085: The client asks for the focus.
01165             case XEMBED_REQUEST_FOCUS:
01166                 if( ((QPublicWidget*)topLevelWidget())->topData()->embedded ) {
01167                     focusMap->remove( topLevelWidget() );
01168                     focusMap->insert( topLevelWidget(), new QGuardedPtr<QWidget>( this ));
01169                     WId window = ((QPublicWidget*)topLevelWidget())->topData()->parentWinId;
01170                     sendXEmbedMessage( window, XEMBED_REQUEST_FOCUS );
01171                 } else {
01172                     QFocusEvent::setReason( QFocusEvent::Mouse );
01173                     setFocus();
01174                     QFocusEvent::resetReason();
01175                 }
01176                 break;
01177             default:
01178                 break;
01179             }
01180         }
01181     break;
01182 
01183     case ConfigureRequest:
01184         // L2090: Client wants to change its geometry. 
01185         //        Just inform it that nothing has changed.
01186         if (e->xconfigurerequest.window == window) 
01187         {
01188              sendSyntheticConfigureNotifyEvent();
01189         }
01190         break;
01191     case MotionNotify: 
01192     // fall through, workaround for Qt 3.0 < 3.0.3
01193     case EnterNotify:
01194         // L2095: See L2200.
01195         if ( QWhatsThis::inWhatsThisMode() )
01196             enterWhatsThisMode();
01197         break;
01198     default:
01199         break;
01200     }
01201     return false;
01202 }
01203 
01204 
01205 // L2200: Try to handle Qt's "what's this" mode.  Broken.
01206 //        "temporary, fix in Qt (Matthias, Mon Jul 17 15:20:55 CEST 2000"
01207 void QXEmbed::enterWhatsThisMode()
01208 {
01209     // L2210: When the what-s-this pointer enters the embedded window (L2095)
01210     //        cancel what-s-this mode, and use a non stantard _NET_WM_ message
01211     //        to instruct the embedded client to enter the "what's this" mode.
01212     //        This works only one way...
01213     QWhatsThis::leaveWhatsThisMode();
01214     if ( !context_help )
01215         context_help = XInternAtom( x11Display(), "_NET_WM_CONTEXT_HELP", false );
01216     sendClientMessage(window , qt_wm_protocols, context_help );
01217 }
01218 
01219 
01220 // L2300: indicates that the embedded window has been changed.
01221 void QXEmbed::windowChanged( WId )
01222 {
01223 }
01224 
01225 
01226 // L2400: Utility function for clients that embed themselves.
01227 //        This is client side code.
01228 bool QXEmbed::processClientCmdline( QWidget* client, int& argc, char ** argv )
01229 {
01230     int myargc = argc;
01231     WId window = 0;
01232     int i, j;
01233 
01234     j = 1;
01235     for ( i=1; i<myargc; i++ ) {
01236         if ( argv[i] && *argv[i] != '-' ) {
01237             argv[j++] = argv[i];
01238             continue;
01239         }
01240         QCString arg = argv[i];
01241         if ( !strcmp(arg,"-embed") && i < myargc-1 ) {
01242             QCString s = argv[++i];
01243             window = s.toInt();
01244         } else
01245             argv[j++] = argv[i];
01246     }
01247     argc = j;
01248 
01249     if ( window ) {
01250         embedClientIntoWindow( client, window );
01251         return true;
01252     }
01253 
01254     return false;
01255 }
01256 
01257 
01258 // L2450: Utility function for clients that embed themselves.
01259 //        This is client side code.
01260 void QXEmbed::embedClientIntoWindow(QWidget* client, WId window)
01261 {
01262     initialize();
01263     XReparentWindow(qt_xdisplay(), client->winId(), window, 0, 0);
01264     // L2451: These two lines are redundant. See L0680.
01265     ((QXEmbed*)client)->topData()->embedded = true;
01266     ((QXEmbed*)client)->topData()->parentWinId = window;
01267     // L2452: This seems redundant because L2020 maps the window.
01268     //        But calling show() might also set Qt internal flags.
01269     client->show();
01270 }
01271 
01272 
01273 
01274 // L2500: Specifies that this widget can use additional space,
01275 //        and that it can survive on less than sizeHint().
01276 QSizePolicy QXEmbed::sizePolicy() const
01277 {
01278     return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
01279 }
01280 
01281 
01282 // L2520: Returns a size sufficient for the embedded window
01283 QSize QXEmbed::sizeHint() const
01284 {
01285     return minimumSizeHint();
01286 }
01287 
01288 // L2550: Returns the minimum size specified by the embedded window.
01289 QSize QXEmbed::minimumSizeHint() const
01290 {
01291     int minw = 0;
01292     int minh = 0;
01293     if ( window ) {
01294         XSizeHints size;
01295         long msize;
01296         if (XGetWMNormalHints(qt_xdisplay(), window, &size, &msize)
01297             && ( size.flags & PMinSize) ) {
01298             minw = size.min_width;
01299             minh = size.min_height;
01300         }
01301     }
01302 
01303     return QSize( minw, minh );
01304 }
01305 
01306 // L2600: Tells what shoud be done with the embedded window when
01307 //        the embedding window is destroyed. 
01308 void QXEmbed::setAutoDelete( bool b)
01309 {
01310     d->autoDelete = b;
01311 }
01312 
01313 // L2650: See L2600.
01314 bool QXEmbed::autoDelete() const
01315 {
01316     return d->autoDelete;
01317 }
01318 
01319 // L2700: See L2200.
01320 bool QXEmbed::customWhatsThis() const
01321 {
01322     return true;
01323 }
01324 
01325 // L2800: When using the XPLAIN protocol, this function maintains
01326 //        a passive button grab when (1) the application is active
01327 //        and (2) the Qt focus is not on the QXEmbed.  This passive
01328 //        grab intercepts button clicks in the client window and
01329 //        give us chance to request the Qt focus (L2060).
01330 void QXEmbed::checkGrab() 
01331 {
01332     if (d->xplain && isActiveWindow() && !hasFocus()) {
01333         if (! d->xgrab)
01334             XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, winId(),
01335                         false, ButtonPressMask, GrabModeSync, GrabModeAsync,
01336                         None, None );
01337         d->xgrab = true;
01338     } else {
01339         if (d->xgrab)
01340             XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() );
01341         d->xgrab = false;
01342     }
01343 }
01344 
01345 // L2900: This sends fake configure notify events to inform
01346 //        the client about its window geometry. See L1390, L2024 and L2090.
01347 void QXEmbed::sendSyntheticConfigureNotifyEvent() 
01348 {
01349     // L2910: It seems that the x and y coordinates are global.
01350     //        But this is what ICCCM section 4.1.5 wants.
01351     //        See http://lists.kde.org/?l=kfm-devel&m=107090222032378
01352     QPoint globalPos = mapToGlobal(QPoint(0,0));
01353     if (window) {
01354 #if 0
01355         XConfigureEvent c;
01356         memset(&c, 0, sizeof(c));
01357         c.type = ConfigureNotify;
01358         c.display = qt_xdisplay();
01359         c.send_event = True;
01360         c.event = window;
01361         c.window = window;
01362         c.x = globalPos.x();
01363         c.y = globalPos.y();
01364         c.width = width();
01365         c.height = height();
01366         c.border_width = 0;
01367         c.above = None;
01368         c.override_redirect = 0;
01369         XSendEvent( qt_xdisplay(), c.event, true, StructureNotifyMask, (XEvent*)&c );
01370 #endif
01371         // Yes, this doesn't make sense at all. See the commit message.
01372         XSetWindowBorderWidth( qt_xdisplay(), window, 1 );
01373         XSetWindowBorderWidth( qt_xdisplay(), window, 0 );
01374     }
01375 }
01376 
01377 // L3000: One should not call QWidget::reparent after embedding a window.
01378 void QXEmbed::reparent( QWidget * parent, WFlags f, const QPoint & p, bool showIt )
01379 {
01380     // QWidget::reparent() destroys the old X Window for the widget, and
01381     // creates a new one, thus QXEmbed after reparenting is no longer the
01382     // parent of the embedded window.  I think reparenting of QXEmbed can be
01383     // done only by a mistake, so just complain.
01384     Q_ASSERT( !window );
01385     QWidget::reparent( parent, f, p, showIt );
01386 }
01387 
01388 // for KDE
01389 #include "qxembed.moc"
01390 #endif // Q_WS_X11
KDE Home | KDE Accessibility Home | Description of Access Keys