diff options
author | Alberto Mardegan <alberto.mardegan@canonical.com> | 2012-12-12 17:18:28 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-03-06 18:59:07 +0100 |
commit | b5bdd31de41cb5e6d6abedce79864fc01d8d4984 (patch) | |
tree | 030b374282b12a2857d80295a993fc550cb722f7 /src/widgets | |
parent | f0533ba8c22d6366f9d4fb8e8ce18554cd0d01e9 (diff) |
Implement XEmbed protocol
Add a static QWindow::fromWinId(WId id) constructor which can be used to
create a QWindow object representing windows created by other processes.
Then, QWindow::setParent() can be used to embed a window into a foreign
window socket and QWindow::setTransientParent() to stick the current
window on top of a foreign window.
The changes in the QtWidgets module ensure that the focus chain (TAB
navigation) correctly works when a QtWidgets-based window is embedded
into another application.
As far as the platform implementation is concerned, this commit only
implements the embedding functionality in the XCB plugin. So, this is
roughly equivalent to the Qt4 QX11EmbedWidget functionality.
Change-Id: Iff8f7b9ee974d33fb30f36056f7838b433a413c7
Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com>
Diffstat (limited to 'src/widgets')
-rw-r--r-- | src/widgets/kernel/qapplication.cpp | 14 | ||||
-rw-r--r-- | src/widgets/kernel/qapplication_p.h | 3 | ||||
-rw-r--r-- | src/widgets/kernel/qwidget.cpp | 28 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow.cpp | 40 | ||||
-rw-r--r-- | src/widgets/kernel/qwidgetwindow_qpa_p.h | 7 |
5 files changed, 88 insertions, 4 deletions
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp index cff75f258e..1e493fe8c6 100644 --- a/src/widgets/kernel/qapplication.cpp +++ b/src/widgets/kernel/qapplication.cpp @@ -2010,7 +2010,8 @@ void QApplication::setActiveWindow(QWidget* act) * Returns 0 if a new focus widget could not be found. * Shared with QGraphicsProxyWidgetPrivate::findFocusChild() */ -QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool next) +QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool next, + bool *wrappingOccurred) { uint focus_flag = qt_tab_all_widgets() ? Qt::TabFocus : Qt::StrongFocus; @@ -2020,18 +2021,29 @@ QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool QWidget *w = f; QWidget *test = f->d_func()->focus_next; + bool seenWindow = false; + bool focusWidgetAfterWindow = false; while (test && test != f) { + if (test->isWindow()) + seenWindow = true; + if ((test->focusPolicy() & focus_flag) == focus_flag && !(test->d_func()->extra && test->d_func()->extra->focus_proxy) && test->isVisibleTo(toplevel) && test->isEnabled() && !(w->windowType() == Qt::SubWindow && !w->isAncestorOf(test)) && (toplevel->windowType() != Qt::SubWindow || toplevel->isAncestorOf(test))) { w = test; + if (seenWindow) + focusWidgetAfterWindow = true; if (next) break; } test = test->d_func()->focus_next; } + + if (wrappingOccurred != 0) + *wrappingOccurred = next ? focusWidgetAfterWindow : !focusWidgetAfterWindow; + if (w == f) { if (qt_in_tab_key_event) { w->window()->setAttribute(Qt::WA_KeyboardFocusChange); diff --git a/src/widgets/kernel/qapplication_p.h b/src/widgets/kernel/qapplication_p.h index fbd96366fb..85e26fdd49 100644 --- a/src/widgets/kernel/qapplication_p.h +++ b/src/widgets/kernel/qapplication_p.h @@ -165,7 +165,8 @@ public: void closePopup(QWidget *popup); void openPopup(QWidget *popup); static void setFocusWidget(QWidget *focus, Qt::FocusReason reason); - static QWidget *focusNextPrevChild_helper(QWidget *toplevel, bool next); + static QWidget *focusNextPrevChild_helper(QWidget *toplevel, bool next, + bool *wrappingOccurred = 0); #ifndef QT_NO_GRAPHICSVIEW // Maintain a list of all scenes to ensure font and palette propagation to diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index e5df25e972..7840cddd5d 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -6138,10 +6138,34 @@ bool QWidget::focusNextPrevChild(bool next) if (d->extra && d->extra->proxyWidget) return d->extra->proxyWidget->focusNextPrevChild(next); #endif - QWidget *w = QApplicationPrivate::focusNextPrevChild_helper(this, next); + + bool wrappingOccurred = false; + QWidget *w = QApplicationPrivate::focusNextPrevChild_helper(this, next, + &wrappingOccurred); if (!w) return false; - w->setFocus(next ? Qt::TabFocusReason : Qt::BacktabFocusReason); + Qt::FocusReason reason = next ? Qt::TabFocusReason : Qt::BacktabFocusReason; + + /* If we are about to wrap the focus chain, give the platform + * implementation a chance to alter the wrapping behavior. This is + * especially needed when the window is embedded in a window created by + * another process. + */ + if (wrappingOccurred) { + QWindow *window = windowHandle(); + if (window != 0) { + QWindowPrivate *winp = qt_window_private(window); + + if (winp->platformWindow != 0) { + QFocusEvent event(QEvent::FocusIn, reason); + event.ignore(); + winp->platformWindow->windowEvent(&event); + if (event.isAccepted()) return true; + } + } + } + + w->setFocus(reason); return true; } diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index c543303024..183787ccc3 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -52,6 +52,8 @@ QT_BEGIN_NAMESPACE +Q_WIDGETS_EXPORT extern bool qt_tab_all_widgets(); + QWidget *qt_button_down = 0; // widget got last button-down static QWidget *qt_tablet_target = 0; @@ -123,6 +125,8 @@ bool QWidgetWindow::event(QEvent *event) // these should not be sent to QWidget, the corresponding events // are sent by QApplicationPrivate::notifyActiveWindowChange() case QEvent::FocusIn: + handleFocusInEvent(static_cast<QFocusEvent *>(event)); + // Fallthrough case QEvent::FocusOut: { #ifndef QT_NO_ACCESSIBILITY QAccessible::State state; @@ -284,6 +288,42 @@ void QWidgetWindow::handleEnterLeaveEvent(QEvent *event) } } +QWidget *QWidgetWindow::getFocusWidget(FocusWidgets fw) +{ + QWidget *tlw = m_widget; + QWidget *w = tlw->nextInFocusChain(); + + QWidget *last = tlw; + + uint focus_flag = qt_tab_all_widgets() ? Qt::TabFocus : Qt::StrongFocus; + + while (w != tlw) + { + if (((w->focusPolicy() & focus_flag) == focus_flag) + && w->isVisibleTo(m_widget) && w->isEnabled()) + { + last = w; + if (fw == FirstFocusWidget) + break; + } + w = w->nextInFocusChain(); + } + + return last; +} + +void QWidgetWindow::handleFocusInEvent(QFocusEvent *e) +{ + QWidget *focusWidget = 0; + if (e->reason() == Qt::BacktabFocusReason) + focusWidget = getFocusWidget(LastFocusWidget); + else if (e->reason() == Qt::TabFocusReason) + focusWidget = getFocusWidget(FirstFocusWidget); + + if (focusWidget != 0) + focusWidget->setFocus(); +} + void QWidgetWindow::handleNonClientAreaMouseEvent(QMouseEvent *e) { QApplication::sendSpontaneousEvent(m_widget, e); diff --git a/src/widgets/kernel/qwidgetwindow_qpa_p.h b/src/widgets/kernel/qwidgetwindow_qpa_p.h index 84c1b90826..77fdcbeb56 100644 --- a/src/widgets/kernel/qwidgetwindow_qpa_p.h +++ b/src/widgets/kernel/qwidgetwindow_qpa_p.h @@ -70,6 +70,7 @@ protected: void handleCloseEvent(QCloseEvent *); void handleEnterLeaveEvent(QEvent *); + void handleFocusInEvent(QFocusEvent *); void handleKeyEvent(QKeyEvent *); void handleMouseEvent(QMouseEvent *); void handleNonClientAreaMouseEvent(QMouseEvent *); @@ -100,6 +101,12 @@ private slots: private: void updateGeometry(); + enum FocusWidgets { + FirstFocusWidget, + LastFocusWidget + }; + QWidget *getFocusWidget(FocusWidgets fw); + QWidget *m_widget; QPointer<QWidget> m_implicit_mouse_grabber; #ifndef QT_NO_DRAGANDDROP |