• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kdeui
 

kdeui

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

kdeui

Skip menu "kdeui"
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • krandr
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for kdeui by doxygen 1.7.6.1
This website is maintained by Timothy Pearson.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. |