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