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 #include <qapplication.h>
00023 #include <qptrlist.h>
00024 #include <qptrdict.h>
00025 #include <qguardedptr.h>
00026 #include <qwhatsthis.h>
00027 #include <qfocusdata.h>
00028 #ifdef Q_WS_X11
00029 #include <X11/X.h>
00030 #include <X11/Xlib.h>
00031 #include <X11/Xutil.h>
00032 #include <X11/Xatom.h>
00033 #define XK_MISCELLANY
00034 #define XK_LATIN1
00035 #include <X11/keysymdef.h>
00036 #include <kdebug.h>
00037 //#include <kxeventutil.h>
00038 //#include <kqeventutil.h>
00039 #include <config.h>
00040 
00041 #ifdef HAVE_UNISTD_H
00042 #include <unistd.h>
00043 #ifdef HAVE_USLEEP
00044 #define USLEEP(x) usleep(x)
00045 #else
00046 #define USLEEP(x) sleep(0)
00047 #endif // HAVE_USLEEP
00048 #else
00049 #define USLEEP(x) sleep(0)
00050 #endif // HAVE_UNISTD_H
00051 
00052 #include "qxembed.h"
00053 
00054 #ifndef XK_ISO_Left_Tab
00055 #define XK_ISO_Left_Tab                                 0xFE20
00056 #endif
00057 const int XFocusOut = FocusOut;
00058 const int XFocusIn = FocusIn;
00059 const int XKeyPress = KeyPress;
00060 const int XKeyRelease = KeyRelease;
00061 #undef KeyRelease
00062 #undef KeyPress
00063 #undef FocusOut
00064 #undef FocusIn
00065 
00066 // defined in qapplication_x11.cpp
00067 extern Atom qt_wm_protocols;
00068 extern Atom qt_wm_delete_window;
00069 extern Atom qt_wm_take_focus;
00070 extern Time qt_x_time;
00071 extern Atom qt_wm_state;
00072 
00073 static Atom xembed = 0;
00074 static Atom context_help = 0;
00075 
00076 // xembed messages
00077 #define XEMBED_EMBEDDED_NOTIFY  0
00078 #define XEMBED_WINDOW_ACTIVATE          1
00079 #define XEMBED_WINDOW_DEACTIVATE        2
00080 #define XEMBED_REQUEST_FOCUS            3
00081 #define XEMBED_FOCUS_IN                 4
00082 #define XEMBED_FOCUS_OUT                5
00083 #define XEMBED_FOCUS_NEXT               6
00084 #define XEMBED_FOCUS_PREV               7
00085 
00086 // xembed details
00087 
00088 // XEMBED_FOCUS_IN:
00089 #define XEMBED_FOCUS_CURRENT    0
00090 #define XEMBED_FOCUS_FIRST              1
00091 #define XEMBED_FOCUS_LAST               2
00092 
00093 
00094 
00095 class QXEmbedData
00096 {
00097 public:
00098     QXEmbedData(){ 
00099         autoDelete = TRUE;
00100         xplain = FALSE;
00101         xgrab = FALSE;
00102         lastPos = QPoint(0,0);
00103     }
00104     ~QXEmbedData(){};
00105 
00106     
00107     bool autoDelete;
00108     bool xplain;
00109     bool xgrab;
00110     QWidget* focusProxy;
00111     QPoint lastPos;
00112 };
00113 
00114 class QXEmbedAppFilter : public QObject
00115 {
00116 public:
00117     QXEmbedAppFilter(){ qApp->installEventFilter( this ); }
00118     ~QXEmbedAppFilter(){};
00119     bool eventFilter( QObject *, QEvent * );
00120 };
00121 
00122 
00123 static QXEmbedAppFilter* filter = 0;
00124 static QPtrDict<QGuardedPtr<QWidget> > *focusMap = 0;
00125 
00126 static XKeyEvent last_key_event;
00127 static bool tabForward = TRUE;
00128 
00129 
00130 class QPublicWidget : public QWidget
00131 {
00132 public:
00133     QTLWExtra* topData() { return QWidget::topData(); };
00134     QFocusData *focusData(){ return QWidget::focusData(); };
00135 };
00136 
00137 typedef int (*QX11EventFilter) (XEvent*);
00138 extern QX11EventFilter qt_set_x11_event_filter (QX11EventFilter filter);
00139 static QX11EventFilter oldFilter = 0;
00140 
00141 
00142 static void send_xembed_message( WId window, long message, long detail = 0,
00143                                  long data1 = 0, long data2 = 0)
00144 {
00145     if (!window) return;
00146     XEvent ev;
00147     memset(&ev, 0, sizeof(ev));
00148     ev.xclient.type = ClientMessage;
00149     ev.xclient.window = window;
00150     ev.xclient.message_type = xembed;
00151     ev.xclient.format = 32;
00152     ev.xclient.data.l[0] = qt_x_time;
00153     ev.xclient.data.l[1] = message;
00154     ev.xclient.data.l[2] = detail;
00155     ev.xclient.data.l[3] = data1;
00156     ev.xclient.data.l[4] = data2;
00157     XSendEvent(qt_xdisplay(), window, FALSE, NoEventMask, &ev);
00158 }
00159 
00160 static void sendClientMessage(Window window, Atom a, long x)
00161 {
00162   if (!window) return;
00163   XEvent ev;
00164   memset(&ev, 0, sizeof(ev));
00165   ev.xclient.type = ClientMessage;
00166   ev.xclient.window = window;
00167   ev.xclient.message_type = a;
00168   ev.xclient.format = 32;
00169   ev.xclient.data.l[0] = x;
00170   ev.xclient.data.l[1] = qt_x_time;
00171   XSendEvent(qt_xdisplay(), window, FALSE, NoEventMask, &ev);
00172 }
00173 
00174 static void sendFocusMessage(Window window, int type, int mode, int detail)
00175 {
00176   if (!window) return;
00177   XEvent ev;
00178   memset(&ev, 0, sizeof(ev));
00179   ev.xfocus.type = type;
00180   ev.xfocus.window = window;
00181   ev.xfocus.mode = mode;
00182   ev.xfocus.detail = detail;
00183   XSendEvent(qt_xdisplay(), window, FALSE, FocusChangeMask, &ev);
00184 }
00185 
00186 
00187 bool QXEmbedAppFilter::eventFilter( QObject *o, QEvent * e)
00188 {
00189     static bool obeyFocus = FALSE;
00190     switch ( e->type() ) {
00191     case QEvent::MouseButtonPress:
00192         if ( !((QWidget*)o)->isActiveWindow() )
00193             obeyFocus = TRUE;
00194         break;
00195     case QEvent::FocusIn:
00196         if ( qApp->focusWidget() == o &&
00197              ((QPublicWidget*)qApp->focusWidget()->topLevelWidget())->topData()->embedded ) {
00198             QFocusEvent* fe = (QFocusEvent*) e;
00199 
00200             if ( obeyFocus || fe->reason() == QFocusEvent::Mouse ||
00201                  fe->reason() == QFocusEvent::Shortcut ) {
00202                 WId window = ((QPublicWidget*)qApp->focusWidget()->topLevelWidget())->topData()->parentWinId;
00203                 focusMap->remove( qApp->focusWidget()->topLevelWidget() );
00204                 send_xembed_message( window, XEMBED_REQUEST_FOCUS );
00205             } else if ( fe->reason() == QFocusEvent::ActiveWindow ) {
00206                 focusMap->remove( qApp->focusWidget()->topLevelWidget() );
00207                 focusMap->insert( qApp->focusWidget()->topLevelWidget(),
00208                                   new QGuardedPtr<QWidget>(qApp->focusWidget()->topLevelWidget()->focusWidget() ) );
00209                 qApp->focusWidget()->clearFocus();
00210             }
00211             obeyFocus = FALSE;
00212         }
00213         break;
00214     default:
00215         break;
00216     }
00217     return FALSE;
00218 }
00219 
00220 
00221 static int qxembed_x11_event_filter( XEvent* e)
00222 {
00223     //kdDebug() << "qxembed_x11_event_filter " << KXEventUtil::getX11EventInfo(e) << endl;
00224 
00225     switch ( e->type ) {
00226     case XKeyPress: {
00227         int kc = XKeycodeToKeysym(qt_xdisplay(), e->xkey.keycode, 0);
00228         if ( kc == XK_Tab || kc == XK_ISO_Left_Tab ) {
00229             tabForward = (e->xkey.state & ShiftMask) == 0;
00230             QWidget* w = QWidget::find( e->xkey.window );
00231             if ( w && w->isActiveWindow() && qApp->focusWidget() &&
00232                  qApp->focusWidget()->topLevelWidget() == w->topLevelWidget() &&
00233                  ((QPublicWidget*)w->topLevelWidget())->topData()->embedded ) {
00234                 WId window = ((QPublicWidget*)w->topLevelWidget())->topData()->parentWinId;
00235                 QFocusData *fd = ((QPublicWidget*)w)->focusData();
00236                 while ( fd->next() != w->topLevelWidget() )
00237                     ;
00238                 QWidget* first = fd->next();
00239                 QWidget* last = fd->prev(); last = fd->prev();
00240                 if ( !tabForward && fd->focusWidget() == first ) {
00241                     send_xembed_message( window, XEMBED_FOCUS_PREV );
00242                     return TRUE;
00243                 } else if ( tabForward && fd->focusWidget() == last ) {
00244                     send_xembed_message( window, XEMBED_FOCUS_NEXT );
00245                     return TRUE;
00246                 }
00247             }
00248         } else
00249             last_key_event = e->xkey;
00250     }
00251     // FALL THROUGH
00252     case XKeyRelease: {
00253         last_key_event = e->xkey;
00254         break;
00255     }
00256     case ClientMessage:
00257         if ( e->xclient.message_type == xembed ) {
00258             Time msgtime = (Time) e->xclient.data.l[0];
00259             long message = e->xclient.data.l[1];
00260             long detail = e->xclient.data.l[2];
00261             if ( msgtime > qt_x_time )
00262                 qt_x_time = msgtime;
00263             QWidget* w = QWidget::find( e->xclient.window );
00264             if ( !w )
00265                 break;
00266             switch ( message) {
00267             case XEMBED_EMBEDDED_NOTIFY:
00268                 ((QPublicWidget*)w->topLevelWidget())->topData()->embedded = 1;
00269                 w->topLevelWidget()->show();
00270                 break;
00271             case XEMBED_WINDOW_ACTIVATE: {
00272                 // fake focus in
00273                 XEvent ev;
00274                 memset(&ev, 0, sizeof(ev));
00275                 ev.xfocus.display = qt_xdisplay();
00276                 ev.xfocus.type = XFocusIn;
00277                 ev.xfocus.window = w->topLevelWidget()->winId();
00278                 ev.xfocus.mode = NotifyNormal;
00279                 ev.xfocus.detail = NotifyAncestor;
00280                 qApp->x11ProcessEvent( &ev );
00281             }
00282             break;
00283             case XEMBED_WINDOW_DEACTIVATE: {
00284                 // fake focus out
00285                 XEvent ev;
00286                 memset(&ev, 0, sizeof(ev));
00287                 ev.xfocus.display = qt_xdisplay();
00288                 ev.xfocus.type = XFocusOut;
00289                 ev.xfocus.window = w->topLevelWidget()->winId();
00290                 ev.xfocus.mode = NotifyNormal;
00291                 ev.xfocus.detail = NotifyAncestor;
00292                 qApp->x11ProcessEvent( &ev );
00293             }
00294             break;
00295             case XEMBED_FOCUS_IN:
00296                 {
00297                     QWidget* focusCurrent = 0;
00298                     QGuardedPtr<QWidget>* fw = focusMap->find( w->topLevelWidget() );
00299                     if ( fw ) {
00300                         focusCurrent = *fw;
00301                         focusMap->remove( w->topLevelWidget() );
00302                     }
00303                     switch ( detail ) {
00304                     case XEMBED_FOCUS_CURRENT:
00305                         if ( focusCurrent )
00306                             focusCurrent->setFocus();
00307                         else if ( !w->topLevelWidget()->focusWidget() )
00308                             w->topLevelWidget()->setFocus();
00309                         break;
00310                     case XEMBED_FOCUS_FIRST:
00311                         {
00312                             QFocusData *fd = ((QPublicWidget*)w)->focusData();
00313                             while ( fd->next() != w->topLevelWidget() )
00314                                 ;
00315                             QWidget* fw = fd->next();
00316                             QFocusEvent::setReason( QFocusEvent::Tab );
00317                             if ( w )
00318                                 fw->setFocus();
00319                             else
00320                                 w->topLevelWidget()->setFocus();
00321                             QFocusEvent::resetReason();
00322                         }
00323                         break;
00324                     case XEMBED_FOCUS_LAST:
00325                         {
00326                             QFocusData *fd = ((QPublicWidget*)w)->focusData();
00327                             while ( fd->next() != w->topLevelWidget() )
00328                                 ;
00329                             QWidget* fw = fd->prev();
00330                             QFocusEvent::setReason( QFocusEvent::Tab );
00331                             if ( w )
00332                                 fw->setFocus();
00333                             else
00334                                 w->topLevelWidget()->setFocus();
00335                             QFocusEvent::resetReason();
00336                         }
00337                         break;
00338                     default:
00339                         break;
00340                     }
00341                 }
00342                 break;
00343             case XEMBED_FOCUS_OUT:
00344                 if ( w->topLevelWidget()->focusWidget() ) {
00345                     focusMap->insert( w->topLevelWidget(),
00346                                       new QGuardedPtr<QWidget>(w->topLevelWidget()->focusWidget() ) );
00347                     w->topLevelWidget()->focusWidget()->clearFocus();
00348                 }
00349             break;
00350             default:
00351                 break;
00352             }
00353         } else if ( e->xclient.format == 32 && e->xclient.message_type ) {
00354             if ( e->xclient.message_type == qt_wm_protocols ) {
00355                 QWidget* w = QWidget::find( e->xclient.window );
00356                 if ( !w )
00357                     break;
00358                 Atom a = e->xclient.data.l[0];
00359                 if ( a == qt_wm_take_focus ) {
00360                     if ( (ulong) e->xclient.data.l[1] > qt_x_time )
00361                         qt_x_time = e->xclient.data.l[1];
00362                     if ( w->isActiveWindow() ) {
00363                         // send another WindowActivate. The QXEmbed
00364                         // widget will filter it and pass the focus to
00365                         // the proxy
00366                         QEvent e( QEvent::WindowActivate );
00367                         QApplication::sendEvent( w, &e );
00368                     }
00369                 }
00370             }
00371         }
00372         break;
00373     default:
00374         break;
00375     }
00376 
00377     if ( oldFilter )
00378         return oldFilter( e );
00379     return FALSE;
00380 }
00381 
00390 void QXEmbed::initialize()
00391 {
00392     static bool is_initialized = FALSE;
00393     if ( is_initialized )
00394         return;
00395     xembed = XInternAtom( qt_xdisplay(), "_XEMBED", FALSE );
00396     oldFilter = qt_set_x11_event_filter( qxembed_x11_event_filter );
00397 
00398     focusMap = new QPtrDict<QGuardedPtr<QWidget> >;
00399     focusMap->setAutoDelete( TRUE );
00400 
00401     filter = new QXEmbedAppFilter;
00402 
00403     is_initialized = TRUE;
00404 }
00405 
00406 
00445 QXEmbed::QXEmbed(QWidget *parent, const char *name, WFlags f)
00446   : QWidget(parent, name, f)
00447 {
00448     d = new QXEmbedData;
00449     d->focusProxy = new QWidget( this, "xembed_focus" );
00450     d->focusProxy->setGeometry( -1, -1, 1, 1 );
00451     initialize();
00452     window = 0;
00453     setFocusPolicy(StrongFocus);
00454     setKeyCompression( FALSE );
00455 
00456     //trick to create extraData();
00457     (void) topData();
00458 
00459     // we are interested in SubstructureNotify
00460     XSelectInput(qt_xdisplay(), winId(),
00461                  KeyPressMask | KeyReleaseMask |
00462                  ButtonPressMask | ButtonReleaseMask |
00463                  KeymapStateMask |
00464                  ButtonMotionMask |
00465                  PointerMotionMask | // may need this, too
00466                  EnterWindowMask | LeaveWindowMask |
00467                  FocusChangeMask |
00468                  ExposureMask |
00469                  StructureNotifyMask |
00470                  SubstructureRedirectMask |
00471                  SubstructureNotifyMask
00472                  );
00473 
00474     topLevelWidget()->installEventFilter( this );
00475     qApp->installEventFilter( this );
00476 
00477     if (isActiveWindow())
00478         if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00479             XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00480                             RevertToParent, qt_x_time );
00481 
00482     setAcceptDrops( TRUE );
00483 }
00484 
00488 QXEmbed::~QXEmbed()
00489 {
00490   if ( d && d->xgrab)
00491     XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() );
00492   
00493   if ( window != 0 ) {
00494         if ( autoDelete() )
00495             XUnmapWindow( qt_xdisplay(), window );
00496         
00497         XReparentWindow(qt_xdisplay(), window, qt_xrootwin(), 0, 0);
00498         XSync(qt_xdisplay(), FALSE);
00499 
00500         if ( autoDelete() ) {
00501             XEvent ev;
00502             memset(&ev, 0, sizeof(ev));
00503             ev.xclient.type = ClientMessage;
00504             ev.xclient.window = window;
00505             ev.xclient.message_type = qt_wm_protocols;
00506             ev.xclient.format = 32;
00507             ev.xclient.data.s[0] = qt_wm_delete_window;
00508             XSendEvent(qt_xdisplay(), window, FALSE, NoEventMask, &ev);
00509         }
00510         XFlush( qt_xdisplay() );
00511      }
00512   window = 0;
00513 
00514   delete d;
00515 }
00516 
00517 
00531 void QXEmbed::setProtocol( Protocol proto )
00532 {
00533     if (window == 0) {
00534         d->xplain = FALSE;
00535         if (proto == XPLAIN)
00536             d->xplain = TRUE;
00537     }
00538 }
00539 
00544 QXEmbed::Protocol QXEmbed::protocol()
00545 {
00546   if (d->xplain)
00547     return XPLAIN;
00548   return XEMBED;
00549 }
00550 
00551 
00554 void QXEmbed::resizeEvent(QResizeEvent*)
00555 {
00556     if (window != 0)
00557         XResizeWindow(qt_xdisplay(), window, width(), height());
00558 }
00559 
00562 void QXEmbed::showEvent(QShowEvent*)
00563 {
00564     if (window != 0)
00565         XMapRaised(qt_xdisplay(), window);
00566 }
00567 
00568 
00571 bool QXEmbed::eventFilter( QObject *o, QEvent * e)
00572 {
00573 
00574     switch ( e->type() ) {
00575     case QEvent::WindowActivate:
00576         if ( o == topLevelWidget() ) {
00577             if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00578                 if (! hasFocus() )
00579                     XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00580                                     RevertToParent, qt_x_time );
00581             if (d->xplain)
00582                 checkGrab();
00583             else
00584                 send_xembed_message( window, XEMBED_WINDOW_ACTIVATE );
00585         }
00586         break;
00587     case QEvent::WindowDeactivate:
00588         if ( o == topLevelWidget() ) {
00589             if (d->xplain)
00590                 checkGrab();
00591             else
00592                 send_xembed_message( window, XEMBED_WINDOW_DEACTIVATE );
00593         }
00594         break;
00595     case QEvent::Move:
00596         {
00597             QPoint globalPos = mapToGlobal(QPoint(0,0));
00598             if (globalPos != d->lastPos) {
00599                 d->lastPos = globalPos;
00600                 sendSyntheticConfigureNotifyEvent();
00601             }
00602         }                    
00603         break;
00604     default:
00605         break;
00606    }
00607    return FALSE;
00608 }
00609 
00610 
00611 bool  QXEmbed::event( QEvent * e)
00612 {
00613     return QWidget::event( e );
00614 }
00615 
00618 void QXEmbed::keyPressEvent( QKeyEvent *)
00619 {
00620     if (!window)
00621         return;
00622     last_key_event.window = window;
00623     XSendEvent(qt_xdisplay(), window, FALSE, KeyPressMask, (XEvent*)&last_key_event);
00624 
00625 }
00626 
00629 void QXEmbed::keyReleaseEvent( QKeyEvent *)
00630 {
00631     if (!window)
00632         return;
00633     last_key_event.window = window;
00634     XSendEvent(qt_xdisplay(), window, FALSE, KeyReleaseMask, (XEvent*)&last_key_event);
00635 }
00636 
00639 void QXEmbed::focusInEvent( QFocusEvent * e ){
00640     if (!window)
00641         return;
00642     if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00643         XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00644                         RevertToParent, qt_x_time );
00645     if (d->xplain) {
00646         checkGrab();
00647         sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
00648     } else {
00649         int detail = XEMBED_FOCUS_CURRENT;
00650         if ( e->reason() == QFocusEvent::Tab )
00651             detail = tabForward?XEMBED_FOCUS_FIRST:XEMBED_FOCUS_LAST;
00652         send_xembed_message( window, XEMBED_FOCUS_IN, detail);
00653     }
00654 }
00655 
00658 void QXEmbed::focusOutEvent( QFocusEvent * ){
00659     if (!window)
00660         return;
00661     if (d->xplain) {
00662         checkGrab();
00663         sendFocusMessage(window, XFocusOut, NotifyNormal, NotifyPointer );
00664     } else {
00665         send_xembed_message( window, XEMBED_FOCUS_OUT );
00666     }
00667     if ( !((QPublicWidget*) topLevelWidget())->topData()->embedded )
00668         XSetInputFocus( qt_xdisplay(), d->focusProxy->winId(), 
00669                         RevertToParent, qt_x_time );
00670 }
00671 
00672 
00673 
00674 static bool wstate_withdrawn( WId winid )
00675 {
00676     Atom type;
00677     int format;
00678     unsigned long length, after;
00679     unsigned char *data;
00680     int r = XGetWindowProperty( qt_xdisplay(), winid, qt_wm_state, 0, 2,
00681                                 FALSE, AnyPropertyType, &type, &format,
00682                                 &length, &after, &data );
00683     bool withdrawn = TRUE;
00684     if ( r == Success && data && format == 32 ) {
00685         Q_UINT32 *wstate = (Q_UINT32*)data;
00686         withdrawn  = (*wstate == WithdrawnState );
00687         XFree( (char *)data );
00688     }
00689     return withdrawn;
00690 }
00691 
00692 static int get_parent(WId winid, Window *out_parent)
00693 {
00694     Window root, *children=0;
00695     unsigned int nchildren;
00696     int st = XQueryTree(qt_xdisplay(), winid, &root, out_parent, &children, &nchildren);
00697     if (st) {
00698         if (children) {
00699             XFree(children);
00700         }
00701         return st;
00702     } else {
00703         // kdDebug() << QString("**** FAILED **** XQueryTree returns status %1").arg(st) << endl;
00704     }
00705     return st;
00706 }
00707 #include <unistd.h>
00720 void QXEmbed::embed(WId w)
00721 {
00722     kdDebug() << "************************** Embed "<< QString("0x%1").arg(w, 0, 16) << " into " << QString("0x%1").arg(winId(), 0, 16) << " window=" << QString("0x%1").arg(window, 0, 16) << " **********" << endl; 
00723     if (!w)
00724         return;
00725     XAddToSaveSet( qt_xdisplay(), w );
00726     bool has_window =  w == window;
00727     window = w;
00728     if ( !has_window ) {
00729         if ( !wstate_withdrawn(window) ) {
00730             XWithdrawWindow(qt_xdisplay(), window, qt_xscreen());
00731             QApplication::flushX();
00732             while (!wstate_withdrawn(window))
00733                 ;
00734         }
00735         Window parent;
00736         get_parent(w, &parent);
00737         kdDebug() << QString(">>> before reparent: parent=0x%1").arg(parent, 0, 16) << endl;
00738         for (int i = 0; i < 50; i++) {
00739             Window parent = 0;
00740             XReparentWindow(qt_xdisplay(), w, winId(), 0, 0);
00741             if (get_parent(w, &parent) && parent == winId()) {
00742                kdDebug() << QString(">>> Loop %1: reparent of 0x%2 into 0x%3 successful").arg(i).arg(w, 0, 16).arg(winId(), 0, 16) << endl;
00743                break;
00744             }
00745             kdDebug() << QString(">>> Loop %1: reparent of 0x%2 into 0x%3 failed").arg(i).arg(w, 0, 16).arg(winId(), 0, 16) << endl;
00746             USLEEP(1000);
00747         }
00748         QApplication::syncX();
00749     }
00750 
00751     XResizeWindow(qt_xdisplay(), w, width(), height());
00752     XMapRaised(qt_xdisplay(), window);
00753     sendSyntheticConfigureNotifyEvent();
00754     extraData()->xDndProxy = w;
00755 
00756     if ( parent() ) {
00757         QEvent * layoutHint = new QEvent( QEvent::LayoutHint );
00758         QApplication::postEvent( parent(), layoutHint );
00759     }
00760     windowChanged( window );
00761     if (d->xplain) {
00762         checkGrab();
00763         if ( hasFocus() )
00764             sendFocusMessage(window, XFocusIn, NotifyNormal, NotifyPointer );
00765     } else {
00766         send_xembed_message( window, XEMBED_EMBEDDED_NOTIFY, 0, (long) winId() );
00767         send_xembed_message( window, isActiveWindow() ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE );
00768         if ( hasFocus() )
00769             send_xembed_message( window, XEMBED_FOCUS_IN );
00770     }
00771 }
00772 
00773 
00778 WId QXEmbed::embeddedWinId() const
00779 {
00780     return window;
00781 }
00782 
00783 
00786 bool QXEmbed::focusNextPrevChild( bool next )
00787 {
00788     if ( window )
00789         return FALSE;
00790     else
00791         return QWidget::focusNextPrevChild( next );
00792 }
00793 
00794 
00797 bool QXEmbed::x11Event( XEvent* e)
00798 {
00799     //kdDebug() << "x11Event " << KXEventUtil::getX11EventInfo(e) << endl;
00800     switch ( e->type ) {
00801     case DestroyNotify:
00802         if ( e->xdestroywindow.window == window ) {
00803             window = 0;
00804             windowChanged( window );
00805             emit embeddedWindowDestroyed();
00806         }
00807         break;
00808     case ReparentNotify:
00809         if ( e->xreparent.window == d->focusProxy->winId() )
00810             break; // ignore proxy
00811         if ( window && e->xreparent.window == window &&
00812              e->xreparent.parent != winId() ) {
00813             // we lost the window
00814             window = 0;
00815             windowChanged( window );
00816         } else if ( e->xreparent.parent == winId() ){
00817             // we got a window
00818             window = e->xreparent.window;
00819             embed( window );
00820         }
00821         break;
00822     case ButtonPress:
00823         if (d->xplain) {
00824             QFocusEvent::setReason( QFocusEvent::Mouse );
00825             setFocus();
00826             QFocusEvent::resetReason();
00827             XAllowEvents(qt_xdisplay(), ReplayPointer, CurrentTime);
00828             return TRUE;
00829         }
00830         break;
00831     case ButtonRelease:
00832         if (d->xplain) 
00833             XAllowEvents(qt_xdisplay(), SyncPointer, CurrentTime);
00834         break;
00835     case MapRequest:
00836         if ( window && e->xmaprequest.window == window )
00837             XMapRaised(qt_xdisplay(), window );
00838         break;
00839     case ClientMessage:
00840         if ( e->xclient.format == 32 && e->xclient.message_type == xembed ) {
00841             long message = e->xclient.data.l[1];
00842 //          long detail = e->xclient.data.l[2];
00843             switch ( message ) {
00844             case XEMBED_FOCUS_NEXT:
00845                 QWidget::focusNextPrevChild( TRUE );
00846                 break;
00847             case XEMBED_FOCUS_PREV:
00848                 QWidget::focusNextPrevChild( FALSE );
00849                 break;
00850             case XEMBED_REQUEST_FOCUS:
00851                 QFocusEvent::setReason( QFocusEvent::Mouse );
00852                 setFocus();
00853                 QFocusEvent::resetReason();
00854                 break;
00855             default:
00856                 break;
00857             }
00858         }
00859     break;
00860 
00861     case ConfigureRequest:
00862         if (e->xconfigurerequest.window == window) 
00863         {
00864              sendSyntheticConfigureNotifyEvent();
00865         }
00866         break;
00867     case MotionNotify: 
00868     // fall through, workaround for Qt 3.0 < 3.0.3
00869     case EnterNotify:
00870         if ( QWhatsThis::inWhatsThisMode() )
00871             enterWhatsThisMode();
00872         break;
00873     default:
00874         break;
00875     }
00876     return FALSE;
00877 }
00878 
00879  // temporary, fix in Qt (Matthias, Mon Jul 17 15:20:55 CEST 2000  )
00880 void QXEmbed::enterWhatsThisMode()
00881 {
00882     QWhatsThis::leaveWhatsThisMode();
00883     if ( !context_help )
00884         context_help = XInternAtom( x11Display(), "_NET_WM_CONTEXT_HELP", FALSE );
00885     sendClientMessage(window , qt_wm_protocols, context_help );
00886 }
00887 
00888 
00894 void QXEmbed::windowChanged( WId )
00895 {
00896 }
00897 
00898 
00909 bool QXEmbed::processClientCmdline( QWidget* client, int& argc, char ** argv )
00910 {
00911     int myargc = argc;
00912     WId window = 0;
00913     int i, j;
00914 
00915     j = 1;
00916     for ( i=1; i<myargc; i++ ) {
00917         if ( argv[i] && *argv[i] != '-' ) {
00918             argv[j++] = argv[i];
00919             continue;
00920         }
00921         QCString arg = argv[i];
00922         if ( strcmp(arg,"-embed") == 0 && i < myargc-1 ) {
00923             QCString s = argv[++i];
00924             window = s.toInt();
00925         } else
00926             argv[j++] = argv[i];
00927     }
00928     argc = j;
00929 
00930     if ( window != 0 ) {
00931         embedClientIntoWindow( client, window );
00932         return TRUE;
00933     }
00934 
00935     return FALSE;
00936 }
00937 
00938 
00947 void QXEmbed::embedClientIntoWindow(QWidget* client, WId window)
00948 {
00949     initialize();
00950     XReparentWindow(qt_xdisplay(), client->winId(), window, 0, 0);
00951     ((QXEmbed*)client)->topData()->embedded = TRUE;
00952     ((QXEmbed*)client)->topData()->parentWinId = window;
00953     client->show();
00954 }
00955 
00956 
00957 
00963 QSizePolicy QXEmbed::sizePolicy() const
00964 {
00965     return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
00966 }
00967 
00968 
00972 QSize QXEmbed::sizeHint() const
00973 {
00974     return minimumSizeHint();
00975 }
00976 
00989 QSize QXEmbed::minimumSizeHint() const
00990 {
00991     int minw = 0;
00992     int minh = 0;
00993     if ( window ) {
00994         XSizeHints size;
00995         long msize;
00996         if (XGetWMNormalHints(qt_xdisplay(), window, &size, &msize)
00997             && ( size.flags & PMinSize) ) {
00998             minw = size.min_width;
00999             minh = size.min_height;
01000         }
01001     }
01002 
01003     return QSize( minw, minh );
01004 }
01005 
01006 void QXEmbed::setAutoDelete( bool b)
01007 {
01008     d->autoDelete = b;
01009 }
01010 
01011 bool QXEmbed::autoDelete() const
01012 {
01013     return d->autoDelete;
01014 }
01015 
01018 bool QXEmbed::customWhatsThis() const
01019 {
01020     return TRUE;
01021 }
01022 
01023 
01024 void QXEmbed::checkGrab() 
01025 {
01026     if (d->xplain && isActiveWindow() && !hasFocus()) {
01027         if (! d->xgrab)
01028             XGrabButton(qt_xdisplay(), AnyButton, AnyModifier, winId(),
01029                         FALSE, ButtonPressMask, GrabModeSync, GrabModeAsync,
01030                         None, None );
01031         d->xgrab = TRUE;
01032     } else {
01033         if (d->xgrab)
01034             XUngrabButton( qt_xdisplay(), AnyButton, AnyModifier, winId() );
01035         d->xgrab = FALSE;
01036     }
01037 }
01038 
01039 
01040 void QXEmbed::sendSyntheticConfigureNotifyEvent() 
01041 {
01042     QPoint globalPos = mapToGlobal(QPoint(0,0));
01043     if (window) {
01044         // kdDebug(6100) << "*************** sendSyntheticConfigureNotify ******************" << endl;
01045         XConfigureEvent c;
01046         memset(&c, 0, sizeof(c));
01047         c.type = ConfigureNotify;
01048         c.display = qt_xdisplay();
01049         c.send_event = True;
01050         c.event = window;
01051         c.window = winId();
01052         c.x = globalPos.x();
01053         c.y = globalPos.y();
01054         c.width = width();
01055         c.height = height();
01056         c.border_width = 0;
01057         c.above = None;
01058         c.override_redirect = 0;
01059         XSendEvent( qt_xdisplay(), c.event, TRUE, StructureNotifyMask, (XEvent*)&c );
01060         //kdDebug(6100) << "SENT " << KXEventUtil::getX11EventInfo((XEvent*)&c) << endl;
01061     }
01062 }
01063 
01064 // for KDE
01065 #include "qxembed.moc"
01066 #endif
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.4.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Sun Feb 27 22:15:06 2005 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2001