summaryrefslogtreecommitdiffstats
path: root/src/widgets/kernel
diff options
context:
space:
mode:
authorAlberto Mardegan <alberto.mardegan@canonical.com>2012-12-12 17:18:28 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-03-06 18:59:07 +0100
commitb5bdd31de41cb5e6d6abedce79864fc01d8d4984 (patch)
tree030b374282b12a2857d80295a993fc550cb722f7 /src/widgets/kernel
parentf0533ba8c22d6366f9d4fb8e8ce18554cd0d01e9 (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/kernel')
-rw-r--r--src/widgets/kernel/qapplication.cpp14
-rw-r--r--src/widgets/kernel/qapplication_p.h3
-rw-r--r--src/widgets/kernel/qwidget.cpp28
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp40
-rw-r--r--src/widgets/kernel/qwidgetwindow_qpa_p.h7
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