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