summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/global/qnamespace.h1
-rw-r--r--src/corelib/global/qnamespace.qdoc4
-rw-r--r--src/gui/kernel/qguiapplication.cpp2
-rw-r--r--src/gui/kernel/qplatformintegration.cpp4
-rw-r--r--src/gui/kernel/qplatformintegration.h3
-rw-r--r--src/gui/kernel/qwindow.cpp37
-rw-r--r--src/gui/kernel/qwindow.h2
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp5
-rw-r--r--src/gui/kernel/qwindowsysteminterface.h3
-rw-r--r--src/gui/kernel/qwindowsysteminterface_p.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp4
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp1
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp260
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h9
-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
20 files changed, 410 insertions, 24 deletions
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 41bca2a443..a33c50a041 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -284,6 +284,7 @@ public:
SplashScreen = ToolTip | Dialog,
Desktop = 0x00000010 | Window,
SubWindow = 0x00000012,
+ ForeignWindow = 0x00000020 | Window,
WindowType_Mask = 0x000000ff,
MSWindowsFixedSizeDialogHint = 0x00000100,
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 8ec206a572..02d00c213b 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -1966,6 +1966,10 @@
\value SubWindow Indicates that this widget is a sub-window, such
as a QMdiSubWindow widget.
+ \value ForeignWindow Indicates that this window object is a handle
+ representing a native platform window created by
+ another process or by manually using native code.
+
There are also a number of flags which you can use to customize
the appearance of top-level windows. These have no effect on other
windows:
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index 7bfc9ccbec..32c52d2fe2 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -1605,7 +1605,7 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate
}
if (QGuiApplicationPrivate::focus_window) {
- QFocusEvent focusIn(QEvent::FocusIn);
+ QFocusEvent focusIn(QEvent::FocusIn, e->reason);
QCoreApplication::sendSpontaneousEvent(QGuiApplicationPrivate::focus_window, &focusIn);
QObject::connect(QGuiApplicationPrivate::focus_window, SIGNAL(focusObjectChanged(QObject*)),
qApp, SLOT(_q_updateFocusObject(QObject*)));
diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp
index fbc7eeb76f..70de75072c 100644
--- a/src/gui/kernel/qplatformintegration.cpp
+++ b/src/gui/kernel/qplatformintegration.cpp
@@ -206,6 +206,10 @@ QPlatformServices *QPlatformIntegration::services() const
state explicitly by using QWindowSystemInterface::handleApplicationStateChanged().
If not set, application state will follow window activation, which is the normal
behavior for desktop platforms.
+
+ \value ForeignWindows The platform allows creating QWindows which represent
+ native windows created by other processes or anyway created by using native
+ libraries.
*/
diff --git a/src/gui/kernel/qplatformintegration.h b/src/gui/kernel/qplatformintegration.h
index 55517cf600..ddee6f05c8 100644
--- a/src/gui/kernel/qplatformintegration.h
+++ b/src/gui/kernel/qplatformintegration.h
@@ -89,7 +89,8 @@ public:
BufferQueueingOpenGL,
WindowMasks,
MultipleWindows,
- ApplicationState
+ ApplicationState,
+ ForeignWindows
};
virtual ~QPlatformIntegration() { }
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 99a54dc847..3d4383301e 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -474,6 +474,10 @@ void QWindow::create()
WId QWindow::winId() const
{
Q_D(const QWindow);
+
+ if (type() == Qt::ForeignWindow)
+ return WId(property("_q_foreignWinId").value<WId>());
+
if(!d->platformWindow)
const_cast<QWindow *>(this)->create();
@@ -499,8 +503,11 @@ QWindow *QWindow::parent() const
the clip of the window, so it will be clipped to the \a parent window.
Setting \a parent to be 0 will make the window become a top level window.
-*/
+ If \a parent is a window created by fromWinId(), then the current window
+ will be embedded inside \a parent, if the platform supports it. Window
+ embedding is currently supported only by the X11 platform plugin.
+*/
void QWindow::setParent(QWindow *parent)
{
Q_D(QWindow);
@@ -2104,6 +2111,34 @@ void QWindowPrivate::maybeQuitOnLastWindowClosed()
}
+/*!
+ Creates a local representation of a window created by another process or by
+ using native libraries below Qt.
+
+ Given the handle \a id to a native window, this method creates a QWindow
+ object which can be used to represent the window when invoking methods like
+ setParent() and setTransientParent().
+ This can be used, on platforms which support it, to embed a window inside a
+ container or to make a window stick on top of a window created by another
+ process.
+
+ \sa setParent()
+ \sa setTransientParent()
+*/
+QWindow *QWindow::fromWinId(WId id)
+{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ForeignWindows)) {
+ qWarning() << "QWindow::fromWinId(): platform plugin does not support foreign windows.";
+ return 0;
+ }
+
+ QWindow *window = new QWindow;
+ window->setFlags(Qt::ForeignWindow);
+ window->setProperty("_q_foreignWinId", QVariant::fromValue(id));
+ window->create();
+ return window;
+}
+
#ifndef QT_NO_CURSOR
/*!
\brief set the cursor shape for this window
diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h
index 0842e9ceb6..ca3ffb0709 100644
--- a/src/gui/kernel/qwindow.h
+++ b/src/gui/kernel/qwindow.h
@@ -257,6 +257,8 @@ public:
void unsetCursor();
#endif
+ static QWindow *fromWinId(WId id);
+
public Q_SLOTS:
void setVisible(bool visible);
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 3609d5dce6..d2add91d66 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -112,9 +112,10 @@ void QWindowSystemInterface::handleEnterLeaveEvent(QWindow *enter, QWindow *leav
}
}
-void QWindowSystemInterface::handleWindowActivated(QWindow *tlw)
+void QWindowSystemInterface::handleWindowActivated(QWindow *tlw, Qt::FocusReason r)
{
- QWindowSystemInterfacePrivate::ActivatedWindowEvent *e = new QWindowSystemInterfacePrivate::ActivatedWindowEvent(tlw);
+ QWindowSystemInterfacePrivate::ActivatedWindowEvent *e =
+ new QWindowSystemInterfacePrivate::ActivatedWindowEvent(tlw, r);
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
}
diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h
index 22e5983a07..212259c113 100644
--- a/src/gui/kernel/qwindowsysteminterface.h
+++ b/src/gui/kernel/qwindowsysteminterface.h
@@ -135,7 +135,8 @@ public:
static void handleEnterEvent(QWindow *w, const QPointF &local = QPointF(), const QPointF& global = QPointF());
static void handleLeaveEvent(QWindow *w);
static void handleEnterLeaveEvent(QWindow *enter, QWindow *leave, const QPointF &local = QPointF(), const QPointF& global = QPointF());
- static void handleWindowActivated(QWindow *w);
+ static void handleWindowActivated(QWindow *w, Qt::FocusReason r = Qt::OtherFocusReason);
+
static void handleWindowStateChanged(QWindow *w, Qt::WindowState newState);
static void handleApplicationStateChanged(Qt::ApplicationState newState);
diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h
index eca559abfa..f1bc4667f7 100644
--- a/src/gui/kernel/qwindowsysteminterface_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_p.h
@@ -139,10 +139,11 @@ public:
class ActivatedWindowEvent : public WindowSystemEvent {
public:
- explicit ActivatedWindowEvent(QWindow *activatedWindow)
- : WindowSystemEvent(ActivatedWindow), activated(activatedWindow)
+ explicit ActivatedWindowEvent(QWindow *activatedWindow, Qt::FocusReason r)
+ : WindowSystemEvent(ActivatedWindow), activated(activatedWindow), reason(r)
{ }
QPointer<QWindow> activated;
+ Qt::FocusReason reason;
};
class WindowStateChangedEvent : public WindowSystemEvent {
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 2467eb6e7a..1504bd99d2 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1066,7 +1066,7 @@ void QXcbConnection::processXcbEvents()
while (it != m_peekFuncs.end()) {
// These callbacks return true if the event is what they were
// waiting for, remove them from the list in that case.
- if ((*it)(event))
+ if ((*it)(this, event))
it = m_peekFuncs.erase(it);
else
++it;
@@ -1086,7 +1086,7 @@ void QXcbConnection::processXcbEvents()
// Indicate with a null event that the event the callbacks are waiting for
// is not in the queue currently.
Q_FOREACH (PeekFunc f, m_peekFuncs)
- f(0);
+ f(this, 0);
m_peekFuncs.clear();
xcb_flush(xcb_connection());
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index b499f75b78..f69a8a9f35 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -364,7 +364,7 @@ public:
template<typename T>
inline xcb_generic_event_t *checkEvent(T &checker);
- typedef bool (*PeekFunc)(xcb_generic_event_t *);
+ typedef bool (*PeekFunc)(QXcbConnection *, xcb_generic_event_t *);
void addPeekFunc(PeekFunc f);
inline xcb_timestamp_t time() const { return m_time; }
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 0a02ea02af..f0cabea43d 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -228,6 +228,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
case ThreadedOpenGL: return m_connections.at(0)->supportsThreadedRendering();
case WindowMasks: return true;
case MultipleWindows: return true;
+ case ForeignWindows: return true;
default: return QPlatformIntegration::hasCapability(cap);
}
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index abd2f7a147..27cd163c36 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -122,6 +122,36 @@ enum {
QT_BEGIN_NAMESPACE
+#undef FocusIn
+
+enum QX11EmbedFocusInDetail {
+ XEMBED_FOCUS_CURRENT = 0,
+ XEMBED_FOCUS_FIRST = 1,
+ XEMBED_FOCUS_LAST = 2
+};
+
+enum QX11EmbedInfoFlags {
+ XEMBED_MAPPED = (1 << 0),
+};
+
+enum QX11EmbedMessageType {
+ XEMBED_EMBEDDED_NOTIFY = 0,
+ XEMBED_WINDOW_ACTIVATE = 1,
+ XEMBED_WINDOW_DEACTIVATE = 2,
+ XEMBED_REQUEST_FOCUS = 3,
+ XEMBED_FOCUS_IN = 4,
+ XEMBED_FOCUS_OUT = 5,
+ XEMBED_FOCUS_NEXT = 6,
+ XEMBED_FOCUS_PREV = 7,
+ XEMBED_MODALITY_ON = 10,
+ XEMBED_MODALITY_OFF = 11,
+ XEMBED_REGISTER_ACCELERATOR = 12,
+ XEMBED_UNREGISTER_ACCELERATOR = 13,
+ XEMBED_ACTIVATE_ACCELERATOR = 14
+};
+
+static unsigned int XEMBED_VERSION = 0;
+
// Returns true if we should set WM_TRANSIENT_FOR on \a w
static inline bool isTransient(const QWindow *w)
{
@@ -157,6 +187,7 @@ QXcbWindow::QXcbWindow(QWindow *window)
, m_mapped(false)
, m_transparent(false)
, m_deferredActivation(false)
+ , m_embedded(false)
, m_netWmUserTimeWindow(XCB_NONE)
, m_dirtyFrameMargins(false)
#if defined(XCB_USE_EGL)
@@ -168,7 +199,10 @@ QXcbWindow::QXcbWindow(QWindow *window)
setConnection(m_screen->connection());
- create();
+ if (window->type() != Qt::ForeignWindow)
+ create();
+ else
+ m_window = window->winId();
}
void QXcbWindow::create()
@@ -235,8 +269,10 @@ void QXcbWindow::create()
}
xcb_window_t xcb_parent_id = m_screen->root();
- if (parent())
+ if (parent()) {
xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
+ m_embedded = parent()->window()->type() == Qt::ForeignWindow;
+ }
m_format = window()->requestedFormat();
@@ -368,6 +404,14 @@ void QXcbWindow::create()
atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
1, &leader));
+ /* Add XEMBED info; this operation doesn't initiate the embedding. */
+ long data[] = { XEMBED_VERSION, XEMBED_MAPPED };
+ Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
+ atom(QXcbAtom::_XEMBED_INFO),
+ atom(QXcbAtom::_XEMBED_INFO),
+ 32, 2, (void *)data));
+
+
#ifdef XCB_USE_XINPUT2_MAEMO
if (connection()->isUsingXInput2Maemo()) {
XIEventMask xieventmask;
@@ -410,7 +454,8 @@ void QXcbWindow::create()
QXcbWindow::~QXcbWindow()
{
- destroy();
+ if (window()->type() != Qt::ForeignWindow)
+ destroy();
}
void QXcbWindow::destroy()
@@ -574,9 +619,10 @@ void QXcbWindow::show()
propagateSizeHints();
// update WM_TRANSIENT_FOR
- if (isTransient(window())) {
+ const QWindow *tp = window()->transientParent();
+ if (isTransient(window()) || tp != 0) {
xcb_window_t transientXcbParent = 0;
- if (const QWindow *tp = window()->transientParent())
+ if (tp)
transientXcbParent = static_cast<const QXcbWindow *>(tp->handle())->winId();
// Default to client leader if there is no transient parent, else modal dialogs can
// be hidden by their parents.
@@ -1140,7 +1186,15 @@ void QXcbWindow::setParent(const QPlatformWindow *parent)
{
QPoint topLeft = geometry().topLeft();
- xcb_window_t xcb_parent_id = parent ? static_cast<const QXcbWindow *>(parent)->xcb_window() : m_screen->root();
+ xcb_window_t xcb_parent_id;
+ if (parent) {
+ const QXcbWindow *qXcbParent = static_cast<const QXcbWindow *>(parent);
+ xcb_parent_id = qXcbParent->xcb_window();
+ m_embedded = qXcbParent->window()->type() == Qt::ForeignWindow;
+ } else {
+ xcb_parent_id = m_screen->root();
+ m_embedded = false;
+ }
Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), xcb_parent_id, topLeft.x(), topLeft.y()));
}
@@ -1271,6 +1325,13 @@ void QXcbWindow::propagateSizeHints()
void QXcbWindow::requestActivateWindow()
{
+ /* Never activate embedded windows; doing that would prevent the container
+ * to re-gain the keyboard focus later. */
+ if (m_embedded) {
+ QPlatformWindow::requestActivateWindow();
+ return;
+ }
+
if (!m_mapped) {
m_deferredActivation = true;
return;
@@ -1434,7 +1495,8 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
} else if (event->type == atom(QXcbAtom::XdndDrop)) {
connection()->drag()->handleDrop(window(), event);
#endif
- } else if (event->type == atom(QXcbAtom::_XEMBED)) { // QSystemTrayIcon
+ } else if (event->type == atom(QXcbAtom::_XEMBED)) {
+ handleXEmbedMessage(event);
} else {
qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type);
}
@@ -1476,6 +1538,53 @@ bool QXcbWindow::isExposed() const
return m_mapped;
}
+bool QXcbWindow::isEmbedded(const QPlatformWindow *parentWindow) const
+{
+ if (!m_embedded)
+ return false;
+
+ return parentWindow ? (parentWindow == parent()) : true;
+}
+
+QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const
+{
+ if (!m_embedded)
+ return pos;
+
+ QPoint ret;
+ xcb_translate_coordinates_cookie_t cookie =
+ xcb_translate_coordinates(xcb_connection(), xcb_window(), m_screen->root(),
+ pos.x(), pos.y());
+ xcb_translate_coordinates_reply_t *reply =
+ xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
+ if (reply) {
+ ret.setX(reply->dst_x);
+ ret.setY(reply->dst_y);
+ free(reply);
+ }
+
+ return ret;
+}
+
+QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const
+{
+ if (!m_embedded)
+ return pos;
+ QPoint ret;
+ xcb_translate_coordinates_cookie_t cookie =
+ xcb_translate_coordinates(xcb_connection(), m_screen->root(), xcb_window(),
+ pos.x(), pos.y());
+ xcb_translate_coordinates_reply_t *reply =
+ xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
+ if (reply) {
+ ret.setX(reply->dst_x);
+ ret.setY(reply->dst_y);
+ free(reply);
+ }
+
+ return ret;
+}
+
void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
{
if (event->window == m_window) {
@@ -1506,6 +1615,15 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
updateNetWmUserTime(event->time);
+ if (m_embedded) {
+ if (window() != QGuiApplication::focusWindow()) {
+ const QXcbWindow *container = static_cast<const QXcbWindow *>(parent());
+ Q_ASSERT(container != 0);
+
+ sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS);
+ }
+ }
+
QPoint local(event->event_x, event->event_y);
QPoint global(event->root_x, event->root_y);
@@ -1661,6 +1779,25 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
QWindowSystemInterface::handleWindowStateChanged(window(), newState);
m_lastWindowStateEvent = newState;
}
+ return;
+ }
+
+ const xcb_atom_t xEmbedInfoAtom = atom(QXcbAtom::_XEMBED_INFO);
+ if (event->atom == xEmbedInfoAtom) {
+ const xcb_get_property_cookie_t get_cookie =
+ xcb_get_property(xcb_connection(), 0, m_window, xEmbedInfoAtom,
+ XCB_ATOM_ANY, 0, 3);
+
+ xcb_get_property_reply_t *reply =
+ xcb_get_property_reply(xcb_connection(), get_cookie, NULL);
+ if (reply && reply->length >= 2) {
+ const long *data = (const long *)xcb_get_property_value(reply);
+ if (data[1] & XEMBED_MAPPED)
+ Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
+ else
+ Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window));
+ }
+ free(reply);
}
}
@@ -1672,7 +1809,7 @@ void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *)
QWindowSystemInterface::handleWindowActivated(w);
}
-static bool focusInPeeker(xcb_generic_event_t *event)
+static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event)
{
if (!event) {
// FocusIn event is not in the queue, proceed with FocusOut normally.
@@ -1680,7 +1817,18 @@ static bool focusInPeeker(xcb_generic_event_t *event)
return true;
}
uint response_type = event->response_type & ~0x80;
- return response_type == XCB_FOCUS_IN;
+ if (response_type == XCB_FOCUS_IN)
+ return true;
+
+ /* We are also interested in XEMBED_FOCUS_IN events */
+ if (response_type == XCB_CLIENT_MESSAGE) {
+ xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event;
+ if (cme->type == connection->atom(QXcbAtom::_XEMBED)
+ && cme->data.data32[1] == XEMBED_FOCUS_IN)
+ return true;
+ }
+
+ return false;
}
void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
@@ -1744,6 +1892,35 @@ void QXcbWindow::setCursor(xcb_cursor_t cursor)
xcb_flush(xcb_connection());
}
+void QXcbWindow::windowEvent(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::FocusIn:
+ if (m_embedded && !event->spontaneous()) {
+ QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event);
+ switch (focusEvent->reason()) {
+ case Qt::TabFocusReason:
+ case Qt::BacktabFocusReason:
+ {
+ const QXcbWindow *container =
+ static_cast<const QXcbWindow *>(parent());
+ sendXEmbedMessage(container->xcb_window(),
+ focusEvent->reason() == Qt::TabFocusReason ?
+ XEMBED_FOCUS_NEXT : XEMBED_FOCUS_PREV);
+ event->accept();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ QPlatformWindow::windowEvent(event);
+}
+
bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
{
const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
@@ -1772,6 +1949,71 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
return true;
}
+// Sends an XEmbed message.
+void QXcbWindow::sendXEmbedMessage(xcb_window_t window, long message,
+ long detail, long data1, long data2)
+{
+ xcb_client_message_event_t event;
+
+ event.response_type = XCB_CLIENT_MESSAGE;
+ event.format = 32;
+ event.window = window;
+ event.type = atom(QXcbAtom::_XEMBED);
+ event.data.data32[0] = connection()->time();
+ event.data.data32[1] = message;
+ event.data.data32[2] = detail;
+ event.data.data32[3] = data1;
+ event.data.data32[4] = data2;
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, window,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&event));
+}
+
+static bool activeWindowChangeQueued(const QWindow *window)
+{
+ /* Check from window system event queue if the next queued activation
+ * targets a window other than @window.
+ */
+ QWindowSystemInterfacePrivate::ActivatedWindowEvent *systemEvent =
+ static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>
+ (QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::ActivatedWindow));
+ return systemEvent && systemEvent->activated != window;
+}
+
+void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event)
+{
+ connection()->setTime(event->data.data32[0]);
+ switch (event->data.data32[1]) {
+ case XEMBED_WINDOW_ACTIVATE:
+ case XEMBED_WINDOW_DEACTIVATE:
+ case XEMBED_EMBEDDED_NOTIFY:
+ break;
+ case XEMBED_FOCUS_IN:
+ Qt::FocusReason reason;
+ switch (event->data.data32[2]) {
+ case XEMBED_FOCUS_FIRST:
+ reason = Qt::TabFocusReason;
+ break;
+ case XEMBED_FOCUS_LAST:
+ reason = Qt::BacktabFocusReason;
+ break;
+ case XEMBED_FOCUS_CURRENT:
+ default:
+ reason = Qt::OtherFocusReason;
+ break;
+ }
+ connection()->setFocusWindow(static_cast<QXcbWindow*>(window()->handle()));
+ QWindowSystemInterface::handleWindowActivated(window(), reason);
+ break;
+ case XEMBED_FOCUS_OUT:
+ if (window() == QGuiApplication::focusWindow()
+ && !activeWindowChangeQueued(window())) {
+ connection()->setFocusWindow(0);
+ QWindowSystemInterface::handleWindowActivated(0);
+ }
+ break;
+ }
+}
+
#if !defined(QT_NO_SHAPE)
static inline xcb_rectangle_t qRectToXCBRectangle(const QRect &r)
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 3b5404684f..1810a58c7b 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -87,6 +87,9 @@ public:
void setParent(const QPlatformWindow *window);
bool isExposed() const;
+ bool isEmbedded(const QPlatformWindow *parentWindow) const;
+ QPoint mapToGlobal(const QPoint &pos) const;
+ QPoint mapFromGlobal(const QPoint &pos) const;
void setWindowTitle(const QString &title);
void setWindowIcon(const QIcon &icon);
@@ -107,6 +110,8 @@ public:
QSurfaceFormat format() const;
+ void windowEvent(QEvent *event);
+
bool startSystemResize(const QPoint &pos, Qt::Corner corner);
void setOpacity(qreal level);
@@ -158,6 +163,9 @@ private:
void updateDoesNotAcceptFocus(bool doesNotAcceptFocus);
QRect windowToWmGeometry(QRect r) const;
+ void sendXEmbedMessage(xcb_window_t window, long message,
+ long detail = 0, long data1 = 0, long data2 = 0);
+ void handleXEmbedMessage(const xcb_client_message_event_t *event);
void create();
void destroy();
@@ -184,6 +192,7 @@ private:
bool m_deferredActivation;
bool m_deferredExpose;
bool m_configureNotifyPending;
+ bool m_embedded;
xcb_window_t m_netWmUserTimeWindow;
QSurfaceFormat m_format;
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