00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "qx11embed_x11.h"
00025 #include <qapplication.h>
00026 #include <qevent.h>
00027 #include <qpainter.h>
00028 #include <qlayout.h>
00029 #include <qstyle.h>
00030 #include <qstyleoption.h>
00031 #include <qdatetime.h>
00032 #include <qpointer.h>
00033 #include <qdebug.h>
00034 #include <qx11info_x11.h>
00035 #include <private/qt_x11_p.h>
00036 #include <private/qwidget_p.h>
00037
00038 #define XK_MISCELLANY
00039 #define XK_LATIN1
00040 #define None 0
00041 #include <X11/Xlib.h>
00042 #include <X11/Xatom.h>
00043 #include <X11/Xutil.h>
00044 #include <X11/keysymdef.h>
00045 #include <X11/X.h>
00046
00047 #ifndef XK_ISO_Left_Tab
00048 #define XK_ISO_Left_Tab 0xFE20
00049 #endif
00050
00246 const int XButtonPress = ButtonPress;
00247 const int XButtonRelease = ButtonRelease;
00248 #undef ButtonPress
00249 #undef ButtonRelease
00250
00251
00252
00253 class QHackWidget : public QWidget
00254 {
00255 Q_DECLARE_PRIVATE(QWidget)
00256 public:
00257 QTLWExtra* topData() { return d_func()->topData(); }
00258 };
00259
00260 static unsigned int XEMBED_VERSION = 0;
00261
00262 static Atom _XEMBED = None;
00263 static Atom _XEMBED_INFO = None;
00264
00265 enum QX11EmbedMessageType {
00266 XEMBED_EMBEDDED_NOTIFY = 0,
00267 XEMBED_WINDOW_ACTIVATE = 1,
00268 XEMBED_WINDOW_DEACTIVATE = 2,
00269 XEMBED_REQUEST_FOCUS = 3,
00270 XEMBED_FOCUS_IN = 4,
00271 XEMBED_FOCUS_OUT = 5,
00272 XEMBED_FOCUS_NEXT = 6,
00273 XEMBED_FOCUS_PREV = 7,
00274 XEMBED_MODALITY_ON = 10,
00275 XEMBED_MODALITY_OFF = 11,
00276 XEMBED_REGISTER_ACCELERATOR = 12,
00277 XEMBED_UNREGISTER_ACCELERATOR = 13,
00278 XEMBED_ACTIVATE_ACCELERATOR = 14
00279 };
00280
00281 enum QX11EmbedFocusInDetail {
00282 XEMBED_FOCUS_CURRENT = 0,
00283 XEMBED_FOCUS_FIRST = 1,
00284 XEMBED_FOCUS_LAST = 2
00285 };
00286
00287 enum QX11EmbedFocusInFlags {
00288 XEMBED_FOCUS_OTHER = (0 << 0),
00289 XEMBED_FOCUS_WRAPAROUND = (1 << 0)
00290 };
00291
00292 enum QX11EmbedInfoFlags {
00293 XEMBED_MAPPED = (1 << 0)
00294 };
00295
00296 enum QX11EmbedAccelModifiers {
00297 XEMBED_MODIFIER_SHIFT = (1 << 0),
00298 XEMBED_MODIFIER_CONTROL = (1 << 1),
00299 XEMBED_MODIFIER_ALT = (1 << 2),
00300 XEMBED_MODIFIER_SUPER = (1 << 3),
00301 XEMBED_MODIFIER_HYPER = (1 << 4)
00302 };
00303
00304 enum QX11EmbedAccelFlags {
00305 XEMBED_ACCELERATOR_OVERLOADED = (1 << 0)
00306 };
00307
00308
00309 static int x11ErrorHandler(Display *, XErrorEvent *)
00310 {
00311 return 0;
00312 }
00313
00314
00315 static void initXEmbedAtoms(Display *d)
00316 {
00317 if (_XEMBED == None)
00318 _XEMBED = XInternAtom(d, "_XEMBED", false);
00319
00320 if (_XEMBED_INFO == None)
00321 _XEMBED_INFO = XInternAtom(d, "_XEMBED_INFO", false);
00322 }
00323
00324
00325
00326 static Time x11Time()
00327 {
00328 return qt_x11Data->time;
00329 }
00330
00331
00332 static unsigned int XEmbedVersion()
00333 {
00334 return 0;
00335 }
00336
00337
00338 static void sendXEmbedMessage(WId window, Display *display, long message,
00339 long detail = 0, long data1 = 0, long data2 = 0)
00340 {
00341 XClientMessageEvent c;
00342 memset(&c, 0, sizeof(c));
00343 c.type = ClientMessage;
00344 c.message_type = _XEMBED;
00345 c.format = 32;
00346 c.display = display;
00347 c.window = window;
00348
00349 c.data.l[0] = x11Time();
00350 c.data.l[1] = message;
00351 c.data.l[2] = detail;
00352 c.data.l[3] = data1;
00353 c.data.l[4] = data2;
00354
00355 XSendEvent(display, window, false, NoEventMask, (XEvent *) &c);
00356 }
00357
00358
00359 static XKeyEvent lastKeyEvent;
00360
00361 static QCoreApplication::EventFilter oldX11EventFilter;
00362
00363
00364
00365
00366 static bool x11EventFilter(void *message, long *result)
00367 {
00368 XEvent *event = reinterpret_cast<XEvent *>(message);
00369 if (event->type == XKeyPress || event->type == XKeyRelease)
00370 lastKeyEvent = event->xkey;
00371
00372
00373
00374
00375
00376 if (event->type == ClientMessage && event->xclient.message_type == ATOM(WM_PROTOCOLS)) {
00377 QWidget *w = QWidget::find(event->xclient.window);
00378 if (w) {
00379 Atom a = event->xclient.data.l[0];
00380 if (a == ATOM(WM_TAKE_FOCUS)) {
00381 if ((ulong) event->xclient.data.l[1] > X11->time )
00382 X11->time = event->xclient.data.l[1];
00383
00384 if (w->isActiveWindow()) {
00385 QEvent e(QEvent::WindowActivate);
00386 QApplication::sendEvent(w, &e);
00387 }
00388 }
00389 }
00390 }
00391
00392 if (oldX11EventFilter && oldX11EventFilter != &x11EventFilter)
00393 return oldX11EventFilter(message, result);
00394 else
00395 return false;
00396 }
00397
00398 class QX11EmbedWidgetPrivate : public QWidgetPrivate
00399 {
00400 Q_DECLARE_PUBLIC(QX11EmbedWidget)
00401 public:
00402 inline QX11EmbedWidgetPrivate()
00403 {
00404 container = 0;
00405 }
00406
00407 void setEmbedded();
00408
00409 void emitError(QX11EmbedWidget::Error error) {
00410 Q_Q(QX11EmbedWidget);
00411
00412 lastError = error;
00413 emit q->error(error);
00414 }
00415
00416 enum FocusWidgets {
00417 FirstFocusWidget,
00418 LastFocusWidget
00419 };
00420
00421 int focusOriginator;
00422 QWidget *getFocusWidget(FocusWidgets fw);
00423 void checkActivateWindow(QObject *o);
00424 QX11EmbedWidget *xEmbedWidget(QObject *o) const;
00425 void clearFocus();
00426
00427 WId container;
00428 QPointer<QWidget> currentFocus;
00429
00430 QX11EmbedWidget::Error lastError;
00431
00432 };
00433
00437 QX11EmbedWidget::QX11EmbedWidget(QWidget *parent)
00438 : QWidget(*new QX11EmbedWidgetPrivate, parent, 0)
00439 {
00440 XSetErrorHandler(x11ErrorHandler);
00441 initXEmbedAtoms(x11Info().display());
00442
00443 createWinId();
00444 XSelectInput(x11Info().display(), internalWinId(),
00445 KeyPressMask | KeyReleaseMask | ButtonPressMask
00446 | ButtonReleaseMask
00447 | KeymapStateMask | ButtonMotionMask | PointerMotionMask
00448 | FocusChangeMask
00449 | ExposureMask | StructureNotifyMask
00450 | SubstructureNotifyMask | PropertyChangeMask);
00451
00452 unsigned int data[] = {XEMBED_VERSION, XEMBED_MAPPED};
00453 XChangeProperty(x11Info().display(), internalWinId(), _XEMBED_INFO,
00454 XA_CARDINAL, 32, PropModeReplace,
00455 (unsigned char*) data, 2);
00456
00457 setFocusPolicy(Qt::StrongFocus);
00458 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00459 QApplication::instance()->installEventFilter(this);
00460 }
00461
00467 QX11EmbedWidget::~QX11EmbedWidget()
00468 {
00469 Q_D(QX11EmbedWidget);
00470 if (d->container) {
00471 XUnmapWindow(x11Info().display(), internalWinId());
00472 XReparentWindow(x11Info().display(), internalWinId(), x11Info().appRootWindow(), 0, 0);
00473 }
00474 }
00475
00476 QX11EmbedWidget::Error QX11EmbedWidget::error() const {
00477 return d_func()->lastError;
00478 }
00479
00487 void QX11EmbedWidget::embedInto(WId id)
00488 {
00489 Q_D(QX11EmbedWidget);
00490 d->container = id;
00491 switch (XReparentWindow(x11Info().display(), internalWinId(), d->container, 0, 0)) {
00492 case BadWindow:
00493 d->emitError(InvalidWindowID);
00494 break;
00495 case BadMatch:
00496 d->emitError(Internal);
00497 break;
00498 case Success:
00499 default:
00500 break;
00501 }
00502 QTLWExtra* x = d->extra ? d->extra->topextra : 0;
00503 if (x)
00504 x->frameStrut.setCoords(0, 0, 0, 0);
00505 d->data.fstrut_dirty = false;
00506 }
00507
00512 QWidget *QX11EmbedWidgetPrivate::getFocusWidget(FocusWidgets fw)
00513 {
00514 Q_Q(QX11EmbedWidget);
00515 QWidget *tlw = q;
00516 QWidget *w = tlw->nextInFocusChain();
00517
00518 QWidget *last = tlw;
00519
00520 extern bool qt_tab_all_widgets;
00521 uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus;
00522
00523 while (w != tlw)
00524 {
00525 if (((w->focusPolicy() & focus_flag) == focus_flag)
00526 && w->isVisibleTo(q) && w->isEnabled())
00527 {
00528 last = w;
00529 if (fw == FirstFocusWidget)
00530 break;
00531 }
00532 w = w->nextInFocusChain();
00533 }
00534
00535 return last;
00536 }
00537
00542 QX11EmbedWidget *QX11EmbedWidgetPrivate::xEmbedWidget(QObject *o) const
00543 {
00544 QX11EmbedWidget *xec = 0;
00545
00546
00547
00548 do {
00549 if ((xec = qobject_cast<QX11EmbedWidget *>(o)))
00550 return xec;
00551 } while ((o = o->parent()));
00552 return 0;
00553 }
00554
00559 void QX11EmbedWidgetPrivate::checkActivateWindow(QObject *o)
00560 {
00561 Q_Q(QX11EmbedWidget);
00562 QX11EmbedWidget *xec = xEmbedWidget(o);
00563
00564
00565 if (q != xec)
00566 return;
00567
00568 QWidget *w = qobject_cast<QWidget *>(o);
00569
00570
00571 if (!(w && qApp->activeWindow()))
00572 return;
00573
00574
00575 if (w->window() != qApp->activeWindow())
00576 {
00577 qApp->setActiveWindow(w->window());
00578 currentFocus = w;
00579
00580 sendXEmbedMessage(xec->containerWinId(), q->x11Info().display(), XEMBED_REQUEST_FOCUS);
00581 }
00582 }
00583
00588 void QX11EmbedWidgetPrivate::clearFocus()
00589 {
00590 Q_Q(QX11EmbedWidget);
00591
00592
00593
00594
00595
00596
00597
00598 if (!q->window()->hasFocus())
00599 q->window()->setFocus(Qt::OtherFocusReason);
00600
00601 currentFocus = 0;
00602 }
00603
00608 void QX11EmbedWidgetPrivate::setEmbedded()
00609 {
00610 Q_Q(QX11EmbedWidget);
00611 ((QHackWidget *)q->window())->topData()->embedded = 1;
00612 }
00613
00618 bool QX11EmbedWidget::eventFilter(QObject *o, QEvent *event)
00619 {
00620 Q_D(QX11EmbedWidget);
00621 switch (event->type()) {
00622 case QEvent::FocusIn:
00623 switch (((QFocusEvent *)event)->reason()) {
00624 case Qt::MouseFocusReason:
00625
00626
00627
00628 if (d->xEmbedWidget(o) == this) {
00629 if (d->currentFocus.isNull())
00630 sendXEmbedMessage(d->container, x11Info().display(), XEMBED_REQUEST_FOCUS);
00631
00632 d->currentFocus = qobject_cast<QWidget *>(o);
00633 }
00634 break;
00635 case Qt::TabFocusReason:
00636
00637
00638
00639 if (o == this) {
00640 d->clearFocus();
00641 sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_NEXT);
00642 return true;
00643 } else {
00644
00645
00646
00647
00648 if (d->xEmbedWidget(o) == this)
00649 d->currentFocus = qobject_cast<QWidget *>(o);
00650 }
00651 break;
00652 case Qt::BacktabFocusReason:
00653
00654
00655
00656
00657 if (o == this) {
00658
00659
00660
00661
00662
00663 d->clearFocus();
00664 sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_PREV);
00665 return true;
00666 } else {
00667 if (d->xEmbedWidget(o) == this)
00668 d->currentFocus = qobject_cast<QWidget *>(o);
00669 }
00670 break;
00671 case Qt::ActiveWindowFocusReason:
00672 if (!d->currentFocus.isNull()) {
00673 if (!d->currentFocus->hasFocus())
00674 d->currentFocus->setFocus(Qt::OtherFocusReason);
00675 } else {
00676 d->clearFocus();
00677 return true;
00678 }
00679
00680 break;
00681 case Qt::PopupFocusReason:
00682 case Qt::ShortcutFocusReason:
00683 case Qt::OtherFocusReason:
00684
00685
00686
00687 if (d->xEmbedWidget(o) == this) {
00688 d->currentFocus = qobject_cast<QWidget *>(o);
00689 }
00690 break;
00691 default:
00692 break;
00693 }
00694 break;
00695 case QEvent::MouseButtonPress:
00696
00697
00698 d->checkActivateWindow(o);
00699 break;
00700 default:
00701 break;
00702 }
00703
00704 return QWidget::eventFilter(o, event);
00705 }
00706
00712 bool QX11EmbedWidget::x11Event(XEvent *event)
00713 {
00714 Q_D(QX11EmbedWidget);
00715 switch (event->type) {
00716 case DestroyNotify:
00717
00718 emit containerClosed();
00719 break;
00720 case ReparentNotify:
00721
00722
00723
00724 if (event->xreparent.parent == x11Info().appRootWindow()) {
00725 emit containerClosed();
00726 return true;
00727 } else {
00728 d->container = event->xreparent.parent;
00729 }
00730 break;
00731 case UnmapNotify:
00732
00733
00734
00735 return true;
00736 case PropertyNotify:
00737
00738
00739
00740 if (event->xproperty.atom == _XEMBED_INFO) {
00741 Atom actual_type_return;
00742 int actual_format_return;
00743 unsigned long nitems_return;
00744 unsigned long bytes_after_return;
00745 unsigned char *prop_return = 0;
00746 if (XGetWindowProperty(x11Info().display(), internalWinId(), _XEMBED_INFO, 0, 2,
00747 false, XA_CARDINAL, &actual_type_return,
00748 &actual_format_return, &nitems_return,
00749 &bytes_after_return, &prop_return) == Success) {
00750 if (nitems_return > 1) {
00751 if (((int * )prop_return)[1] & XEMBED_MAPPED) {
00752 XMapWindow(x11Info().display(), internalWinId());
00753 } else {
00754 XUnmapWindow(x11Info().display(), internalWinId());
00755 }
00756 }
00757 }
00758 }
00759
00760 break;
00761 case ClientMessage:
00762
00763 if (event->xclient.message_type == _XEMBED) {
00764
00765 if (event->xclient.window != internalWinId())
00766 break;
00767
00768
00769 Time msgtime = (Time) event->xclient.data.l[0];
00770 if (msgtime > X11->time)
00771 X11->time = msgtime;
00772
00773 switch (event->xclient.data.l[1]) {
00774 case XEMBED_WINDOW_ACTIVATE: {
00775
00776
00777
00778 XEvent ev;
00779 memset(&ev, 0, sizeof(ev));
00780 ev.xfocus.display = x11Info().display();
00781 ev.xfocus.type = XFocusIn;
00782 ev.xfocus.window = internalWinId();
00783 ev.xfocus.mode = NotifyNormal;
00784 ev.xfocus.detail = NotifyNonlinear;
00785 ((QApplication *)QApplication::instance())->x11ProcessEvent(&ev);
00786 }
00787 break;
00788 case XEMBED_WINDOW_DEACTIVATE: {
00789
00790
00791
00792 XEvent ev;
00793 memset(&ev, 0, sizeof(ev));
00794 ev.xfocus.display = x11Info().display();
00795 ev.xfocus.type = XFocusOut;
00796 ev.xfocus.window = internalWinId();
00797 ev.xfocus.mode = NotifyNormal;
00798 ev.xfocus.detail = NotifyNonlinear;
00799 ((QApplication *)QApplication::instance())->x11ProcessEvent(&ev);
00800 }
00801 break;
00802 case XEMBED_EMBEDDED_NOTIFY: {
00803
00804
00805
00806
00807
00808
00809 d->setEmbedded();
00810 emit embedded();
00811 }
00812 break;
00813 case XEMBED_FOCUS_IN:
00814
00815
00816 if (window() != qApp->activeWindow())
00817 qApp->setActiveWindow(this);
00818
00819 switch (event->xclient.data.l[2]) {
00820 case XEMBED_FOCUS_CURRENT:
00821
00822
00823
00824
00825 if (!d->currentFocus.isNull()) {
00826 if (!d->currentFocus->hasFocus())
00827 d->currentFocus->setFocus(Qt::OtherFocusReason);
00828 } else {
00829
00830
00831
00832
00833
00834 d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::FirstFocusWidget);
00835 d->currentFocus->setFocus(Qt::OtherFocusReason);
00836 }
00837 break;
00838 case XEMBED_FOCUS_FIRST:
00839
00840
00841
00842 d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::FirstFocusWidget);
00843 d->currentFocus->setFocus(Qt::TabFocusReason);
00844 break;
00845 case XEMBED_FOCUS_LAST:
00846
00847
00848
00849 d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::LastFocusWidget);
00850 d->currentFocus->setFocus(Qt::BacktabFocusReason);
00851 break;
00852 default:
00853
00854 break;
00855 }
00856 break;
00857 case XEMBED_FOCUS_OUT:
00858
00859
00860
00861
00862
00863
00864 d->clearFocus();
00865
00866 break;
00867 default:
00868
00869 break;
00870 };
00871 } else {
00872
00873 }
00874
00875 break;
00876 default:
00877
00878 break;
00879 }
00880
00881
00882 return QWidget::x11Event(event);
00883 }
00884
00888 bool QX11EmbedWidget::event(QEvent *event)
00889 {
00890 if (event->type() == QEvent::ParentChange) {
00891 XSelectInput(x11Info().display(), internalWinId(),
00892 KeyPressMask | KeyReleaseMask | ButtonPressMask
00893 | ButtonReleaseMask
00894 | KeymapStateMask | ButtonMotionMask | PointerMotionMask
00895 | FocusChangeMask
00896 | ExposureMask | StructureNotifyMask
00897 | SubstructureNotifyMask | PropertyChangeMask);
00898 }
00899 return QWidget::event(event);
00900 }
00901
00905 void QX11EmbedWidget::resizeEvent(QResizeEvent *event)
00906 {
00907 if (layout())
00908 layout()->update();
00909 QWidget::resizeEvent(event);
00910 }
00911
00916 WId QX11EmbedWidget::containerWinId() const
00917 {
00918 Q_D(const QX11EmbedWidget);
00919 return d->container;
00920 }
00921
00922 class QX11EmbedContainerPrivate : public QWidgetPrivate
00923 {
00924 Q_DECLARE_PUBLIC(QX11EmbedContainer)
00925 public:
00926 inline QX11EmbedContainerPrivate()
00927 {
00928 client = 0;
00929 focusProxy = 0;
00930 clientIsXEmbed = false;
00931 }
00932
00933 bool isEmbedded() const;
00934 void moveInputToProxy();
00935
00936 void acceptClient(WId window);
00937 void rejectClient(WId window);
00938
00939 void checkGrab();
00940
00941 WId topLevelParentWinId() const;
00942
00943 void emitError(QX11EmbedContainer::Error error) {
00944 Q_Q(QX11EmbedContainer);
00945 lastError = error;
00946 emit q->error(error);
00947 }
00948
00949 WId client;
00950 QWidget *focusProxy;
00951 bool clientIsXEmbed;
00952 bool xgrab;
00953 QRect clientOriginalRect;
00954 QSize wmMinimumSizeHint;
00955
00956 QX11EmbedContainer::Error lastError;
00957 };
00958
00962 QX11EmbedContainer::QX11EmbedContainer(QWidget *parent)
00963 : QWidget(*new QX11EmbedContainerPrivate, parent, 0)
00964 {
00965 Q_D(QX11EmbedContainer);
00966 XSetErrorHandler(x11ErrorHandler);
00967 initXEmbedAtoms(x11Info().display());
00968
00969 createWinId();
00970
00971 setFocusPolicy(Qt::StrongFocus);
00972 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00973
00974 setAcceptDrops(true);
00975 setEnabled(false);
00976
00977
00978
00979 d->focusProxy = new QWidget(this);
00980 d->focusProxy->setGeometry(-1, -1, 1, 1);
00981
00982
00983
00984 qApp->installEventFilter(this);
00985 window()->installEventFilter(this);
00986
00987
00988 if (!oldX11EventFilter)
00989 oldX11EventFilter = QCoreApplication::instance()->setEventFilter(x11EventFilter);
00990
00991 XSelectInput(x11Info().display(), internalWinId(),
00992 KeyPressMask | KeyReleaseMask
00993 | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
00994 | KeymapStateMask
00995 | PointerMotionMask
00996 | EnterWindowMask | LeaveWindowMask
00997 | FocusChangeMask
00998 | ExposureMask
00999 | StructureNotifyMask
01000 | SubstructureNotifyMask);
01001
01002
01003
01004
01005 if (qApp->activeWindow() == window() && !d->isEmbedded())
01006 d->moveInputToProxy();
01007 }
01008
01012 QX11EmbedContainer::~QX11EmbedContainer()
01013 {
01014 Q_D(QX11EmbedContainer);
01015 if (d->client) {
01016 XUnmapWindow(x11Info().display(), d->client);
01017 XReparentWindow(x11Info().display(), d->client, x11Info().appRootWindow(), 0, 0);
01018 }
01019
01020 if (d->xgrab)
01021 XUngrabButton(x11Info().display(), AnyButton, AnyModifier, internalWinId());
01022 }
01023
01024
01025 QX11EmbedContainer::Error QX11EmbedContainer::error() const {
01026 return d_func()->lastError;
01027 }
01028
01029
01032 void QX11EmbedContainer::paintEvent(QPaintEvent *)
01033 {
01034 }
01035
01040 bool QX11EmbedContainerPrivate::isEmbedded() const
01041 {
01042 Q_Q(const QX11EmbedContainer);
01043 return ((QHackWidget *)q->window())->topData()->embedded == 1;
01044 }
01045
01050 WId QX11EmbedContainerPrivate::topLevelParentWinId() const
01051 {
01052 Q_Q(const QX11EmbedContainer);
01053 return ((QHackWidget *)q->window())->topData()->parentWinId;
01054 }
01055
01060 WId QX11EmbedContainer::clientWinId() const
01061 {
01062 Q_D(const QX11EmbedContainer);
01063 return d->client;
01064 }
01065
01077 void QX11EmbedContainer::embedClient(WId id)
01078 {
01079 Q_D(QX11EmbedContainer);
01080
01081 if (id == 0) {
01082 d->emitError(InvalidWindowID);
01083 return;
01084 }
01085
01086
01087 WId thisId = internalWinId();
01088 Window rootReturn;
01089 Window parentReturn;
01090 Window *childrenReturn = 0;
01091 unsigned int nchildrenReturn;
01092 do {
01093 if (XQueryTree(x11Info().display(), thisId, &rootReturn,
01094 &parentReturn, &childrenReturn, &nchildrenReturn) == 0) {
01095 d->emitError(InvalidWindowID);
01096 return;
01097 }
01098 if (childrenReturn) {
01099 XFree(childrenReturn);
01100 childrenReturn = 0;
01101 }
01102
01103 thisId = parentReturn;
01104 if (id == thisId) {
01105 d->emitError(InvalidWindowID);
01106 return;
01107 }
01108 } while (thisId != rootReturn);
01109
01110
01111 XGrabServer(x11Info().display());
01112 XWindowAttributes attrib;
01113 if (!XGetWindowAttributes(x11Info().display(), id, &attrib)) {
01114 d->emitError(InvalidWindowID);
01115 return;
01116 }
01117 XSelectInput(x11Info().display(), id, attrib.your_event_mask | PropertyChangeMask);
01118 XUngrabServer(x11Info().display());
01119
01120
01121 XUnmapWindow(x11Info().display(), id);
01122 XSync(x11Info().display(), False);
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133 QTime t;
01134 t.start();
01135 for (;;) {
01136 if (t.elapsed() > 500)
01137 break;
01138
01139 XEvent event;
01140 if (!XCheckTypedWindowEvent(x11Info().display(), id, PropertyNotify, &event)) {
01141 XSync(x11Info().display(), False);
01142 continue;
01143 }
01144 if (event.xproperty.atom != ATOM(WM_STATE)) {
01145 qApp->x11ProcessEvent(&event);
01146 continue;
01147 }
01148
01149 if (event.xproperty.state == PropertyDelete)
01150 break;
01151
01152 Atom ret;
01153 int format, status;
01154 long *state;
01155 unsigned long nitems, after;
01156 status = XGetWindowProperty(x11Info().display(), id, ATOM(WM_STATE), 0, 2, False, ATOM(WM_STATE),
01157 &ret, &format, &nitems, &after, (unsigned char **) &state );
01158 if (status == Success && ret == ATOM(WM_STATE) && format == 32 && nitems > 0) {
01159 if (state[0] == WithdrawnState)
01160 break;
01161 }
01162 }
01163
01164
01165 XSelectInput(x11Info().display(), id, attrib.your_event_mask);
01166
01167 switch (XReparentWindow(x11Info().display(), id, internalWinId(), 0, 0)) {
01168 case BadWindow:
01169 case BadMatch:
01170 d->emitError(InvalidWindowID);
01171 break;
01172 default:
01173 break;
01174 }
01175 }
01176
01181 bool QX11EmbedContainer::eventFilter(QObject *o, QEvent *event)
01182 {
01183 Q_D(QX11EmbedContainer);
01184 switch (event->type()) {
01185 case QEvent::KeyPress:
01186
01187 if (o == this && d->client) {
01188 lastKeyEvent.window = d->client;
01189 XSendEvent(x11Info().display(), d->client, false, KeyPressMask, (XEvent *) &lastKeyEvent);
01190 return true;
01191 }
01192 break;
01193 case QEvent::KeyRelease:
01194
01195 if (o == this && d->client) {
01196 lastKeyEvent.window = d->client;
01197 XSendEvent(x11Info().display(), d->client, false, KeyReleaseMask, (XEvent *) &lastKeyEvent);
01198 return true;
01199 }
01200 break;
01201
01202 case QEvent::WindowActivate:
01203
01204
01205
01206
01207 if (o == window() && d->client) {
01208 if (!d->isEmbedded())
01209 d->moveInputToProxy();
01210
01211 if (d->clientIsXEmbed) {
01212 sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_ACTIVATE);
01213 } else {
01214 d->checkGrab();
01215 if (hasFocus())
01216 XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
01217 }
01218 }
01219 break;
01220 case QEvent::WindowDeactivate:
01221
01222
01223 if (o == window() && d->client) {
01224 if (d->clientIsXEmbed)
01225 sendXEmbedMessage(d->client, x11Info().display(), XEMBED_WINDOW_DEACTIVATE);
01226 else
01227 d->checkGrab();
01228 }
01229 break;
01230 case QEvent::FocusIn:
01231
01232
01233
01234
01235 if (o == this && d->client) {
01236 if (d->clientIsXEmbed) {
01237 if (!d->isEmbedded())
01238 d->moveInputToProxy();
01239
01240 QFocusEvent *fe = (QFocusEvent *)event;
01241 switch (fe->reason()) {
01242 case Qt::TabFocusReason:
01243 sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST);
01244 break;
01245 case Qt::BacktabFocusReason:
01246 sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_LAST);
01247 break;
01248 default:
01249 break;
01250 }
01251 } else {
01252 d->checkGrab();
01253 XSetInputFocus(x11Info().display(), d->client, XRevertToParent, x11Time());
01254 }
01255 }
01256
01257 break;
01258 case QEvent::FocusOut: {
01259
01260
01261 if (o == this && d->client) {
01262 if (!d->isEmbedded())
01263 d->moveInputToProxy();
01264
01265 if (d->clientIsXEmbed) {
01266 QFocusEvent *fe = (QFocusEvent *)event;
01267 if (o == this && d->client && fe->reason() != Qt::ActiveWindowFocusReason)
01268 sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_OUT);
01269 } else {
01270 d->checkGrab();
01271 }
01272 }
01273 }
01274 break;
01275
01276 case QEvent::Close: {
01277 if (o == this && d->client) {
01278
01279
01280
01281 XUnmapWindow(x11Info().display(), d->client);
01282 XReparentWindow(x11Info().display(), d->client, x11Info().appRootWindow(), 0, 0);
01283 XSync(x11Info().display(), false);
01284
01285 XEvent ev;
01286 memset(&ev, 0, sizeof(ev));
01287 ev.xclient.type = ClientMessage;
01288 ev.xclient.window = d->client;
01289 ev.xclient.message_type = ATOM(WM_PROTOCOLS);
01290 ev.xclient.format = 32;
01291 ev.xclient.data.s[0] = ATOM(WM_DELETE_WINDOW);
01292 XSendEvent(x11Info().display(), d->client, false, NoEventMask, &ev);
01293
01294 XFlush(x11Info().display());
01295 d->client = 0;
01296 d->clientIsXEmbed = false;
01297 d->wmMinimumSizeHint = QSize();
01298 updateGeometry();
01299 setEnabled(false);
01300 update();
01301
01302 emit clientClosed();
01303 }
01304 }
01305 default:
01306 break;
01307 }
01308
01309 return QObject::eventFilter(o, event);
01310 }
01311
01316 bool QX11EmbedContainer::x11Event(XEvent *event)
01317 {
01318 Q_D(QX11EmbedContainer);
01319
01320 switch (event->type) {
01321 case CreateNotify:
01322
01323 if (d->client)
01324 d->rejectClient(event->xcreatewindow.window);
01325 else
01326 d->acceptClient(event->xcreatewindow.window);
01327 break;
01328 case DestroyNotify:
01329 if (event->xdestroywindow.window == d->client) {
01330
01331 d->client = 0;
01332 d->clientIsXEmbed = false;
01333 d->wmMinimumSizeHint = QSize();
01334 updateGeometry();
01335 update();
01336 setEnabled(false);
01337 emit clientClosed();
01338 }
01339 break;
01340 case ReparentNotify:
01341
01342
01343 if (event->xreparent.window == d->client && event->xreparent.parent != internalWinId()) {
01344 d->client = 0;
01345 d->clientIsXEmbed = false;
01346 d->wmMinimumSizeHint = QSize();
01347 updateGeometry();
01348 update();
01349 setEnabled(false);
01350 emit clientClosed();
01351 } else if (event->xreparent.parent == internalWinId()) {
01352
01353 if (d->client)
01354 d->rejectClient(event->xreparent.window);
01355 else
01356 d->acceptClient(event->xreparent.window);
01357 }
01358 break;
01359 case ClientMessage: {
01360 if (event->xclient.message_type == _XEMBED) {
01361
01362 if (event->xclient.window != internalWinId())
01363 break;
01364
01365
01366
01367 d->clientIsXEmbed = true;
01368
01369 Time msgtime = (Time) event->xclient.data.l[0];
01370 if (msgtime > X11->time)
01371 X11->time = msgtime;
01372
01373 switch (event->xclient.data.l[1]) {
01374 case XEMBED_REQUEST_FOCUS: {
01375
01376
01377 if (!hasFocus())
01378 setFocus(Qt::OtherFocusReason);
01379
01380
01381
01382
01383
01384
01385
01386 if (d->isEmbedded()) {
01387
01388
01389
01390
01391 sendXEmbedMessage(d->topLevelParentWinId(), x11Info().display(), XEMBED_REQUEST_FOCUS);
01392 } else {
01393
01394
01395
01396
01397
01398
01399 sendXEmbedMessage(d->client, x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
01400 }
01401
01402 break;
01403 }
01404 case XEMBED_FOCUS_NEXT:
01405
01406
01407
01408
01409 if (d->focus_next != this) {
01410 focusNextPrevChild(true);
01411 } else {
01412 QFocusEvent event(QEvent::FocusIn, Qt::TabFocusReason);
01413 qApp->sendEvent(this, &event);
01414 }
01415
01416 break;
01417 case XEMBED_FOCUS_PREV:
01418
01419
01420
01421
01422 if (d->focus_next != this) {
01423 focusNextPrevChild(false);
01424 } else {
01425 QFocusEvent event(QEvent::FocusIn, Qt::BacktabFocusReason);
01426 qApp->sendEvent(this, &event);
01427 }
01428
01429 break;
01430 default:
01431 break;
01432 }
01433 }
01434 }
01435 break;
01436 case XButtonPress:
01437 if (!d->clientIsXEmbed) {
01438 setFocus(Qt::MouseFocusReason);
01439 XAllowEvents(x11Info().display(), ReplayPointer, CurrentTime);
01440 return true;
01441 }
01442 break;
01443 case XButtonRelease:
01444 if (!d->clientIsXEmbed)
01445 XAllowEvents(x11Info().display(), SyncPointer, CurrentTime);
01446 break;
01447 default:
01448 break;
01449 }
01450
01451 return QWidget::x11Event(event);
01452 }
01453
01458 void QX11EmbedContainer::resizeEvent(QResizeEvent *)
01459 {
01460 Q_D(QX11EmbedContainer);
01461 if (d->client)
01462 XResizeWindow(x11Info().display(), d->client, width(), height());
01463 }
01464
01471 void QX11EmbedContainer::showEvent(QShowEvent *)
01472 {
01473 Q_D(QX11EmbedContainer);
01474 if (d->client) {
01475 unsigned int data[] = {XEMBED_VERSION, XEMBED_MAPPED};
01476 XChangeProperty(x11Info().display(), d->client, _XEMBED_INFO, XA_CARDINAL, 32,
01477 PropModeReplace, (unsigned char *) data, 2);
01478 }
01479 }
01480
01487 void QX11EmbedContainer::hideEvent(QHideEvent *)
01488 {
01489 Q_D(QX11EmbedContainer);
01490 if (d->client) {
01491 unsigned int data[] = {XEMBED_VERSION, XEMBED_MAPPED};
01492
01493 XChangeProperty(x11Info().display(), d->client, _XEMBED_INFO, XA_CARDINAL, 32,
01494 PropModeReplace, (unsigned char *) data, 2);
01495 }
01496 }
01497
01501 bool QX11EmbedContainer::event(QEvent *event)
01502 {
01503 if (event->type() == QEvent::ParentChange) {
01504 XSelectInput(x11Info().display(), internalWinId(),
01505 KeyPressMask | KeyReleaseMask
01506 | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
01507 | KeymapStateMask
01508 | PointerMotionMask
01509 | EnterWindowMask | LeaveWindowMask
01510 | FocusChangeMask
01511 | ExposureMask
01512 | StructureNotifyMask
01513 | SubstructureNotifyMask);
01514 }
01515 return QWidget::event(event);
01516 }
01517
01526 void QX11EmbedContainerPrivate::rejectClient(WId window)
01527 {
01528 Q_Q(QX11EmbedContainer);
01529 q->setEnabled(false);
01530 XRemoveFromSaveSet(q->x11Info().display(), client);
01531 XReparentWindow(q->x11Info().display(), window, q->x11Info().appRootWindow(), 0, 0);
01532 }
01533
01539 void QX11EmbedContainerPrivate::acceptClient(WId window)
01540 {
01541 Q_Q(QX11EmbedContainer);
01542 client = window;
01543 q->setEnabled(true);
01544
01545
01546
01547 if (!extra)
01548 createExtra();
01549 extraData()->xDndProxy = client;
01550
01551 unsigned int version = XEmbedVersion();
01552
01553 Atom actual_type_return;
01554 int actual_format_return;
01555 unsigned long nitems_return = 0;
01556 unsigned long bytes_after_return;
01557 unsigned char *prop_return = 0;
01558 unsigned int clientversion = 0;
01559
01560
01561
01562
01563
01564 XAddToSaveSet(q->x11Info().display(), client);
01565
01566
01567
01568 if (XGetWindowProperty(q->x11Info().display(), client, _XEMBED_INFO, 0, 2, false, XA_CARDINAL,
01569 &actual_type_return, &actual_format_return, &nitems_return,
01570 &bytes_after_return, &prop_return) == Success) {
01571
01572 if (actual_type_return != None && actual_format_return != 0) {
01573
01574 clientIsXEmbed = true;
01575
01576 unsigned int *p = (unsigned int *)prop_return;
01577 if (nitems_return >= 2)
01578 clientversion = p[0];
01579 }
01580
01581 XFree(prop_return);
01582 }
01583
01584
01585 Window root;
01586 int x_return, y_return;
01587 unsigned int width_return, height_return, border_width_return, depth_return;
01588 XGetGeometry(q->x11Info().display(), client, &root, &x_return, &y_return,
01589 &width_return, &height_return, &border_width_return, &depth_return);
01590 clientOriginalRect.setCoords(x_return, y_return,
01591 x_return + width_return - 1,
01592 y_return + height_return - 1);
01593
01594
01595 XSizeHints size;
01596 long msize;
01597 if (XGetWMNormalHints(q->x11Info().display(), client, &size, &msize) && (size.flags & PMinSize)) {
01598 wmMinimumSizeHint = QSize(size.min_width, size.min_height);
01599 q->updateGeometry();
01600 }
01601
01602
01603
01604
01605 unsigned int minversion = version > clientversion ? clientversion : version;
01606 sendXEmbedMessage(client, q->x11Info().display(), XEMBED_EMBEDDED_NOTIFY, q->internalWinId(), minversion);
01607 XMapWindow(q->x11Info().display(), client);
01608
01609
01610 XResizeWindow(q->x11Info().display(), client,
01611 qMax(q->width(), size.min_width), qMax(q->height(), size.min_height));
01612 q->update();
01613
01614
01615
01616
01617 if (q->window()->isActiveWindow())
01618 sendXEmbedMessage(client, q->x11Info().display(), XEMBED_WINDOW_ACTIVATE);
01619
01620
01621
01622
01623 if (q->focusWidget() == q && q->hasFocus())
01624 sendXEmbedMessage(client, q->x11Info().display(), XEMBED_FOCUS_IN, XEMBED_FOCUS_FIRST);
01625 else
01626 sendXEmbedMessage(client, q->x11Info().display(), XEMBED_FOCUS_OUT);
01627
01628 if (!clientIsXEmbed) {
01629 checkGrab();
01630 if (q->hasFocus()) {
01631 XSetInputFocus(q->x11Info().display(), client, XRevertToParent, x11Time());
01632 } else {
01633 if (!isEmbedded())
01634 moveInputToProxy();
01635 }
01636 }
01637
01638 emit q->clientIsEmbedded();
01639 }
01640
01649 void QX11EmbedContainerPrivate::moveInputToProxy()
01650 {
01651 Q_Q(QX11EmbedContainer);
01652 WId focus;
01653 int revert_to;
01654 XGetInputFocus(q->x11Info().display(), &focus, &revert_to);
01655 if (focus != focusProxy->internalWinId())
01656 XSetInputFocus(q->x11Info().display(), focusProxy->internalWinId(), XRevertToParent, x11Time());
01657 }
01658
01663 QSize QX11EmbedContainer::minimumSizeHint() const
01664 {
01665 Q_D(const QX11EmbedContainer);
01666 if (!d->client || !d->wmMinimumSizeHint.isValid())
01667 return QWidget::minimumSizeHint();
01668 return d->wmMinimumSizeHint;
01669 }
01670
01674 void QX11EmbedContainerPrivate::checkGrab()
01675 {
01676 Q_Q(QX11EmbedContainer);
01677 if (!clientIsXEmbed && q->isActiveWindow() && !q->hasFocus()) {
01678 if (!xgrab) {
01679 XGrabButton(q->x11Info().display(), AnyButton, AnyModifier, q->internalWinId(),
01680 true, ButtonPressMask, GrabModeSync, GrabModeAsync,
01681 None, None);
01682 }
01683 xgrab = true;
01684 } else {
01685 if (xgrab)
01686 XUngrabButton(q->x11Info().display(), AnyButton, AnyModifier, q->internalWinId());
01687 xgrab = false;
01688 }
01689 }
01690
01695 void QX11EmbedContainer::discardClient()
01696 {
01697 Q_D(QX11EmbedContainer);
01698 if (d->client) {
01699 XResizeWindow(x11Info().display(), d->client, d->clientOriginalRect.width(),
01700 d->clientOriginalRect.height());
01701
01702 d->rejectClient(d->client);
01703 }
01704 }