kdeui Library API Documentation

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