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::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                         else if ( !w->topLevelWidget()->focusWidget() )
00484                             w->topLevelWidget()->setFocus();
00485                         break;
00486                     case XEMBED_FOCUS_FIRST:
00487                         {
00488                             // L0684: Search first widget in tab chain
00489                             QFocusEvent::setReason( QFocusEvent::Tab );
00490                             w->topLevelWidget()->setFocus();
00491                             ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(true);
00492                             QFocusEvent::resetReason();
00493                         }
00494                         break;
00495                     case XEMBED_FOCUS_LAST:
00496                         {
00497                             // L0686: Search last widget in tab chain
00498                             QFocusEvent::setReason( QFocusEvent::Backtab );
00499                             w->topLevelWidget()->setFocus();
00500                             ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(false);
00501                             QFocusEvent::resetReason();
00502                         }
00503                         break;
00504                     default:
00505                         break;
00506                     }
00507                 }
00508                 break;
00509             case XEMBED_FOCUS_OUT:
00510                 // L0688: Embedding application takes the focus away
00511                 //        We first record what the focus widget was
00512                 //        and clear the Qt focus.
00513                 if ( w->topLevelWidget()->focusWidget() ) {
00514                     focusMap->insert( w->topLevelWidget(),
00515                         new QGuardedPtr<QWidget>(w->topLevelWidget()->focusWidget() ) );
00516                     w->topLevelWidget()->focusWidget()->clearFocus();
00517                 }
00518             break;
00519             default:
00520                 break;
00521             }
00522         } else if ( e->xclient.format == 32 && e->xclient.message_type ) {
00523             if ( e->xclient.message_type == qt_wm_protocols ) {
00524                 QWidget* w = QWidget::find( e->xclient.window );
00525                 if ( !w )
00526                     break;
00527                 // L0690: This is for the embedding side!
00528                 //        See L0902 for more information about the focus proxy.
00529                 //        Window manager may send WM_TAKE_FOCUS messages to the 
00530                 //        embedding application to indicate that it becomes active. 
00531                 //        But this also suggests that the window manager has
00532                 //        changed the X11 focus. We want to make sure it goes
00533                 //        to the focus proxy window eventually.
00534                 Atom a = e->xclient.data.l[0];
00535                 if ( a == qt_wm_take_focus ) {
00536                     // L0695: update Qt message time variable
00537                     if ( (ulong) e->xclient.data.l[1] > qt_x_time )
00538                         qt_x_time = e->xclient.data.l[1];
00539                     // L0696: There is no problem when the window is not active.
00540                     //        Qt will generate a WindowActivate event that will
00541                     //        do the job (L1310).  This does not happen if the
00542                     //        window is already active.  So we simulate it.
00543                     if ( w->isActiveWindow() ) {
00544                         QEvent e( QEvent::WindowActivate );
00545                         QApplication::sendEvent( w, &e );
00546                     }
00547                 }
00548             }
00549         }
00550         break;
00551     default:
00552         break;
00553     }
00554     // L0698: The next x11 filter 
00555     if ( oldFilter )
00556         return oldFilter( e );
00557     // L0699: Otherwise process the event as usual.
00558     return false;
00559 }
00560 
00561 
00562 
00563 // L0700: Install the xembed filters in both client and embedder sides.
00564 //        This function is called automatically when using
00565 //        embedClientIntoWindow() or creating an instance of QXEmbed You may
00566 //        have to call it manually for a client when using embedder-side
00567 //        embedding, though.
00568 void QXEmbed::initialize()
00569 {
00570     static bool is_initialized = false;
00571     if ( is_initialized )
00572         return;
00573 
00574     // L0710: Atom used by the XEMBED protocol.
00575     xembed = XInternAtom( qt_xdisplay(), "_XEMBED", false );
00576     // L0720: Install low level filter for X11 events (L0650)
00577     oldFilter = qt_set_x11_event_filter( qxembed_x11_event_filter );
00578     // L0730: See L0610 for an explanation about focusMap.
00579     focusMap = new QPtrDict<QGuardedPtr<QWidget> >;
00580     focusMap->setAutoDelete( true );
00581     // L0740: Create client side application wide event filter (L0610)
00582     filter = new QXEmbedAppFilter;
00583 
00584     is_initialized = true;
00585 }
00586 
00587 
00588 
00589 
00590 
00591 // ------------------------------------------------------------
00592 // L0800: MOST OF WHAT FOLLOWS CONCERNS THE EMBEDDER SIDE.
00593 //        Things that happen inside a Qt application that contain
00594 //        a QXEmbed widget for embedding other applications.
00595 //        This applies to both the XEMBED and XPLAIN protocols.
00596 //        Deviations are commented below.
00597 
00598 
00599 
00600 // L0810: Class QXEmbed.
00601 //        A QXEmbed widget serves as an embedder that can manage one single
00602 //        embedded X-window. These so-called client windows can be arbitrary
00603 //        Qt or non Qt applications.  There are two different ways of using
00604 //        QXEmbed, from the client side or from the embedder's side.
00605 
00606 
00607 // L0900: Constructs a xembed widget.
00608 QXEmbed::QXEmbed(QWidget *parent, const char *name, WFlags f)
00609   : QWidget(parent, name, f)
00610 {
00611     // L0901: Create private data. See L0100.
00612     d = new QXEmbedData;
00613     // L0902: Create focus proxy widget. See XEmbed specification.
00614     //        Each QXEmbed widget has a focus proxy window. Every single
00615     //        QXEmbed widget tries to force its focus proxy window onto the
00616     //        whole embedding application. They compete between themselves and
00617     //        against Qt (L0690, L0914, L1040, L1310, L1510, L1580). 
00618     //        This would be much simpler if implemented within Qt.
00619     d->focusProxy = new QWidget( topLevelWidget(), "xembed_focus" );
00620     d->focusProxy->setGeometry( -1, -1, 1, 1 );
00621     d->focusProxy->show();
00622     // make sure it's shown - for XSetInputFocus
00623     QApplication::sendPostedEvents( d->focusProxy, 0 );
00624     // L0903: Install the client side event filters
00625     //        because they also provide services for the embedder side
00626     //        See L0660, L0671, L0685.
00627     initialize();
00628     window = 0;
00629     setFocusPolicy(StrongFocus);
00630     setKeyCompression( false );
00631 
00632     // L0910: Trick Qt to create extraData();
00633     (void) topData();
00634 
00635     // L0912: We are mostly interested in SubstructureNotify
00636     //        This is sent when something happens to the children of
00637     //        the X11 window associated with the QXEmbed widget.
00638     XSelectInput(qt_xdisplay(), winId(),
00639                  KeyPressMask | KeyReleaseMask |
00640                  ButtonPressMask | ButtonReleaseMask |
00641                  KeymapStateMask |
00642                  ButtonMotionMask |
00643                  PointerMotionMask | // may need this, too
00644                  EnterWindowMask | LeaveWindowMask |
00645                  FocusChangeMask |
00646                  ExposureMask |
00647                  StructureNotifyMask |
00648                  SubstructureRedirectMask |
00649                  SubstructureNotifyMask
00650                  );
00651     // L0913: all application events pass through eventFilter().
00652     //        This is mostly used to force the X11 focus on the 
00653     //        proxy focus window. See L1300.
00654     topLevelWidget()->installEventFilter( this );
00655     qApp->installEventFilter( this );
00656 
00657     // L0914: Start moving the X11 focus on the focus proxy window.
00658     //        See L1581 to know why we do not use isActiveWindow().
00659     if ( qApp->activeWindow() == topLevelWidget() )
00660         if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00661             XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00662                             RevertToParent, qt_x_time );
00663     // L0915: ??? [drag&drop?]
00664     setAcceptDrops( true );
00665 }
00666 
00667 // L1000: Destructor must dispose of the embedded client window.
00668 QXEmbed::~QXEmbed()
00669 {
00670     // L1010: Make sure no pointer grab is left.
00671     if ( d && d->xgrab)
00672         XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() );
00673     if ( window && ( autoDelete() || !d->xplain ))
00674         {
00675             // L1021: Hide the window and safely reparent it into the root,
00676             //        otherwise it would be destroyed by X11 together 
00677             //        with this QXEmbed's window.
00678 #if 0
00679 // TODO: The proper XEmbed way would be to unmap the window, and the embedded
00680 // app would detect the embedding has ended, and do whatever it finds appropriate.
00681 // However, QXEmbed currently doesn't provide support for this detection,
00682 // so for the time being, it's better to leave the window mapped as toplevel window.
00683 // This will be ever more complicated with the systray windows, as the simple API
00684 // for them (KWin::setSystemTrayWindowFor()) doesn't make it possible to detect
00685 // themselves they have been released from systray, but KWin requires them
00686 // to be visible to allow next Kicker instance to swallow them.
00687 // See also below the L1022 comment.
00688 //            XUnmapWindow( qt_xdisplay(), window );
00689 #else
00690             if( autoDelete())
00691                 XUnmapWindow( qt_xdisplay(), window );
00692 #endif
00693             XReparentWindow(qt_xdisplay(), window, qt_xrootwin(), 0, 0);
00694             if( !d->xplain )
00695                 XRemoveFromSaveSet( qt_xdisplay(), window );
00696             if( d->mapAfterRelease )
00697                 XMapWindow( qt_xdisplay(), window );
00698             XSync(qt_xdisplay(), false);
00699             // L1022: Send the WM_DELETE_WINDOW message
00700             if( autoDelete() /*&& d->xplain*/ ) 
00701                 // This sendDelete should only apply to XPLAIN.
00702                 // XEMBED apps are supposed to detect when the embedding ends.
00703                 // ??? [We do not do this detection yet! 
00704                 //      So we sendDelete() instead.]
00705                 sendDelete();
00706       }
00707     window = 0;
00708     // L01040: Our focus proxy window will be destroyed as well.
00709     //         Make sure that the X11 focus is not lost in the process.
00710     Window focus;
00711     int revert;
00712     XGetInputFocus( qt_xdisplay(), &focus, &revert );
00713     if( focus == d->focusProxy->winId())
00714         XSetInputFocus( qt_xdisplay(), topLevelWidget()->winId(), RevertToParent, qt_x_time );
00715     // L01045: Delete our private data.
00716     delete d;
00717 }
00718 
00719 
00720 // L1050: Sends a WM_DELETE_WINDOW message to the embedded window.  This is
00721 //        what typically happens when you click on the close button of a 
00722 //        window manager decoration.
00723 void QXEmbed::sendDelete( void )
00724 {
00725   if (window)
00726     {
00727       sendClientMessage(window, qt_wm_protocols, qt_wm_delete_window);
00728       XFlush( qt_xdisplay() );
00729     }
00730 }
00731 
00732 // L1100: Sets the protocol used for embedding windows.
00733 //        This function must be called before embedding a window.
00734 //        Protocol XEMBED provides maximal functionality (focus, tabs, etc)
00735 //        but requires explicit cooperation from the embedded window.  
00736 //        Protocol XPLAIN provides maximal compatibility with 
00737 //        embedded applications that do not support the XEMBED protocol.
00738 //        The default is XEMBED.  
00739 void QXEmbed::setProtocol( Protocol proto )
00740 {
00741     if (!window) {
00742         d->xplain = false;
00743         if (proto == XPLAIN)
00744             d->xplain = true;
00745     }
00746 }
00747 
00748 // L1150: Returns the protocol used for embedding the current window.
00749 QXEmbed::Protocol QXEmbed::protocol()
00750 {
00751   if (d->xplain)
00752     return XPLAIN;
00753   return XEMBED;
00754 }
00755 
00756 
00757 // L1200: QXEmbed widget size changes: resize embedded window.
00758 void QXEmbed::resizeEvent(QResizeEvent*)
00759 {
00760     if (window)
00761         XResizeWindow(qt_xdisplay(), window, width(), height());
00762 }
00763 
00764 // L1250: QXEmbed widget is shown: make sure embedded window is visible.
00765 void QXEmbed::showEvent(QShowEvent*)
00766 {
00767     if (window)
00768         XMapRaised(qt_xdisplay(), window);
00769 }
00770 
00771 
00772 // L1300: This event filter sees all application events (L0913).
00773 bool QXEmbed::eventFilter( QObject *o, QEvent * e)
00774 {
00775 
00776     switch ( e->type() ) {
00777     case QEvent::WindowActivate:
00778         if ( o == topLevelWidget() ) {
00779             // L1310: Qt thinks the application window has just been activated.
00780             //        Make sure the X11 focus is on the focus proxy window. See L0686.
00781             if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00782                 if (! hasFocus() )
00783                     XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00784                                     RevertToParent, qt_x_time );
00785             if (d->xplain)
00786                 // L1311: Activation has changed. Grab state might change. See L2800.
00787                 checkGrab();
00788             else
00789                 // L1312: Let the client know that we just became active
00790                 sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE );
00791         }
00792         break;
00793     case QEvent::WindowDeactivate:
00794         if ( o == topLevelWidget() ) {
00795             if (d->xplain)
00796                 // L1321: Activation has changed. Grab state might change. See L2800.
00797                 checkGrab();
00798             else
00799                 // L1322: Let the client know that we are no longer active
00800                 sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE );
00801         }
00802         break;
00803     case QEvent::Move:
00804         {
00805             QWidget* pos = this;
00806             while( pos != o && pos != topLevelWidget())
00807                 pos = pos->parentWidget();
00808             if( pos == o ) {
00809                 // L1390: Send fake configure notify events whenever the
00810                 //        global position of the client changes. See L2900.
00811                 QPoint globalPos = mapToGlobal(QPoint(0,0));
00812                 if (globalPos != d->lastPos) {
00813                     d->lastPos = globalPos;
00814                     sendSyntheticConfigureNotifyEvent();
00815                 }
00816             }
00817         }                    
00818         break;
00819     default:
00820         break;
00821    }
00822    return false;
00823 }
00824 
00825 // L1350: ??? [why this?]
00826 bool  QXEmbed::event( QEvent * e)
00827 {
00828     return QWidget::event( e );
00829 }
00830 
00831 // L1400: Forward keypress event to the client
00832 //        Receiving a Qt key event indicates that
00833 //        the QXEmbed object has the Qt focus.
00834 //        The X11 event that caused the Qt key event
00835 //        must be forwarded to the client.
00836 //        See L0660.
00837 void QXEmbed::keyPressEvent( QKeyEvent *)
00838 {
00839     if (!window)
00840         return;
00841     last_key_event.window = window;
00842     XSendEvent(qt_xdisplay(), window, false, KeyPressMask, (XEvent*)&last_key_event);
00843 
00844 }
00845 
00846 // L1450: Forward keyrelease event to the client.
00847 //        See comment L1400.
00848 void QXEmbed::keyReleaseEvent( QKeyEvent *)
00849 {
00850     if (!window)
00851         return;
00852     last_key_event.window = window;
00853     XSendEvent(qt_xdisplay(), window, false, KeyReleaseMask, (XEvent*)&last_key_event);
00854 }
00855 
00856 // L1500: Handle Qt focus in event.
00857 void QXEmbed::focusInEvent( QFocusEvent * e ){
00858     if (!window)
00859         return;
00860     // L1510: This is a good time to set the X11 focus on the focus proxy window.
00861     //        Except if the the embedding application itself is embedded into another.
00862     if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00863       if ( qApp->activeWindow() == topLevelWidget() )
00864           // L1511: Alter X focus only when window is active. 
00865           //        This is dual safety here because FocusIn implies this.
00866           //        But see L1581 for an example where this really matters.
00867           XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00868                           RevertToParent, qt_x_time );
00869     if (d->xplain) {
00870         // L1520: Qt focus has changed. Grab state might change. See L2800.
00871         checkGrab();
00872         // L1521: Window managers activate applications by setting the X11 focus.
00873         //        We cannot do this (see L1510) but we can send a fake focus event
00874         //        and forward the X11 key events ourselves (see L1400, L1450).
00875         sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
00876     } else {
00877         // L1530: No need for fake events with XEMBED.
00878         //        Just inform the client. It knows what to do.
00879         int detail = XEMBED_FOCUS_CURRENT;
00880         // L1531: When the focus change is caused by the tab key,
00881         //        the client must select the first (or last) widget of
00882         //        its own tab chain.
00883         if ( e->reason() == QFocusEvent::Tab )
00884             detail = XEMBED_FOCUS_FIRST;
00885         else if ( e->reason() == QFocusEvent::Backtab )
00886             detail = XEMBED_FOCUS_LAST;
00887         sendXEmbedMessage( window, XEMBED_FOCUS_IN, detail);
00888     }
00889 }
00890 
00891 // L1550: Handle Qt focus out event.
00892 void QXEmbed::focusOutEvent( QFocusEvent * ){
00893     if (!window)
00894         return;
00895     if (d->xplain) {
00896         // L1560: Qt focus has changed. Grab state might change. See L2800.
00897         checkGrab();
00898         // L1561: Send fake focus out message. See L1521.
00899         sendFocusMessage(window, XFocusOut, NotifyNormal, NotifyPointer );
00900     } else {
00901         // L1570: Send XEMBED focus out message. See L1531.
00902         sendXEmbedMessage( window, XEMBED_FOCUS_OUT );
00903     }
00904     // L1580: The QXEmbed object might loose the focus because its
00905     //        toplevel window looses the X11 focus and is no longer active, 
00906     //        or simply because the Qt focus has been moved to another widget.
00907     //        In the latter case only, we want to make sure that the X11 focus
00908     //        is properly set to the X11 focus widget.  We do this because
00909     //        the client application might have moved the X11 focus after
00910     //        receiving the fake focus messages.
00911     if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00912         if ( qApp->activeWindow() == topLevelWidget() )
00913             // L1581: Alter X focus only when window is active.
00914             //        The test above is not the same as isActiveWindow().
00915             //        Function isActiveWindow() also returns true when a modal
00916             //        dialog child of this window is active.
00917             XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00918                             RevertToParent, qt_x_time );
00919 }
00920 
00921 
00922 // L1600: Helper for QXEmbed::embed()
00923 //        Check whether a window is in withdrawn state.
00924 static bool wstate_withdrawn( WId winid )
00925 {
00926     Atom type;
00927     int format;
00928     unsigned long length, after;
00929     unsigned char *data;
00930     int r = XGetWindowProperty( qt_xdisplay(), winid, qt_wm_state, 0, 2,
00931                                 false, AnyPropertyType, &type, &format,
00932                                 &length, &after, &data );
00933     bool withdrawn = true;
00934     // L1610: Non managed windows have no WM_STATE property.
00935     //        Returning true ensures that the loop L1711 stops.
00936     if ( r == Success && data && format == 32 ) {
00937         Q_UINT32 *wstate = (Q_UINT32*)data;
00938         withdrawn  = (*wstate == WithdrawnState );
00939         XFree( (char *)data );
00940     }
00941     return withdrawn;
00942 }
00943 
00944 // L1650: Helper for QXEmbed::embed()
00945 //        Get the X11 id of the parent window.
00946 static int get_parent(WId winid, Window *out_parent)
00947 {
00948     Window root, *children=0;
00949     unsigned int nchildren;
00950     int st = XQueryTree(qt_xdisplay(), winid, &root, out_parent, &children, &nchildren);
00951     if (st && children) 
00952         XFree(children);
00953     return st;
00954 }
00955 
00956 // L1700: Embeds the window w into this QXEmbed widget.
00957 //        See doc in qxembed.h.
00958 void QXEmbed::embed(WId w)
00959 {
00960     kdDebug() << "*** Embed " << w << " into " << winId() << ". window=" << window << endl;
00961     if (!w)
00962         return;
00963     // L1701: The has_window variable prevents embedding a same window twice.
00964     //        ??? [what happens if one embed two windows into the same QXEmbed?]
00965     bool has_window =  (w == window);
00966     window = w;
00967     if ( !has_window ) {
00968         KXErrorHandler errhandler; // make X BadWindow errors silent
00969         // L1710: Try hard to withdraw the window.
00970         //        This makes sure that the window manager will
00971         //        no longer try to manage this window.
00972         if ( !wstate_withdrawn(window) ) {
00973             XWithdrawWindow(qt_xdisplay(), window, qt_xscreen());
00974             QApplication::flushX();
00975             // L1711: See L1610
00976             while (!wstate_withdrawn(window))
00977                 USLEEP(1000);
00978         }
00979         // L1710: It would be sufficient in principle to reparent
00980         //        window w into winId(). Everything else happens in L2020.
00981         //        The following code might be useful when the X11 server takes 
00982         //        time to create the embedded application main window.
00983         Window parent = 0;
00984         get_parent(w, &parent);
00985         kdDebug() << QString("> before reparent: parent=0x%1").arg(parent,0,16) << endl;
00986         for (int i = 0; i < 50; i++) {
00987             // this is done once more when finishing embedding, but it's done also here
00988             // just in case we crash before reaching that place
00989             if( !d->xplain )
00990                 XAddToSaveSet( qt_xdisplay(), w );
00991             XReparentWindow(qt_xdisplay(), w, winId(), 0, 0);
00992             if (get_parent(w, &parent) && parent == winId()) {
00993                kdDebug() << QString("> Loop %1: ").arg(i)
00994                          << QString("> reparent of 0x%1").arg(w,0,16)
00995                          << QString(" into 0x%1").arg(winId(),0,16)
00996                          << QString(" successful") << endl;
00997                 break;
00998             }
00999             kdDebug() << QString("> Loop %1: ").arg(i)
01000                       << QString("> reparent of 0x%1").arg(w,0,16)
01001                       << QString(" into 0x%1").arg(winId(),0,16)
01002                       << QString(" failed") << endl;
01003             USLEEP(1000);
01004         }
01005         if( parent != winId()) // failed
01006             window = 0;
01007     }
01008 }
01009 
01010 
01011 // L1800: Returns the window identifier of the embedded window
01012 WId QXEmbed::embeddedWinId() const
01013 {
01014     return window;
01015 }
01016 
01017 
01018 // L1900: Control Qt tab focus management.
01019 //        See Qt documentation.
01020 bool QXEmbed::focusNextPrevChild( bool next )
01021 {
01022     if ( window )
01023         // L1901: Return false when there is an embedded window
01024         //        When the user presses TAB, Qt will not change 
01025         //        the focus and pass the TAB key events to the QXEmbed widget.
01026         //        These key events will be forwarded to the client (L1400, L1450)
01027         //        who eventually will manage the tab focus (L0620) and possible
01028         //        instruct us to call QWidget::focusNextPrevChild (L2081).
01029         return false;
01030     else
01031         // L1920: Default behavior otherwise.
01032         return QWidget::focusNextPrevChild( next );
01033 }
01034 
01035 
01036 // L2000: Filter for X11 events sent to the QXEmbed window.
01037 bool QXEmbed::x11Event( XEvent* e)
01038 {
01039     switch ( e->type ) {
01040     case DestroyNotify:
01041         if ( e->xdestroywindow.window == window ) {
01042             // L2005: Client window is being destroyed.
01043             window = 0;
01044             windowChanged( window );
01045             emit embeddedWindowDestroyed();
01046         }
01047         break;
01048     case ReparentNotify:
01049         if ( e->xreparent.window == d->focusProxy->winId() )
01050             break; // ignore proxy
01051         if ( window && e->xreparent.window == window &&
01052              e->xreparent.parent != winId() ) {
01053             // L2010: We lost the window
01054             window = 0;
01055             windowChanged( window );
01056             emit embeddedWindowDestroyed();
01057             // L2011: Remove window from save set
01058             //        ??? [not sure it is good to touch this window since
01059             //             someone else has taken control of it already.]
01060             if( !d->xplain )
01061                 XRemoveFromSaveSet( qt_xdisplay(), window );
01062         } else if ( e->xreparent.parent == winId()){
01063             // L2020: We got a window. Complete the embedding process.
01064             window = e->xreparent.window;
01065             // only XEMBED apps can survive crash,
01066             // see http://lists.kde.org/?l=kfm-devel&m=106752026501968&w=2
01067             if( !d->xplain )
01068                 XAddToSaveSet( qt_xdisplay(), window );
01069             XResizeWindow(qt_xdisplay(), window, width(), height());
01070             XMapRaised(qt_xdisplay(), window);
01071             // L2024: see L2900.
01072             sendSyntheticConfigureNotifyEvent();
01073             // L2025: ??? [any idea about drag&drop?] 
01074             extraData()->xDndProxy = window;
01075             if ( parent() ) {
01076                 // L2030: embedded window might have new size requirements.
01077                 //        see L2500, L2520, L2550.
01078                 QEvent * layoutHint = new QEvent( QEvent::LayoutHint );
01079                 QApplication::postEvent( parent(), layoutHint );
01080             }
01081             windowChanged( window );
01082             if (d->xplain) {
01083                 // L2040: Activation has changed. Grab state might change. See L2800.
01084                 checkGrab();
01085                 if ( hasFocus() )
01086                     // L2041: Send fake focus message to inform the client. See L1521.
01087                     sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
01088             } else {
01089                 // L2050: Send XEMBED messages (see L0670, L1312, L1322, L1530)
01090                 sendXEmbedMessage( window, XEMBED_EMBEDDED_NOTIFY, 0, (long) winId() );
01091                 if (isActiveWindow())
01092                     sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE);
01093                 else
01094                     sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE);
01095                 if ( hasFocus() )
01096                     sendXEmbedMessage( window, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT );
01097             }
01098         }
01099         break;
01100     case ButtonPress:
01101         if (d->xplain && d->xgrab) {
01102             // L2060: The passive grab has intercepted a mouse click
01103             //        in the embedded client window. Take the focus.
01104             QFocusEvent::setReason( QFocusEvent::Mouse );
01105             setFocus();
01106             QFocusEvent::resetReason();
01107             // L2064: Resume X11 event processing.
01108             XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime);
01109             // L2065: Qt should not know about this.
01110             return true;
01111         }
01112         break;
01113     case ButtonRelease:
01114         if (d->xplain && d->xgrab) {
01115             // L2064: Resume X11 event processing after passive grab (see L2060)
01116             XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime);
01117             return true;
01118         }
01119         break;
01120     case MapRequest:
01121         // L2070: Behave like a window manager.
01122         if ( window && e->xmaprequest.window == window )
01123             XMapRaised(qt_xdisplay(), window );
01124         break;
01125     case ClientMessage:
01126         // L2080: This is where the QXEmbed object receives XEMBED 
01127         //        messaged from the client application.
01128         if ( e->xclient.format == 32 && e->xclient.message_type == xembed ) {
01129             long message = e->xclient.data.l[1];
01130             switch ( message ) {
01131                 // L2081: Tab focus management. It is very important to call the 
01132                 //        focusNextPrevChild() defined by QWidget (not QXEmbed). 
01133                 //        See L1901.
01134             case XEMBED_FOCUS_NEXT:
01135                 QWidget::focusNextPrevChild( true );
01136                 break;
01137             case XEMBED_FOCUS_PREV:
01138                 QWidget::focusNextPrevChild( false );
01139                 break;
01140                 // L2085: The client asks for the focus.
01141             case XEMBED_REQUEST_FOCUS:
01142                 if( ((QPublicWidget*)topLevelWidget())->topData()->embedded ) {
01143                     WId window = ((QPublicWidget*)topLevelWidget())->topData()->parentWinId;
01144                     sendXEmbedMessage( window, XEMBED_REQUEST_FOCUS );
01145                 } else {
01146                     QFocusEvent::setReason( QFocusEvent::Mouse );
01147                     setFocus();
01148                     QFocusEvent::resetReason();
01149                 }
01150                 break;
01151             default:
01152                 break;
01153             }
01154         }
01155     break;
01156 
01157     case ConfigureRequest:
01158         // L2090: Client wants to change its geometry. 
01159         //        Just inform it that nothing has changed.
01160         if (e->xconfigurerequest.window == window) 
01161         {
01162              sendSyntheticConfigureNotifyEvent();
01163         }
01164         break;
01165     case MotionNotify: 
01166     // fall through, workaround for Qt 3.0 < 3.0.3
01167     case EnterNotify:
01168         // L2095: See L2200.
01169         if ( QWhatsThis::inWhatsThisMode() )
01170             enterWhatsThisMode();
01171         break;
01172     default:
01173         break;
01174     }
01175     return false;
01176 }
01177 
01178 
01179 // L2200: Try to handle Qt's "what's this" mode.  Broken.
01180 //        "temporary, fix in Qt (Matthias, Mon Jul 17 15:20:55 CEST 2000"
01181 void QXEmbed::enterWhatsThisMode()
01182 {
01183     // L2210: When the what-s-this pointer enters the embedded window (L2095)
01184     //        cancel what-s-this mode, and use a non stantard _NET_WM_ message
01185     //        to instruct the embedded client to enter the "what's this" mode.
01186     //        This works only one way...
01187     QWhatsThis::leaveWhatsThisMode();
01188     if ( !context_help )
01189         context_help = XInternAtom( x11Display(), "_NET_WM_CONTEXT_HELP", false );
01190     sendClientMessage(window , qt_wm_protocols, context_help );
01191 }
01192 
01193 
01194 // L2300: indicates that the embedded window has been changed.
01195 void QXEmbed::windowChanged( WId )
01196 {
01197 }
01198 
01199 
01200 // L2400: Utility function for clients that embed themselves.
01201 //        This is client side code.
01202 bool QXEmbed::processClientCmdline( QWidget* client, int& argc, char ** argv )
01203 {
01204     int myargc = argc;
01205     WId window = 0;
01206     int i, j;
01207 
01208     j = 1;
01209     for ( i=1; i<myargc; i++ ) {
01210         if ( argv[i] && *argv[i] != '-' ) {
01211             argv[j++] = argv[i];
01212             continue;
01213         }
01214         QCString arg = argv[i];
01215         if ( !strcmp(arg,"-embed") && i < myargc-1 ) {
01216             QCString s = argv[++i];
01217             window = s.toInt();
01218         } else
01219             argv[j++] = argv[i];
01220     }
01221     argc = j;
01222 
01223     if ( window ) {
01224         embedClientIntoWindow( client, window );
01225         return true;
01226     }
01227 
01228     return false;
01229 }
01230 
01231 
01232 // L2450: Utility function for clients that embed themselves.
01233 //        This is client side code.
01234 void QXEmbed::embedClientIntoWindow(QWidget* client, WId window)
01235 {
01236     initialize();
01237     XReparentWindow(qt_xdisplay(), client->winId(), window, 0, 0);
01238     // L2451: These two lines are redundant. See L0680.
01239     ((QXEmbed*)client)->topData()->embedded = true;
01240     ((QXEmbed*)client)->topData()->parentWinId = window;
01241     // L2452: This seems redundant because L2020 maps the window.
01242     //        But calling show() might also set Qt internal flags.
01243     client->show();
01244 }
01245 
01246 
01247 
01248 // L2500: Specifies that this widget can use additional space,
01249 //        and that it can survive on less than sizeHint().
01250 QSizePolicy QXEmbed::sizePolicy() const
01251 {
01252     return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
01253 }
01254 
01255 
01256 // L2520: Returns a size sufficient for the embedded window
01257 QSize QXEmbed::sizeHint() const
01258 {
01259     return minimumSizeHint();
01260 }
01261 
01262 // L2550: Returns the minimum size specified by the embedded window.
01263 QSize QXEmbed::minimumSizeHint() const
01264 {
01265     int minw = 0;
01266     int minh = 0;
01267     if ( window ) {
01268         XSizeHints size;
01269         long msize;
01270         if (XGetWMNormalHints(qt_xdisplay(), window, &size, &msize)
01271             && ( size.flags & PMinSize) ) {
01272             minw = size.min_width;
01273             minh = size.min_height;
01274         }
01275     }
01276 
01277     return QSize( minw, minh );
01278 }
01279 
01280 // L2600: Tells what shoud be done with the embedded window when
01281 //        the embedding window is destroyed. 
01282 void QXEmbed::setAutoDelete( bool b)
01283 {
01284     d->autoDelete = b;
01285 }
01286 
01287 // L2650: See L2600.
01288 bool QXEmbed::autoDelete() const
01289 {
01290     return d->autoDelete;
01291 }
01292 
01293 // L2700: See L2200.
01294 bool QXEmbed::customWhatsThis() const
01295 {
01296     return true;
01297 }
01298 
01299 // L2800: When using the XPLAIN protocol, this function maintains
01300 //        a passive button grab when (1) the application is active
01301 //        and (2) the Qt focus is not on the QXEmbed.  This passive
01302 //        grab intercepts button clicks in the client window and
01303 //        give us chance to request the Qt focus (L2060).
01304 void QXEmbed::checkGrab() 
01305 {
01306     if (d->xplain && isActiveWindow() && !hasFocus()) {
01307         if (! d->xgrab)
01308             XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, winId(),
01309                         false, ButtonPressMask, GrabModeSync, GrabModeAsync,
01310                         None, None );
01311         d->xgrab = true;
01312     } else {
01313         if (d->xgrab)
01314             XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() );
01315         d->xgrab = false;
01316     }
01317 }
01318 
01319 // L2900: This sends fake configure notify events to inform
01320 //        the client about its window geometry. See L1390, L2024 and L2090.
01321 void QXEmbed::sendSyntheticConfigureNotifyEvent() 
01322 {
01323     // L2910: It seems that the x and y coordinates are global.
01324     //        But this is what ICCCM section 4.1.5 wants.
01325     //        See http://lists.kde.org/?l=kfm-devel&m=107090222032378
01326     QPoint globalPos = mapToGlobal(QPoint(0,0));
01327     if (window) {
01328         XConfigureEvent c;
01329         memset(&c, 0, sizeof(c));
01330         c.type = ConfigureNotify;
01331         c.display = qt_xdisplay();
01332         c.send_event = True;
01333         c.event = window;
01334         c.window = winId();
01335         c.x = globalPos.x();
01336         c.y = globalPos.y();
01337         c.width = width();
01338         c.height = height();
01339         c.border_width = 0;
01340         c.above = None;
01341         c.override_redirect = 0;
01342         XSendEvent( qt_xdisplay(), c.event, true, StructureNotifyMask, (XEvent*)&c );
01343     }
01344 }
01345 
01346 // L3000: One should not call QWidget::reparent after embedding a window.
01347 void QXEmbed::reparent( QWidget * parent, WFlags f, const QPoint & p, bool showIt )
01348 {
01349     // QWidget::reparent() destroys the old X Window for the widget, and
01350     // creates a new one, thus QXEmbed after reparenting is no longer the
01351     // parent of the embedded window.  I think reparenting of QXEmbed can be
01352     // done only by a mistake, so just complain.
01353     Q_ASSERT( !window );
01354     QWidget::reparent( parent, f, p, showIt );
01355 }
01356 
01357 // for KDE
01358 #include "qxembed.moc"
01359 #endif // Q_WS_X11
KDE Home | KDE Accessibility Home | Description of Access Keys