📄 qx11embed_x11.cpp
字号:
}class QX11EmbedWidgetPrivate : public QWidgetPrivate{ Q_DECLARE_PUBLIC(QX11EmbedWidget)public: inline QX11EmbedWidgetPrivate() { container = 0; } void setEmbedded(); enum FocusWidgets { FirstFocusWidget, LastFocusWidget }; int focusOriginator; QWidget *getFocusWidget(FocusWidgets fw); void checkActivateWindow(QObject *o); QX11EmbedWidget *xEmbedWidget(QObject *o) const; void clearFocus(); WId container; QPointer<QWidget> currentFocus;};/*! Constructs a QX11EmbedWidget object with the given \a parent.*/QX11EmbedWidget::QX11EmbedWidget(QWidget *parent) : QWidget(*new QX11EmbedWidgetPrivate, parent, 0){ XSetErrorHandler(x11ErrorHandler); initXEmbedAtoms(x11Info().display()); XSelectInput(x11Info().display(), winId(), KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | KeymapStateMask | ButtonMotionMask | PointerMotionMask | FocusChangeMask | ExposureMask | StructureNotifyMask | SubstructureNotifyMask | PropertyChangeMask); unsigned int data[] = {XEMBED_VERSION, XEMBED_MAPPED}; XChangeProperty(x11Info().display(), winId(), _XEMBED_INFO, XA_CARDINAL, 32, PropModeReplace, (unsigned char*) data, 2); setFocusPolicy(Qt::StrongFocus); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QApplication::instance()->installEventFilter(this);}/*! Destructs the QX11EmbedWidget object. If the widget is embedded when deleted, it is hidden and then detached from its container, so that the container is free to embed a new widget.*/QX11EmbedWidget::~QX11EmbedWidget(){ Q_D(QX11EmbedWidget); if (d->container) { XUnmapWindow(x11Info().display(), winId()); XReparentWindow(x11Info().display(), winId(), x11Info().appRootWindow(), 0, 0); }}/*! When this function is called, the widget embeds itself into the container whose window ID is \a id. If \a id is \e not the window ID of a container this function will behave unpredictably.*/void QX11EmbedWidget::embedInto(WId id){ Q_D(QX11EmbedWidget); d->container = id; switch (XReparentWindow(x11Info().display(), winId(), d->container, 0, 0)) { case BadWindow: emit error(InvalidWindowID); break; case BadMatch: emit error(Internal); break; case Success: default: break; }}/*! \internal Gets the first or last child widget that can get focus.*/QWidget *QX11EmbedWidgetPrivate::getFocusWidget(FocusWidgets fw){ Q_Q(QX11EmbedWidget); QWidget *tlw = q; QWidget *w = tlw->nextInFocusChain(); QWidget *last = tlw; extern bool qt_tab_all_widgets; uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus; while (w != tlw) { if (((w->focusPolicy() & focus_flag) == focus_flag) && w->isVisibleTo(q) && w->isEnabled()) { last = w; if (fw == FirstFocusWidget) break; } w = w->nextInFocusChain(); } return last;}/*! \internal Returns the xembed widget that the widget is a child of*/QX11EmbedWidget *QX11EmbedWidgetPrivate::xEmbedWidget(QObject *o) const{ QX11EmbedWidget *xec = 0; // Check the widget itself, then its parents, and find the first // QX11EmbedWidget. do { if ((xec = qobject_cast<QX11EmbedWidget *>(o))) return xec; } while ((o = o->parent())); return 0;}/*! \internal Checks the active window.*/void QX11EmbedWidgetPrivate::checkActivateWindow(QObject *o){ Q_Q(QX11EmbedWidget); QX11EmbedWidget *xec = xEmbedWidget(o); // check if we are in the right xembed client if (q != xec) return; QWidget *w = qobject_cast<QWidget *>(o); // if it is no active window, then don't do the change if (!(w && qApp->activeWindow())) return; // if it already is the active window, don't do anything if (w->window() != qApp->activeWindow()) { qApp->setActiveWindow(w->window()); currentFocus = w; sendXEmbedMessage(xec->containerWinId(), q->x11Info().display(), XEMBED_REQUEST_FOCUS); }}/*! \internal Clears the focus*/void QX11EmbedWidgetPrivate::clearFocus(){ Q_Q(QX11EmbedWidget); // Setting focus on the client itself removes Qt's // logical focus rectangle. We can't just do a // clearFocus here, because when we send the synthetic // FocusIn to ourselves on activation, Qt will set // focus on focusWidget() again. This way, we "hide" // focus rather than clearing it. if (!q->window()->hasFocus()) q->window()->setFocus(Qt::OtherFocusReason); currentFocus = 0;}/*! \internal Sets the embedded flag on the client.*/void QX11EmbedWidgetPrivate::setEmbedded(){ Q_Q(QX11EmbedWidget); ((QHackWidget *)q->window())->topData()->embedded = 1;}/*! \internal Handles WindowActivate and FocusIn events for the client.*/bool QX11EmbedWidget::eventFilter(QObject *o, QEvent *event){ Q_D(QX11EmbedWidget); switch (event->type()) { case QEvent::FocusIn: switch (((QFocusEvent *)event)->reason()) { case Qt::MouseFocusReason: // If the user clicks into one of the client widget's // children and we didn't have focus already, we request // focus from our container. if (d->xEmbedWidget(o) == this) { if (d->currentFocus.isNull()) sendXEmbedMessage(d->container, x11Info().display(), XEMBED_REQUEST_FOCUS); d->currentFocus = qobject_cast<QWidget *>(o); } break; case Qt::TabFocusReason: // If the xembed client receives a focus event because of // a Tab, then we are at the end of our focus chain and we // ask the container to move to its next focus widget. if (o == this) { d->clearFocus(); sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_NEXT); return true; } else { // We're listening on events from qApp, so in order // for us to know who to set focus on if we receive an // activation event, we note the widget that got the // focusin last. if (d->xEmbedWidget(o) == this) d->currentFocus = qobject_cast<QWidget *>(o); } break; case Qt::BacktabFocusReason: // If the window receives a focus event because of // a Backtab, then we are at the start of our focus chain // and we ask the container to move to its previous focus // widget. if (o == this) { // See comment for Tab. // If we receive a XEMBED_FOCUS_IN // XEMBED_FOCUS_CURRENT, we will set focus in // currentFocus. To avoid that in this case, we reset // currentFocus. d->clearFocus(); sendXEmbedMessage(d->container, x11Info().display(), XEMBED_FOCUS_PREV); return true; } else { if (d->xEmbedWidget(o) == this) d->currentFocus = qobject_cast<QWidget *>(o); } break; case Qt::ActiveWindowFocusReason: if (!d->currentFocus.isNull()) { if (!d->currentFocus->hasFocus()) d->currentFocus->setFocus(Qt::OtherFocusReason); } else { d->clearFocus(); return true; } break; case Qt::PopupFocusReason: case Qt::ShortcutFocusReason: case Qt::OtherFocusReason: // If focus is received to any child widget because of any // other reason, remember the widget so that we can give // it focus again if we're activated. if (d->xEmbedWidget(o) == this) { d->currentFocus = qobject_cast<QWidget *>(o); } break; default: break; } break; case QEvent::MouseButtonPress: // If we get a mouse button press event inside a embedded widget // make sure this is the active window in qapp. d->checkActivateWindow(o); break; default: break; } return QWidget::eventFilter(o, event);}/*! \internal Handles some notification events and client messages. Client side XEmbed message receiving is also handled here.*/bool QX11EmbedWidget::x11Event(XEvent *event){ Q_D(QX11EmbedWidget); switch (event->type) { case DestroyNotify: // If the container window is destroyed, we signal this to the user. emit containerClosed(); break; case ReparentNotify: // If the container shuts down, we will be reparented to the // root window. We must also consider the case that we may be // reparented from one container to another. if (event->xreparent.parent == x11Info().appRootWindow()) { emit containerClosed(); return true; } else { d->container = event->xreparent.parent; } break; case UnmapNotify: // Mapping and unmapping are handled by changes to the // _XEMBED_INFO property. Any default map/unmap requests are // ignored. return true; case PropertyNotify: // The container sends us map/unmap messages through the // _XEMBED_INFO property. We adhere to the XEMBED_MAPPED bit in // data2. if (event->xproperty.atom == _XEMBED_INFO) { Atom actual_type_return; int actual_format_return; unsigned long nitems_return; unsigned long bytes_after_return; unsigned char *prop_return = 0; if (XGetWindowProperty(x11Info().display(), winId(), _XEMBED_INFO, 0, 2, false, XA_CARDINAL, &actual_type_return, &actual_format_return, &nitems_return, &bytes_after_return, &prop_return) == Success) { if (nitems_return > 1) { if (((int * )prop_return)[1] & XEMBED_MAPPED) { XMapWindow(x11Info().display(), winId()); } else { XUnmapWindow(x11Info().display(), winId()); } } } } break; case ClientMessage: // XEMBED messages have message_type _XEMBED if (event->xclient.message_type == _XEMBED) { // Discard XEMBED messages not to ourselves. (### dead code?) if (event->xclient.window != winId()) break; // Update qt_x_time if necessary Time msgtime = (Time) event->xclient.data.l[0]; if (msgtime > X11->time) X11->time = msgtime; switch (event->xclient.data.l[1]) { case XEMBED_WINDOW_ACTIVATE: { // When we receive an XEMBED_WINDOW_ACTIVATE, we need // to send ourselves a synthetic FocusIn X11 event for // Qt to activate us. XEvent ev; memset(&ev, 0, sizeof(ev)); ev.xfocus.display = x11Info().display(); ev.xfocus.type = XFocusIn; ev.xfocus.window = winId(); ev.xfocus.mode = NotifyNormal; ev.xfocus.detail = NotifyNonlinear; ((QApplication *)QApplication::instance())->x11ProcessEvent(&ev); } break; case XEMBED_WINDOW_DEACTIVATE: { // When we receive an XEMBED_WINDOW_DEACTIVATE, we // need to send ourselves a synthetic FocusOut event // for Qt to deativate us. XEvent ev; memset(&ev, 0, sizeof(ev)); ev.xfocus.display = x11Info().display(); ev.xfocus.type = XFocusOut; ev.xfocus.window = winId(); ev.xfocus.mode = NotifyNormal; ev.xfocus.detail = NotifyNonlinear; ((QApplication *)QApplication::instance())->x11ProcessEvent(&ev); } break; case XEMBED_EMBEDDED_NOTIFY: { // In this message's l[2] we have the max version // supported by both the client and the // container. QX11EmbedWidget does not use this field. // We have been embedded, so we set our // client's embedded flag. d->setEmbedded(); emit embedded(); } break; case XEMBED_FOCUS_IN: // in case we embed more than one topLevel window inside the same // host window. if (window() != qApp->activeWindow()) qApp->setActiveWindow(this); switch (event->xclient.data.l[2]) { case XEMBED_FOCUS_CURRENT: // The container sends us this message if it wants // us to focus on the widget that last had focus. // This is the reply when XEMBED_REQUEST_FOCUS is // sent to the container. if (!d->currentFocus.isNull()) { if (!d->currentFocus->hasFocus()) d->currentFocus->setFocus(Qt::OtherFocusReason); } else { // No widget currently has focus. We set focus // on the first widget next to the // client widget. Since the setFocus will not work // if the window is disabled, set the currentFocus // directly so that it's set on window activate. d->currentFocus = d->getFocusWidget(QX11EmbedWidgetPrivate::FirstFocusWidget); d->currentFocus->setFocus(Qt::OtherFocusReason); } break; case XEMBED_FOCUS_FIRST:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -