• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

kdeui

qxembed.cpp

Go to the documentation of this file.
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             for (int i=0; i < 10000; ++i) {
00977                 if (wstate_withdrawn(window)) {
00978                     Window parent = 0;
00979                     get_parent(w, &parent);
00980                     if (parent == qt_xrootwin()) break;
00981                 }
00982                 USLEEP(1000);
00983             }
00984         }
00985         // L1710: It would be sufficient in principle to reparent
00986         //        window w into winId(). Everything else happens in L2020.
00987         //        The following code might be useful when the X11 server takes 
00988         //        time to create the embedded application main window.
00989         Window parent = 0;
00990         get_parent(w, &parent);
00991         kdDebug() << QString("> before reparent: parent=0x%1").arg(parent,0,16) << endl;
00992         for (int i = 0; i < 50; i++) {
00993             // this is done once more when finishing embedding, but it's done also here
00994             // just in case we crash before reaching that place
00995             if( !d->xplain )
00996                 XAddToSaveSet( qt_xdisplay(), w );
00997             XReparentWindow(qt_xdisplay(), w, winId(), 0, 0);
00998             if (get_parent(w, &parent) && parent == winId()) {
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(" successful") << endl;
01003                 break;
01004             }
01005             kdDebug() << QString("> Loop %1: ").arg(i)
01006                       << QString("> reparent of 0x%1").arg(w,0,16)
01007                       << QString(" into 0x%1").arg(winId(),0,16)
01008                       << QString(" failed") << endl;
01009             USLEEP(1000);
01010         }
01011         if( parent != winId()) // failed
01012             window = 0;
01013     }
01014 }
01015 
01016 // When a window is reparented into QXEmbed (or created inside of it), this function
01017 // sets up the actual embedding.
01018 void QXEmbed::handleEmbed()
01019 {
01020     // only XEMBED apps can survive crash,
01021     // see http://lists.kde.org/?l=kfm-devel&m=106752026501968&w=2
01022     if( !d->xplain )
01023         XAddToSaveSet( qt_xdisplay(), window );
01024     XResizeWindow(qt_xdisplay(), window, width(), height());
01025     XMapRaised(qt_xdisplay(), window);
01026     // L2024: see L2900.
01027     sendSyntheticConfigureNotifyEvent();
01028     // L2025: ??? [any idea about drag&drop?] 
01029     extraData()->xDndProxy = window;
01030     if ( parent() ) {
01031         // L2030: embedded window might have new size requirements.
01032         //        see L2500, L2520, L2550.
01033         QEvent * layoutHint = new QEvent( QEvent::LayoutHint );
01034         QApplication::postEvent( parent(), layoutHint );
01035     }
01036     windowChanged( window );
01037     if (d->xplain) {
01038         // L2040: Activation has changed. Grab state might change. See L2800.
01039         checkGrab();
01040         if ( hasFocus() )
01041             // L2041: Send fake focus message to inform the client. See L1521.
01042             sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
01043     } else {
01044         // L2050: Send XEMBED messages (see L0670, L1312, L1322, L1530)
01045         sendXEmbedMessage( window, XEMBED_EMBEDDED_NOTIFY, 0, (long) winId() );
01046         if (isActiveWindow())
01047             sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE);
01048         else
01049             sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE);
01050         if ( hasFocus() )
01051             sendXEmbedMessage( window, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT );
01052     }
01053 }
01054 
01055 // L1800: Returns the window identifier of the embedded window
01056 WId QXEmbed::embeddedWinId() const
01057 {
01058     return window;
01059 }
01060 
01061 
01062 // L1900: Control Qt tab focus management.
01063 //        See Qt documentation.
01064 bool QXEmbed::focusNextPrevChild( bool next )
01065 {
01066     if ( window )
01067         // L1901: Return false when there is an embedded window
01068         //        When the user presses TAB, Qt will not change 
01069         //        the focus and pass the TAB key events to the QXEmbed widget.
01070         //        These key events will be forwarded to the client (L1400, L1450)
01071         //        who eventually will manage the tab focus (L0620) and possible
01072         //        instruct us to call QWidget::focusNextPrevChild (L2081).
01073         return false;
01074     else
01075         // L1920: Default behavior otherwise.
01076         return QWidget::focusNextPrevChild( next );
01077 }
01078 
01079 
01080 // L2000: Filter for X11 events sent to the QXEmbed window.
01081 bool QXEmbed::x11Event( XEvent* e)
01082 {
01083     switch ( e->type ) {
01084     case DestroyNotify:
01085         if ( e->xdestroywindow.window == window ) {
01086             // L2005: Client window is being destroyed.
01087             window = 0;
01088             windowChanged( window );
01089             emit embeddedWindowDestroyed();
01090         }
01091         break;
01092     case CreateNotify:
01093         // A window was created inside of QXEmbed, handle it as embedded
01094         if( window == 0 ) { // only one window
01095             window = e->xcreatewindow.window;
01096             handleEmbed();
01097         }
01098         break;
01099     case ReparentNotify:
01100         if ( e->xreparent.window == d->focusProxy->winId() )
01101             break; // ignore proxy
01102         if ( window && e->xreparent.window == window &&
01103              e->xreparent.parent != winId() ) {
01104             // L2010: We lost the window
01105             window = 0;
01106             windowChanged( window );
01107             emit embeddedWindowDestroyed();
01108             // L2011: Remove window from save set
01109             //        ??? [not sure it is good to touch this window since
01110             //             someone else has taken control of it already.]
01111             if( !d->xplain )
01112                 XRemoveFromSaveSet( qt_xdisplay(), window );
01113         } else if ( e->xreparent.parent == winId()){
01114             if( window == 0 ) // something started embedding from the outside
01115                 window = e->xreparent.window;
01116             // L2020: We got a window. Complete the embedding process.
01117             if( e->xreparent.window == window )
01118                 handleEmbed();
01119         }
01120         break;
01121     case ButtonPress:
01122         if (d->xplain && d->xgrab) {
01123             // L2060: The passive grab has intercepted a mouse click
01124             //        in the embedded client window. Take the focus.
01125             QFocusEvent::setReason( QFocusEvent::Mouse );
01126             setFocus();
01127             QFocusEvent::resetReason();
01128             // L2064: Resume X11 event processing.
01129             XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime);
01130             // L2065: Qt should not know about this.
01131             return true;
01132         }
01133         break;
01134     case ButtonRelease:
01135         if (d->xplain && d->xgrab) {
01136             // L2064: Resume X11 event processing after passive grab (see L2060)
01137             XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime);
01138             return true;
01139         }
01140         break;
01141     case MapRequest:
01142         // L2070: Behave like a window manager.
01143         if ( window && e->xmaprequest.window == window )
01144             XMapRaised(qt_xdisplay(), window );
01145         break;
01146     case ClientMessage:
01147         // L2080: This is where the QXEmbed object receives XEMBED 
01148         //        messaged from the client application.
01149         if ( e->xclient.format == 32 && e->xclient.message_type == xembed ) {
01150             long message = e->xclient.data.l[1];
01151             switch ( message ) {
01152                 // L2081: Tab focus management. It is very important to call the 
01153                 //        focusNextPrevChild() defined by QWidget (not QXEmbed). 
01154                 //        See L1901.
01155             case XEMBED_FOCUS_NEXT:
01156                 QWidget::focusNextPrevChild( true );
01157                 break;
01158             case XEMBED_FOCUS_PREV:
01159                 QWidget::focusNextPrevChild( false );
01160                 break;
01161                 // L2085: The client asks for the focus.
01162             case XEMBED_REQUEST_FOCUS:
01163                 if( ((QPublicWidget*)topLevelWidget())->topData()->embedded ) {
01164                     WId window = ((QPublicWidget*)topLevelWidget())->topData()->parentWinId;
01165                     sendXEmbedMessage( window, XEMBED_REQUEST_FOCUS );
01166                 } else {
01167                     QFocusEvent::setReason( QFocusEvent::Mouse );
01168                     setFocus();
01169                     QFocusEvent::resetReason();
01170                 }
01171                 break;
01172             default:
01173                 break;
01174             }
01175         }
01176     break;
01177 
01178     case ConfigureRequest:
01179         // L2090: Client wants to change its geometry. 
01180         //        Just inform it that nothing has changed.
01181         if (e->xconfigurerequest.window == window) 
01182         {
01183              sendSyntheticConfigureNotifyEvent();
01184         }
01185         break;
01186     case MotionNotify: 
01187     // fall through, workaround for Qt 3.0 < 3.0.3
01188     case EnterNotify:
01189         // L2095: See L2200.
01190         if ( QWhatsThis::inWhatsThisMode() )
01191             enterWhatsThisMode();
01192         break;
01193     default:
01194         break;
01195     }
01196     return false;
01197 }
01198 
01199 
01200 // L2200: Try to handle Qt's "what's this" mode.  Broken.
01201 //        "temporary, fix in Qt (Matthias, Mon Jul 17 15:20:55 CEST 2000"
01202 void QXEmbed::enterWhatsThisMode()
01203 {
01204     // L2210: When the what-s-this pointer enters the embedded window (L2095)
01205     //        cancel what-s-this mode, and use a non stantard _NET_WM_ message
01206     //        to instruct the embedded client to enter the "what's this" mode.
01207     //        This works only one way...
01208     QWhatsThis::leaveWhatsThisMode();
01209     if ( !context_help )
01210         context_help = XInternAtom( x11Display(), "_NET_WM_CONTEXT_HELP", false );
01211     sendClientMessage(window , qt_wm_protocols, context_help );
01212 }
01213 
01214 
01215 // L2300: indicates that the embedded window has been changed.
01216 void QXEmbed::windowChanged( WId )
01217 {
01218 }
01219 
01220 
01221 // L2400: Utility function for clients that embed themselves.
01222 //        This is client side code.
01223 bool QXEmbed::processClientCmdline( QWidget* client, int& argc, char ** argv )
01224 {
01225     int myargc = argc;
01226     WId window = 0;
01227     int i, j;
01228 
01229     j = 1;
01230     for ( i=1; i<myargc; i++ ) {
01231         if ( argv[i] && *argv[i] != '-' ) {
01232             argv[j++] = argv[i];
01233             continue;
01234         }
01235         QCString arg = argv[i];
01236         if ( !strcmp(arg,"-embed") && i < myargc-1 ) {
01237             QCString s = argv[++i];
01238             window = s.toInt();
01239         } else
01240             argv[j++] = argv[i];
01241     }
01242     argc = j;
01243 
01244     if ( window ) {
01245         embedClientIntoWindow( client, window );
01246         return true;
01247     }
01248 
01249     return false;
01250 }
01251 
01252 
01253 // L2450: Utility function for clients that embed themselves.
01254 //        This is client side code.
01255 void QXEmbed::embedClientIntoWindow(QWidget* client, WId window)
01256 {
01257     initialize();
01258     XReparentWindow(qt_xdisplay(), client->winId(), window, 0, 0);
01259     // L2451: These two lines are redundant. See L0680.
01260     ((QXEmbed*)client)->topData()->embedded = true;
01261     ((QXEmbed*)client)->topData()->parentWinId = window;
01262     // L2452: This seems redundant because L2020 maps the window.
01263     //        But calling show() might also set Qt internal flags.
01264     client->show();
01265 }
01266 
01267 
01268 
01269 // L2500: Specifies that this widget can use additional space,
01270 //        and that it can survive on less than sizeHint().
01271 QSizePolicy QXEmbed::sizePolicy() const
01272 {
01273     return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
01274 }
01275 
01276 
01277 // L2520: Returns a size sufficient for the embedded window
01278 QSize QXEmbed::sizeHint() const
01279 {
01280     return minimumSizeHint();
01281 }
01282 
01283 // L2550: Returns the minimum size specified by the embedded window.
01284 QSize QXEmbed::minimumSizeHint() const
01285 {
01286     int minw = 0;
01287     int minh = 0;
01288     if ( window ) {
01289         XSizeHints size;
01290         long msize;
01291         if (XGetWMNormalHints(qt_xdisplay(), window, &size, &msize)
01292             && ( size.flags & PMinSize) ) {
01293             minw = size.min_width;
01294             minh = size.min_height;
01295         }
01296     }
01297 
01298     return QSize( minw, minh );
01299 }
01300 
01301 // L2600: Tells what shoud be done with the embedded window when
01302 //        the embedding window is destroyed. 
01303 void QXEmbed::setAutoDelete( bool b)
01304 {
01305     d->autoDelete = b;
01306 }
01307 
01308 // L2650: See L2600.
01309 bool QXEmbed::autoDelete() const
01310 {
01311     return d->autoDelete;
01312 }
01313 
01314 // L2700: See L2200.
01315 bool QXEmbed::customWhatsThis() const
01316 {
01317     return true;
01318 }
01319 
01320 // L2800: When using the XPLAIN protocol, this function maintains
01321 //        a passive button grab when (1) the application is active
01322 //        and (2) the Qt focus is not on the QXEmbed.  This passive
01323 //        grab intercepts button clicks in the client window and
01324 //        give us chance to request the Qt focus (L2060).
01325 void QXEmbed::checkGrab() 
01326 {
01327     if (d->xplain && isActiveWindow() && !hasFocus()) {
01328         if (! d->xgrab)
01329             XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, winId(),
01330                         false, ButtonPressMask, GrabModeSync, GrabModeAsync,
01331                         None, None );
01332         d->xgrab = true;
01333     } else {
01334         if (d->xgrab)
01335             XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() );
01336         d->xgrab = false;
01337     }
01338 }
01339 
01340 // L2900: This sends fake configure notify events to inform
01341 //        the client about its window geometry. See L1390, L2024 and L2090.
01342 void QXEmbed::sendSyntheticConfigureNotifyEvent() 
01343 {
01344     // L2910: It seems that the x and y coordinates are global.
01345     //        But this is what ICCCM section 4.1.5 wants.
01346     //        See http://lists.kde.org/?l=kfm-devel&m=107090222032378
01347     QPoint globalPos = mapToGlobal(QPoint(0,0));
01348     if (window) {
01349 #if 0
01350         XConfigureEvent c;
01351         memset(&c, 0, sizeof(c));
01352         c.type = ConfigureNotify;
01353         c.display = qt_xdisplay();
01354         c.send_event = True;
01355         c.event = window;
01356         c.window = window;
01357         c.x = globalPos.x();
01358         c.y = globalPos.y();
01359         c.width = width();
01360         c.height = height();
01361         c.border_width = 0;
01362         c.above = None;
01363         c.override_redirect = 0;
01364         XSendEvent( qt_xdisplay(), c.event, true, StructureNotifyMask, (XEvent*)&c );
01365 #endif
01366         // Yes, this doesn't make sense at all. See the commit message.
01367         XSetWindowBorderWidth( qt_xdisplay(), window, 1 );
01368         XSetWindowBorderWidth( qt_xdisplay(), window, 0 );
01369     }
01370 }
01371 
01372 // L3000: One should not call QWidget::reparent after embedding a window.
01373 void QXEmbed::reparent( QWidget * parent, WFlags f, const QPoint & p, bool showIt )
01374 {
01375     // QWidget::reparent() destroys the old X Window for the widget, and
01376     // creates a new one, thus QXEmbed after reparenting is no longer the
01377     // parent of the embedded window.  I think reparenting of QXEmbed can be
01378     // done only by a mistake, so just complain.
01379     Q_ASSERT( !window );
01380     QWidget::reparent( parent, f, p, showIt );
01381 }
01382 
01383 // for KDE
01384 #include "qxembed.moc"
01385 #endif // Q_WS_X11

kdeui

Skip menu "kdeui"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal