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