qxembed.cpp
00001 /**************************************************************************** 00002 Implementation of QXEmbed class 00003 00004 Copyright (C) 1999-2002 Trolltech AS 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License as published by the Free Software Foundation; either 00009 version 2 of the License, or (at your option) any later version. 00010 00011 This library is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 Library General Public License for more details. 00015 00016 You should have received a copy of the GNU Library General Public License 00017 along with this library; see the file COPYING.LIB. If not, write to 00018 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 Boston, MA 02110-1301, USA. 00020 *****************************************************************************/ 00021 00022 00023 // L-000: About comments marked with Lxxxx. 00024 // 00025 // These comments represent an attempt to provide a more adequate 00026 // documentation to KDE developpers willing to modify QXEmbed. Keep in 00027 // mind that these comments were written long after most of the code. 00028 // Please improve them if you spot something wrong or missing 00029 // (Leon Bottou, 26-10-2003). 00030 // 00031 // Relevant documents: 00032 // - QXEmbed developper documentation 00033 // (see comments in qxembed.h) 00034 // - Xlib Reference Manual 00035 // (sections about focus, reparenting, window management) 00036 // - ICCCM Manual 00037 // (window management) 00038 // - XEMBED specification 00039 // (http://www.freedesktop.org/Standards/xembed-spec) 00040 // - XPLAIN and XEMBED. 00041 // <http://lists.kde.org/?w=2&r=1&s=qxembed+variants&q=t> 00042 // - Accumulated community knowledge. 00043 // <http://lists.kde.org/?w=2&r=1&s=qxembed&q=t> 00044 // <http://lists.kde.org/?l=kde-devel&w=2&r=1&s=qxembed&q=b> 00045 // <http://lists.kde.org/?l=kfm-devel&w=2&r=1&s=qxembed&q=b> 00046 // 00047 00048 00049 #include <qapplication.h> 00050 #include <qptrlist.h> 00051 #include <qptrdict.h> 00052 #include <qguardedptr.h> 00053 #include <qwhatsthis.h> 00054 #include <qfocusdata.h> 00055 00056 // L0001: QXEmbed works only under X windows. 00057 #ifdef Q_WS_X11 00058 00059 # include <X11/X.h> 00060 # include <X11/Xlib.h> 00061 # include <X11/Xutil.h> 00062 # include <X11/Xatom.h> 00063 # define XK_MISCELLANY 00064 # define XK_LATIN1 00065 # include <X11/keysymdef.h> 00066 # include <kdebug.h> 00067 # include <kxerrorhandler.h> 00068 00069 // L0002: Is file config.h KDE specific? 00070 # include <config.h> 00071 # ifdef HAVE_UNISTD_H 00072 # include <unistd.h> 00073 # ifdef HAVE_USLEEP 00074 # define USLEEP(x) usleep(x) 00075 # else 00076 # define USLEEP(x) sleep(0) 00077 # endif 00078 # else 00079 # define USLEEP(x) sleep(0) 00080 # endif 00081 00082 # include "qxembed.h" 00083 00084 // L0003: This keysym is used for focus navigation. 00085 # ifndef XK_ISO_Left_Tab 00086 # define XK_ISO_Left_Tab 0xFE20 00087 # endif 00088 00089 // L0004: Conflicts between X11 and Qt definitions. 00090 const int XFocusOut = FocusOut; 00091 const int XFocusIn = FocusIn; 00092 const int XKeyPress = KeyPress; 00093 const int XKeyRelease = KeyRelease; 00094 # undef KeyRelease 00095 # undef KeyPress 00096 # undef FocusOut 00097 # undef FocusIn 00098 00099 // L0005: Variables defined in qapplication_x11.cpp 00100 extern Atom qt_wm_protocols; 00101 extern Atom qt_wm_delete_window; 00102 extern Atom qt_wm_take_focus; 00103 extern Atom qt_wm_state; 00104 extern Time qt_x_time; 00105 00106 // L0006: X11 atoms private to QXEmbed 00107 static Atom xembed = 0; 00108 static Atom context_help = 0; 00109 00110 // L0007: Xembed message codes (see XEmbed spec) 00111 #define XEMBED_EMBEDDED_NOTIFY 0 00112 #define XEMBED_WINDOW_ACTIVATE 1 00113 #define XEMBED_WINDOW_DEACTIVATE 2 00114 #define XEMBED_REQUEST_FOCUS 3 00115 #define XEMBED_FOCUS_IN 4 00116 #define XEMBED_FOCUS_OUT 5 00117 #define XEMBED_FOCUS_NEXT 6 00118 #define XEMBED_FOCUS_PREV 7 00119 00120 // L0008: Xembed message details (see XEmbed spec) 00121 // -- XEMBED_FOCUS_IN: 00122 #define XEMBED_FOCUS_CURRENT 0 00123 #define XEMBED_FOCUS_FIRST 1 00124 #define XEMBED_FOCUS_LAST 2 00125 00126 00127 // L0100: Private data held by the QXEmbed object. 00128 // This belongs to the embedder side. 00129 class QXEmbedData 00130 { 00131 public: 00132 QXEmbedData(){ 00133 autoDelete = true; 00134 xplain = false; 00135 xgrab = false; 00136 mapAfterRelease = false; 00137 lastPos = QPoint(0,0); 00138 } 00139 ~QXEmbedData(){} 00140 00141 bool autoDelete; // L0101: See L2600 00142 bool xplain; // L0102: See L1100 00143 bool xgrab; // L0103: See L2800 00144 bool mapAfterRelease; 00145 QWidget* focusProxy; // L0104: See XEmbed spec 00146 QPoint lastPos; // L0105: See L1390 00147 }; 00148 00149 namespace 00150 { 00151 // L0200: This application wide event filter handles focus 00152 // issues in the embedded client. 00153 class QXEmbedAppFilter : public QObject 00154 { 00155 public: 00156 QXEmbedAppFilter() { qApp->installEventFilter( this ); } 00157 ~QXEmbedAppFilter() { } 00158 bool eventFilter( QObject *, QEvent * ); 00159 }; 00160 } 00161 00162 // L0201: See L0200, L0740 00163 static QXEmbedAppFilter* filter = 0; 00164 // L0202: See L0610, L0730 00165 static QPtrDict<QGuardedPtr<QWidget> > *focusMap = 0; 00166 // L0203: See L0660, L1400, L1450 00167 static XKeyEvent last_key_event; 00168 00169 // L0300: This class gives access protected members of class QWidget. 00170 // Function focusData() is useful to reimplement tab focus management 00171 // (L0620) Function topData() returns a structure QTLWExtra containing 00172 // information unique to toplevel windows. This structure contains two 00173 // members for the sole use of QXEmbed. Flag `embedded' indicates whether 00174 // the toplevel window is embedded using the XEMBED protocol (L0680). 00175 // Handle `parentWinId' then records the id of the embedding window. 00176 00177 class QPublicWidget : public QWidget 00178 { 00179 public: 00180 QTLWExtra* topData() { return QWidget::topData(); } 00181 QFocusData *focusData(){ return QWidget::focusData(); } 00182 bool focusNextPrev(bool b) { return focusNextPrevChild(b); } 00183 }; 00184 00185 // L0400: This sets a very low level filter for X11 messages. 00186 // See qapplication_x11.cpp 00187 typedef int (*QX11EventFilter) (XEvent*); 00188 extern QX11EventFilter qt_set_x11_event_filter (QX11EventFilter filter); 00189 static QX11EventFilter oldFilter = 0; 00190 00191 00192 // L0500: Helper to send XEmbed messages. 00193 static void sendXEmbedMessage( WId window, long message, long detail = 0, 00194 long data1 = 0, long data2 = 0) 00195 { 00196 if (!window) return; 00197 XEvent ev; 00198 memset(&ev, 0, sizeof(ev)); 00199 ev.xclient.type = ClientMessage; 00200 ev.xclient.window = window; 00201 ev.xclient.message_type = xembed; 00202 ev.xclient.format = 32; 00203 ev.xclient.data.l[0] = qt_x_time; 00204 ev.xclient.data.l[1] = message; 00205 ev.xclient.data.l[2] = detail; 00206 ev.xclient.data.l[3] = data1; 00207 ev.xclient.data.l[4] = data2; 00208 XSendEvent(qt_xdisplay(), window, false, NoEventMask, &ev); 00209 } 00210 00211 // L0501: Helper to send ICCCM Client messages. 00212 // See X11 ICCCM Specification. 00213 static void sendClientMessage(Window window, Atom a, long x) 00214 { 00215 if (!window) return; 00216 XEvent ev; 00217 memset(&ev, 0, sizeof(ev)); 00218 ev.xclient.type = ClientMessage; 00219 ev.xclient.window = window; 00220 ev.xclient.message_type = a; 00221 ev.xclient.format = 32; 00222 ev.xclient.data.l[0] = x; 00223 ev.xclient.data.l[1] = qt_x_time; 00224 XSendEvent(qt_xdisplay(), window, false, NoEventMask, &ev); 00225 } 00226 00227 // L0502: Helper to send fake X11 focus messages. 00228 // See X11 Reference Manual and Window Management stuff. 00229 static void sendFocusMessage(Window window, int type, int mode, int detail) 00230 { 00231 if (!window) return; 00232 XEvent ev; 00233 memset(&ev, 0, sizeof(ev)); 00234 ev.xfocus.type = type; 00235 ev.xfocus.window = window; 00236 ev.xfocus.mode = mode; 00237 ev.xfocus.detail = detail; 00238 XSendEvent(qt_xdisplay(), window, false, FocusChangeMask, &ev); 00239 } 00240 00241 00242 // ------------------------------------------------------------ 00243 // L0600: MOST OF WHAT FOLLOWS CONCERNS THE CLIENT SIDE. 00244 // The following code mostly executes inside a Qt application swallowed 00245 // by QXEmbed widget. It mostly consists of event filters that fight 00246 // the normal Qt mechanisms in order to implement the XEMBED protocol. 00247 // All this would be a lot simpler if it was implemented by Qt itself. 00248 00249 00250 00251 // L0610: This event filter receives all Qt events. Its main purpose is to 00252 // capture the Qt focus events in the embedded client in order to 00253 // implement the XEMBED protocol. 00254 // 00255 // Let's start with a few reminders: 00256 // 00257 // - X11 only has the concept of the "X11 focus window". This window 00258 // basically receives all key events. The ICCCM conventions define 00259 // how the window manager and the applications must cooperate to 00260 // choose the X11 focus window. 00261 // 00262 // - Most toolkits, including Qt, maintain the concepts of 'active 00263 // widget' and 'Qt focus widget'. A toplevel widget is active when 00264 // the X11 focus is set to one of its children. By extension a 00265 // widget is active when its toplevel widget is active. There is one 00266 // Qt focus widget for each toplevel widget. When the toplevel 00267 // widget is active, all key events are sent to the Qt focus widget, 00268 // regardless of which descendant of the toplevel window has the X11 00269 // focus. Widgets can adjust their appearance according to both 00270 // their activation and focus states. The Qt FocusIn and FocusOut 00271 // events indicate when a widget simultaneously is active and has 00272 // the Qt focus. 00273 // 00274 // The XEMBED protocol defines ways to communicate abouth both 00275 // activation and focus. The embedded client is active as soon as the 00276 // embedding window is active (L0676, L0677). A widget in the embedded 00277 // client receives key events when (1) it has the Qt focus in the 00278 // embedded application, and (2) the QXEmbed widget in the embedding 00279 // application is active and has the Qt focus. The Qt library in the 00280 // embedded application is unaware of the focus status of the QXEmbed 00281 // widget. We must make sure it does the right thing regarding the 00282 // sending of focus events and the visual appearance of the focussed 00283 // widgets. When the QXEmbed widget looses the Qt focus, we clear the 00284 // focus in the embedded client (L1570, L0688). Conversely, when 00285 // the QXEmbed widget gains the Qt focus, we restore the Qt focus 00286 // window in the embedded client (L1530, L0680, L0683). 00287 // Variable focusMap is used to remember which was the Qt focus 00288 // widget in the embedded application. All this would be a lot 00289 // simpler if it was implemented inside Qt... 00290 // 00291 // The XPLAIN protocol is much less refined in this respect. 00292 // The activation status of the embedded client simply reflect 00293 // the focus status of the QXEmbed widget. This is achieved 00294 // by sending fake X11 focus message to the client (L1521, L1561). 00295 // A passive button grab (L2800) intercepts mouse activity in the 00296 // embedded client and sets the Qt focus to the QXEmbed widget 00297 // when this happens (L2060). This can be achieved without 00298 // cooperation from the client. 00299 00300 bool QXEmbedAppFilter::eventFilter( QObject *o, QEvent * e) 00301 { 00302 static bool obeyFocus = false; 00303 switch ( e->type() ) { 00304 case QEvent::MouseButtonPress: 00305 // L0612: This will become clear with L0614 00306 if ( !((QWidget*)o)->isActiveWindow() ) 00307 obeyFocus = true; 00308 break; 00309 case QEvent::FocusIn: 00310 // L0613: FocusIn events either occur because the widget already was 00311 // active and has just been given the Qt focus (L0614) or 00312 // because the widget already had the Qt focus and just became 00313 // active (L0615). 00314 if ( qApp->focusWidget() == o && 00315 ((QPublicWidget*)qApp->focusWidget()->topLevelWidget())->topData()->embedded ) { 00316 QFocusEvent* fe = (QFocusEvent*) e; 00317 if ( obeyFocus || fe->reason() == QFocusEvent::Mouse || 00318 fe->reason() == QFocusEvent::Shortcut ) { 00319 // L0614: A widget in the embedded client was just given the Qt focus. 00320 // Variable `obeyFocus' suggests that this is the result of mouse 00321 // activity in the client. The XEMBED_REQUEST_FOCUS message causes 00322 // the embedding widget to take the Qt focus (L2085). 00323 WId window = ((QPublicWidget*)qApp->focusWidget()->topLevelWidget())->topData()->parentWinId; 00324 focusMap->remove( qApp->focusWidget()->topLevelWidget() ); 00325 sendXEmbedMessage( window, XEMBED_REQUEST_FOCUS ); 00326 } else if ( fe->reason() == QFocusEvent::ActiveWindow ) { 00327 // L0615: Both the embedder and the embedded client became active. 00328 // But we do not know whether the QXEmbed widget has the Qt focus. 00329 // So we clear the Qt focus for now. If indeed the QXEmbed widget 00330 // has the focus, it will receive a FocusIn message (L1530) and 00331 // tell us to restore the focus (L0680, L0683). 00332 focusMap->remove( qApp->focusWidget()->topLevelWidget() ); 00333 focusMap->insert( qApp->focusWidget()->topLevelWidget(), 00334 new QGuardedPtr<QWidget>(qApp->focusWidget()->topLevelWidget()->focusWidget() ) ); 00335 // L0616: qApp->focusWidget() might belong to a modal dialog and not be 00336 // equal to qApp->focusWidget()->topLevelWidget()->focusWidget() ! 00337 qApp->focusWidget()->clearFocus(); 00338 // L0617: ??? [why not {obeyFocus=false; return true;} here?] 00339 } 00340 obeyFocus = false; 00341 } 00342 break; 00343 case QEvent::KeyPress: 00344 if (qApp->focusWidget() == o && 00345 ((QPublicWidget*)qApp->focusWidget()->topLevelWidget())->topData()->embedded ) { 00346 // L0620: The following code replaces the Qt code that 00347 // handles focus focus changes with the tab key. See the 00348 // XEMBED specification for details. The keypress event 00349 // arrives here after an interesting itinerary. It is first 00350 // saved in the embedding application (L0660). After being 00351 // rejected for tab navigation in the embedding application 00352 // (L1901), it gets forwarded to the embedded client 00353 // (L1400) and arrives here. Depending on the status of 00354 // the tab chain in the embedded client, focus navigation 00355 // messages are sent back to the embedding application 00356 // (L0653, L0654) which then performs tab navigation 00357 // (L2081). 00358 QKeyEvent *k = (QKeyEvent *)e; 00359 QWidget *w = qApp->focusWidget(); 00360 // L0621: The following tests are copied from QWidget::event(). 00361 bool res = false; 00362 bool tabForward = true; 00363 if ( !(k->state() & ControlButton || k->state() & AltButton) ) { 00364 if ( k->key() == Key_Backtab || (k->key() == Key_Tab && (k->state() & ShiftButton)) ) { 00365 QFocusEvent::setReason( QFocusEvent::Backtab ); 00366 res = ((QPublicWidget*)w)->focusNextPrev( tabForward = false ); 00367 QFocusEvent::resetReason(); 00368 } else if ( k->key() == Key_Tab ) { 00369 QFocusEvent::setReason( QFocusEvent::Tab ); 00370 res = ((QPublicWidget*)w)->focusNextPrev( tabForward = true ); 00371 QFocusEvent::resetReason(); 00372 } 00373 } 00374 if (res) { 00375 // L0625: We changed the focus because of tab/backtab key 00376 // Now check whether we have been looping around. 00377 QFocusData *fd = ((QPublicWidget*)w)->focusData(); 00378 WId window = ((QPublicWidget*)w->topLevelWidget())->topData()->parentWinId; 00379 QWidget *cw = 0; 00380 QWidget *fw = fd->home(); 00381 if (tabForward && window) { 00382 while (cw != w && cw != fw && cw != w->topLevelWidget()) 00383 cw = fd->prev(); 00384 if (cw != w) 00385 sendXEmbedMessage( window, XEMBED_FOCUS_NEXT ); 00386 } else if (window) { 00387 while (cw != w && cw != fw && cw != w->topLevelWidget()) 00388 cw = fd->next(); 00389 if (cw != w) 00390 sendXEmbedMessage( window, XEMBED_FOCUS_PREV ); 00391 } 00392 // L0628: Qt should no longer process this event. 00393 return true; 00394 } 00395 } 00396 break; 00397 default: 00398 break; 00399 } 00400 // L0640: Application gets to see the events anyway. 00401 return false; 00402 } 00403 00404 // L0650: This filter receives all XEvents in both the client and the embedder. 00405 // Most of it involves the embedded client (except L0660, L0671). 00406 static int qxembed_x11_event_filter( XEvent* e) 00407 { 00408 switch ( e->type ) { 00409 case XKeyPress: 00410 case XKeyRelease: { 00411 // L0660: This is for the embedding side (L1450). 00412 last_key_event = e->xkey; 00413 break; 00414 } 00415 case ClientMessage: 00416 if ( e->xclient.message_type == xembed ) { 00417 // L0670: This is where the XEmbed messages are 00418 // processed on the client side. 00419 Time msgtime = (Time) e->xclient.data.l[0]; 00420 long message = e->xclient.data.l[1]; 00421 long detail = e->xclient.data.l[2]; 00422 // L0671: Keep Qt message time up to date 00423 if ( msgtime > qt_x_time ) 00424 qt_x_time = msgtime; 00425 QWidget* w = QWidget::find( e->xclient.window ); 00426 if ( !w ) 00427 break; 00428 switch ( message) { 00429 case XEMBED_EMBEDDED_NOTIFY: { 00430 // L0675: We just have been embedded into a XEMBED aware widget. 00431 QTLWExtra *extra = ((QPublicWidget*)w->topLevelWidget())->topData(); 00432 extra->embedded = 1; 00433 extra->parentWinId = e->xclient.data.l[3]; 00434 w->topLevelWidget()->show(); 00435 break; 00436 } 00437 case XEMBED_WINDOW_ACTIVATE: { 00438 // L0676: Embedding window becomes active. Send a fake XFocusIn 00439 // to convince Qt that we are active as well. Qt will send 00440 // us a focus notification (L0615) that we will intercept to 00441 // ensure that we have no Qt focus widget yet. The Qt focus 00442 // widget might later be set in L0680. 00443 XEvent ev; 00444 memset(&ev, 0, sizeof(ev)); 00445 ev.xfocus.display = qt_xdisplay(); 00446 ev.xfocus.type = XFocusIn; 00447 ev.xfocus.window = w->topLevelWidget()->winId(); 00448 ev.xfocus.mode = NotifyNormal; 00449 ev.xfocus.detail = NotifyAncestor; 00450 qApp->x11ProcessEvent( &ev ); 00451 } 00452 break; 00453 case XEMBED_WINDOW_DEACTIVATE: { 00454 // L0677: Embedding window becomes inactive. Send a fake XFocusOut 00455 // event to convince Qt that we no longer are active. We will 00456 // receive extra Qt FocusOut events but we do not care. 00457 XEvent ev; 00458 memset(&ev, 0, sizeof(ev)); 00459 ev.xfocus.display = qt_xdisplay(); 00460 ev.xfocus.type = XFocusOut; 00461 ev.xfocus.window = w->topLevelWidget()->winId(); 00462 ev.xfocus.mode = NotifyNormal; 00463 ev.xfocus.detail = NotifyAncestor; 00464 qApp->x11ProcessEvent( &ev ); 00465 } 00466 break; 00467 case XEMBED_FOCUS_IN: 00468 // L0680: Embedding application gives us the focus. 00469 { 00470 // L0681: Search saved focus widget. 00471 QWidget* focusCurrent = 0; 00472 QGuardedPtr<QWidget>* fw = focusMap->find( w->topLevelWidget() ); 00473 if ( fw ) { 00474 focusCurrent = *fw; 00475 // L0682: Remove it from the map 00476 focusMap->remove( w->topLevelWidget() ); 00477 } 00478 switch ( detail ) { 00479 case XEMBED_FOCUS_CURRENT: 00480 // L0683: Set focus on saved focus widget 00481 if ( focusCurrent ) 00482 focusCurrent->setFocus(); 00483 else if ( !w->topLevelWidget()->focusWidget() ) 00484 w->topLevelWidget()->setFocus(); 00485 break; 00486 case XEMBED_FOCUS_FIRST: 00487 { 00488 // L0684: Search first widget in tab chain 00489 QFocusEvent::setReason( QFocusEvent::Tab ); 00490 w->topLevelWidget()->setFocus(); 00491 ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(true); 00492 QFocusEvent::resetReason(); 00493 } 00494 break; 00495 case XEMBED_FOCUS_LAST: 00496 { 00497 // L0686: Search last widget in tab chain 00498 QFocusEvent::setReason( QFocusEvent::Backtab ); 00499 w->topLevelWidget()->setFocus(); 00500 ((QPublicWidget*)w->topLevelWidget())->focusNextPrev(false); 00501 QFocusEvent::resetReason(); 00502 } 00503 break; 00504 default: 00505 break; 00506 } 00507 } 00508 break; 00509 case XEMBED_FOCUS_OUT: 00510 // L0688: Embedding application takes the focus away 00511 // We first record what the focus widget was 00512 // and clear the Qt focus. 00513 if ( w->topLevelWidget()->focusWidget() ) { 00514 focusMap->insert( w->topLevelWidget(), 00515 new QGuardedPtr<QWidget>(w->topLevelWidget()->focusWidget() ) ); 00516 w->topLevelWidget()->focusWidget()->clearFocus(); 00517 } 00518 break; 00519 default: 00520 break; 00521 } 00522 } else if ( e->xclient.format == 32 && e->xclient.message_type ) { 00523 if ( e->xclient.message_type == qt_wm_protocols ) { 00524 QWidget* w = QWidget::find( e->xclient.window ); 00525 if ( !w ) 00526 break; 00527 // L0690: This is for the embedding side! 00528 // See L0902 for more information about the focus proxy. 00529 // Window manager may send WM_TAKE_FOCUS messages to the 00530 // embedding application to indicate that it becomes active. 00531 // But this also suggests that the window manager has 00532 // changed the X11 focus. We want to make sure it goes 00533 // to the focus proxy window eventually. 00534 Atom a = e->xclient.data.l[0]; 00535 if ( a == qt_wm_take_focus ) { 00536 // L0695: update Qt message time variable 00537 if ( (ulong) e->xclient.data.l[1] > qt_x_time ) 00538 qt_x_time = e->xclient.data.l[1]; 00539 // L0696: There is no problem when the window is not active. 00540 // Qt will generate a WindowActivate event that will 00541 // do the job (L1310). This does not happen if the 00542 // window is already active. So we simulate it. 00543 if ( w->isActiveWindow() ) { 00544 QEvent e( QEvent::WindowActivate ); 00545 QApplication::sendEvent( w, &e ); 00546 } 00547 } 00548 } 00549 } 00550 break; 00551 default: 00552 break; 00553 } 00554 // L0698: The next x11 filter 00555 if ( oldFilter ) 00556 return oldFilter( e ); 00557 // L0699: Otherwise process the event as usual. 00558 return false; 00559 } 00560 00561 00562 00563 // L0700: Install the xembed filters in both client and embedder sides. 00564 // This function is called automatically when using 00565 // embedClientIntoWindow() or creating an instance of QXEmbed You may 00566 // have to call it manually for a client when using embedder-side 00567 // embedding, though. 00568 void QXEmbed::initialize() 00569 { 00570 static bool is_initialized = false; 00571 if ( is_initialized ) 00572 return; 00573 00574 // L0710: Atom used by the XEMBED protocol. 00575 xembed = XInternAtom( qt_xdisplay(), "_XEMBED", false ); 00576 // L0720: Install low level filter for X11 events (L0650) 00577 oldFilter = qt_set_x11_event_filter( qxembed_x11_event_filter ); 00578 // L0730: See L0610 for an explanation about focusMap. 00579 focusMap = new QPtrDict<QGuardedPtr<QWidget> >; 00580 focusMap->setAutoDelete( true ); 00581 // L0740: Create client side application wide event filter (L0610) 00582 filter = new QXEmbedAppFilter; 00583 00584 is_initialized = true; 00585 } 00586 00587 00588 00589 00590 00591 // ------------------------------------------------------------ 00592 // L0800: MOST OF WHAT FOLLOWS CONCERNS THE EMBEDDER SIDE. 00593 // Things that happen inside a Qt application that contain 00594 // a QXEmbed widget for embedding other applications. 00595 // This applies to both the XEMBED and XPLAIN protocols. 00596 // Deviations are commented below. 00597 00598 00599 00600 // L0810: Class QXEmbed. 00601 // A QXEmbed widget serves as an embedder that can manage one single 00602 // embedded X-window. These so-called client windows can be arbitrary 00603 // Qt or non Qt applications. There are two different ways of using 00604 // QXEmbed, from the client side or from the embedder's side. 00605 00606 00607 // L0900: Constructs a xembed widget. 00608 QXEmbed::QXEmbed(QWidget *parent, const char *name, WFlags f) 00609 : QWidget(parent, name, f) 00610 { 00611 // L0901: Create private data. See L0100. 00612 d = new QXEmbedData; 00613 // L0902: Create focus proxy widget. See XEmbed specification. 00614 // Each QXEmbed widget has a focus proxy window. Every single 00615 // QXEmbed widget tries to force its focus proxy window onto the 00616 // whole embedding application. They compete between themselves and 00617 // against Qt (L0690, L0914, L1040, L1310, L1510, L1580). 00618 // This would be much simpler if implemented within Qt. 00619 d->focusProxy = new QWidget( topLevelWidget(), "xembed_focus" ); 00620 d->focusProxy->setGeometry( -1, -1, 1, 1 ); 00621 d->focusProxy->show(); 00622 // make sure it's shown - for XSetInputFocus 00623 QApplication::sendPostedEvents( d->focusProxy, 0 ); 00624 // L0903: Install the client side event filters 00625 // because they also provide services for the embedder side 00626 // See L0660, L0671, L0685. 00627 initialize(); 00628 window = 0; 00629 setFocusPolicy(StrongFocus); 00630 setKeyCompression( false ); 00631 00632 // L0910: Trick Qt to create extraData(); 00633 (void) topData(); 00634 00635 // L0912: We are mostly interested in SubstructureNotify 00636 // This is sent when something happens to the children of 00637 // the X11 window associated with the QXEmbed widget. 00638 XSelectInput(qt_xdisplay(), winId(), 00639 KeyPressMask | KeyReleaseMask | 00640 ButtonPressMask | ButtonReleaseMask | 00641 KeymapStateMask | 00642 ButtonMotionMask | 00643 PointerMotionMask | // may need this, too 00644 EnterWindowMask | LeaveWindowMask | 00645 FocusChangeMask | 00646 ExposureMask | 00647 StructureNotifyMask | 00648 SubstructureRedirectMask | 00649 SubstructureNotifyMask 00650 ); 00651 // L0913: all application events pass through eventFilter(). 00652 // This is mostly used to force the X11 focus on the 00653 // proxy focus window. See L1300. 00654 topLevelWidget()->installEventFilter( this ); 00655 qApp->installEventFilter( this ); 00656 00657 // L0914: Start moving the X11 focus on the focus proxy window. 00658 // See L1581 to know why we do not use isActiveWindow(). 00659 if ( qApp->activeWindow() == topLevelWidget() ) 00660 if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded ) 00661 XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 00662 RevertToParent, qt_x_time ); 00663 // L0915: ??? [drag&drop?] 00664 setAcceptDrops( true ); 00665 } 00666 00667 // L1000: Destructor must dispose of the embedded client window. 00668 QXEmbed::~QXEmbed() 00669 { 00670 // L1010: Make sure no pointer grab is left. 00671 if ( d && d->xgrab) 00672 XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() ); 00673 if ( window && ( autoDelete() || !d->xplain )) 00674 { 00675 // L1021: Hide the window and safely reparent it into the root, 00676 // otherwise it would be destroyed by X11 together 00677 // with this QXEmbed's window. 00678 #if 0 00679 // TODO: The proper XEmbed way would be to unmap the window, and the embedded 00680 // app would detect the embedding has ended, and do whatever it finds appropriate. 00681 // However, QXEmbed currently doesn't provide support for this detection, 00682 // so for the time being, it's better to leave the window mapped as toplevel window. 00683 // This will be ever more complicated with the systray windows, as the simple API 00684 // for them (KWin::setSystemTrayWindowFor()) doesn't make it possible to detect 00685 // themselves they have been released from systray, but KWin requires them 00686 // to be visible to allow next Kicker instance to swallow them. 00687 // See also below the L1022 comment. 00688 // XUnmapWindow( qt_xdisplay(), window ); 00689 #else 00690 if( autoDelete()) 00691 XUnmapWindow( qt_xdisplay(), window ); 00692 #endif 00693 XReparentWindow(qt_xdisplay(), window, qt_xrootwin(), 0, 0); 00694 if( !d->xplain ) 00695 XRemoveFromSaveSet( qt_xdisplay(), window ); 00696 if( d->mapAfterRelease ) 00697 XMapWindow( qt_xdisplay(), window ); 00698 XSync(qt_xdisplay(), false); 00699 // L1022: Send the WM_DELETE_WINDOW message 00700 if( autoDelete() /*&& d->xplain*/ ) 00701 // This sendDelete should only apply to XPLAIN. 00702 // XEMBED apps are supposed to detect when the embedding ends. 00703 // ??? [We do not do this detection yet! 00704 // So we sendDelete() instead.] 00705 sendDelete(); 00706 } 00707 window = 0; 00708 // L01040: Our focus proxy window will be destroyed as well. 00709 // Make sure that the X11 focus is not lost in the process. 00710 Window focus; 00711 int revert; 00712 XGetInputFocus( qt_xdisplay(), &focus, &revert ); 00713 if( focus == d->focusProxy->winId()) 00714 XSetInputFocus( qt_xdisplay(), topLevelWidget()->winId(), RevertToParent, qt_x_time ); 00715 // L01045: Delete our private data. 00716 delete d; 00717 } 00718 00719 00720 // L1050: Sends a WM_DELETE_WINDOW message to the embedded window. This is 00721 // what typically happens when you click on the close button of a 00722 // window manager decoration. 00723 void QXEmbed::sendDelete( void ) 00724 { 00725 if (window) 00726 { 00727 sendClientMessage(window, qt_wm_protocols, qt_wm_delete_window); 00728 XFlush( qt_xdisplay() ); 00729 } 00730 } 00731 00732 // L1100: Sets the protocol used for embedding windows. 00733 // This function must be called before embedding a window. 00734 // Protocol XEMBED provides maximal functionality (focus, tabs, etc) 00735 // but requires explicit cooperation from the embedded window. 00736 // Protocol XPLAIN provides maximal compatibility with 00737 // embedded applications that do not support the XEMBED protocol. 00738 // The default is XEMBED. 00739 void QXEmbed::setProtocol( Protocol proto ) 00740 { 00741 if (!window) { 00742 d->xplain = false; 00743 if (proto == XPLAIN) 00744 d->xplain = true; 00745 } 00746 } 00747 00748 // L1150: Returns the protocol used for embedding the current window. 00749 QXEmbed::Protocol QXEmbed::protocol() 00750 { 00751 if (d->xplain) 00752 return XPLAIN; 00753 return XEMBED; 00754 } 00755 00756 00757 // L1200: QXEmbed widget size changes: resize embedded window. 00758 void QXEmbed::resizeEvent(QResizeEvent*) 00759 { 00760 if (window) 00761 XResizeWindow(qt_xdisplay(), window, width(), height()); 00762 } 00763 00764 // L1250: QXEmbed widget is shown: make sure embedded window is visible. 00765 void QXEmbed::showEvent(QShowEvent*) 00766 { 00767 if (window) 00768 XMapRaised(qt_xdisplay(), window); 00769 } 00770 00771 00772 // L1300: This event filter sees all application events (L0913). 00773 bool QXEmbed::eventFilter( QObject *o, QEvent * e) 00774 { 00775 00776 switch ( e->type() ) { 00777 case QEvent::WindowActivate: 00778 if ( o == topLevelWidget() ) { 00779 // L1310: Qt thinks the application window has just been activated. 00780 // Make sure the X11 focus is on the focus proxy window. See L0686. 00781 if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded ) 00782 if (! hasFocus() ) 00783 XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 00784 RevertToParent, qt_x_time ); 00785 if (d->xplain) 00786 // L1311: Activation has changed. Grab state might change. See L2800. 00787 checkGrab(); 00788 else 00789 // L1312: Let the client know that we just became active 00790 sendXEmbedMessage( window, XEMBED_WINDOW_ACTIVATE ); 00791 } 00792 break; 00793 case QEvent::WindowDeactivate: 00794 if ( o == topLevelWidget() ) { 00795 if (d->xplain) 00796 // L1321: Activation has changed. Grab state might change. See L2800. 00797 checkGrab(); 00798 else 00799 // L1322: Let the client know that we are no longer active 00800 sendXEmbedMessage( window, XEMBED_WINDOW_DEACTIVATE ); 00801 } 00802 break; 00803 case QEvent::Move: 00804 { 00805 QWidget* pos = this; 00806 while( pos != o && pos != topLevelWidget()) 00807 pos = pos->parentWidget(); 00808 if( pos == o ) { 00809 // L1390: Send fake configure notify events whenever the 00810 // global position of the client changes. See L2900. 00811 QPoint globalPos = mapToGlobal(QPoint(0,0)); 00812 if (globalPos != d->lastPos) { 00813 d->lastPos = globalPos; 00814 sendSyntheticConfigureNotifyEvent(); 00815 } 00816 } 00817 } 00818 break; 00819 default: 00820 break; 00821 } 00822 return false; 00823 } 00824 00825 // L1350: ??? [why this?] 00826 bool QXEmbed::event( QEvent * e) 00827 { 00828 return QWidget::event( e ); 00829 } 00830 00831 // L1400: Forward keypress event to the client 00832 // Receiving a Qt key event indicates that 00833 // the QXEmbed object has the Qt focus. 00834 // The X11 event that caused the Qt key event 00835 // must be forwarded to the client. 00836 // See L0660. 00837 void QXEmbed::keyPressEvent( QKeyEvent *) 00838 { 00839 if (!window) 00840 return; 00841 last_key_event.window = window; 00842 XSendEvent(qt_xdisplay(), window, false, KeyPressMask, (XEvent*)&last_key_event); 00843 00844 } 00845 00846 // L1450: Forward keyrelease event to the client. 00847 // See comment L1400. 00848 void QXEmbed::keyReleaseEvent( QKeyEvent *) 00849 { 00850 if (!window) 00851 return; 00852 last_key_event.window = window; 00853 XSendEvent(qt_xdisplay(), window, false, KeyReleaseMask, (XEvent*)&last_key_event); 00854 } 00855 00856 // L1500: Handle Qt focus in event. 00857 void QXEmbed::focusInEvent( QFocusEvent * e ){ 00858 if (!window) 00859 return; 00860 // L1510: This is a good time to set the X11 focus on the focus proxy window. 00861 // Except if the the embedding application itself is embedded into another. 00862 if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded ) 00863 if ( qApp->activeWindow() == topLevelWidget() ) 00864 // L1511: Alter X focus only when window is active. 00865 // This is dual safety here because FocusIn implies this. 00866 // But see L1581 for an example where this really matters. 00867 XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 00868 RevertToParent, qt_x_time ); 00869 if (d->xplain) { 00870 // L1520: Qt focus has changed. Grab state might change. See L2800. 00871 checkGrab(); 00872 // L1521: Window managers activate applications by setting the X11 focus. 00873 // We cannot do this (see L1510) but we can send a fake focus event 00874 // and forward the X11 key events ourselves (see L1400, L1450). 00875 sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer ); 00876 } else { 00877 // L1530: No need for fake events with XEMBED. 00878 // Just inform the client. It knows what to do. 00879 int detail = XEMBED_FOCUS_CURRENT; 00880 // L1531: When the focus change is caused by the tab key, 00881 // the client must select the first (or last) widget of 00882 // its own tab chain. 00883 if ( e->reason() == QFocusEvent::Tab ) 00884 detail = XEMBED_FOCUS_FIRST; 00885 else if ( e->reason() == QFocusEvent::Backtab ) 00886 detail = XEMBED_FOCUS_LAST; 00887 sendXEmbedMessage( window, XEMBED_FOCUS_IN, detail); 00888 } 00889 } 00890 00891 // L1550: Handle Qt focus out event. 00892 void QXEmbed::focusOutEvent( QFocusEvent * ){ 00893 if (!window) 00894 return; 00895 if (d->xplain) { 00896 // L1560: Qt focus has changed. Grab state might change. See L2800. 00897 checkGrab(); 00898 // L1561: Send fake focus out message. See L1521. 00899 sendFocusMessage(window, XFocusOut, NotifyNormal, NotifyPointer ); 00900 } else { 00901 // L1570: Send XEMBED focus out message. See L1531. 00902 sendXEmbedMessage( window, XEMBED_FOCUS_OUT ); 00903 } 00904 // L1580: The QXEmbed object might loose the focus because its 00905 // toplevel window looses the X11 focus and is no longer active, 00906 // or simply because the Qt focus has been moved to another widget. 00907 // In the latter case only, we want to make sure that the X11 focus 00908 // is properly set to the X11 focus widget. We do this because 00909 // the client application might have moved the X11 focus after 00910 // receiving the fake focus messages. 00911 if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded ) 00912 if ( qApp->activeWindow() == topLevelWidget() ) 00913 // L1581: Alter X focus only when window is active. 00914 // The test above is not the same as isActiveWindow(). 00915 // Function isActiveWindow() also returns true when a modal 00916 // dialog child of this window is active. 00917 XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 00918 RevertToParent, qt_x_time ); 00919 } 00920 00921 00922 // L1600: Helper for QXEmbed::embed() 00923 // Check whether a window is in withdrawn state. 00924 static bool wstate_withdrawn( WId winid ) 00925 { 00926 Atom type; 00927 int format; 00928 unsigned long length, after; 00929 unsigned char *data; 00930 int r = XGetWindowProperty( qt_xdisplay(), winid, qt_wm_state, 0, 2, 00931 false, AnyPropertyType, &type, &format, 00932 &length, &after, &data ); 00933 bool withdrawn = true; 00934 // L1610: Non managed windows have no WM_STATE property. 00935 // Returning true ensures that the loop L1711 stops. 00936 if ( r == Success && data && format == 32 ) { 00937 Q_UINT32 *wstate = (Q_UINT32*)data; 00938 withdrawn = (*wstate == WithdrawnState ); 00939 XFree( (char *)data ); 00940 } 00941 return withdrawn; 00942 } 00943 00944 // L1650: Helper for QXEmbed::embed() 00945 // Get the X11 id of the parent window. 00946 static int get_parent(WId winid, Window *out_parent) 00947 { 00948 Window root, *children=0; 00949 unsigned int nchildren; 00950 int st = XQueryTree(qt_xdisplay(), winid, &root, out_parent, &children, &nchildren); 00951 if (st && children) 00952 XFree(children); 00953 return st; 00954 } 00955 00956 // L1700: Embeds the window w into this QXEmbed widget. 00957 // See doc in qxembed.h. 00958 void QXEmbed::embed(WId w) 00959 { 00960 kdDebug() << "*** Embed " << w << " into " << winId() << ". window=" << window << endl; 00961 if (!w) 00962 return; 00963 // L1701: The has_window variable prevents embedding a same window twice. 00964 // ??? [what happens if one embed two windows into the same QXEmbed?] 00965 bool has_window = (w == window); 00966 window = w; 00967 if ( !has_window ) { 00968 KXErrorHandler errhandler; // make X BadWindow errors silent 00969 // L1710: Try hard to withdraw the window. 00970 // This makes sure that the window manager will 00971 // no longer try to manage this window. 00972 if ( !wstate_withdrawn(window) ) { 00973 XWithdrawWindow(qt_xdisplay(), window, qt_xscreen()); 00974 QApplication::flushX(); 00975 // L1711: See L1610 00976 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