kdeui Library API Documentation

qxembed.cpp

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