Add support for screen overlays / foreign windows

We're not the only one creating native windows. When using the
multimedia API, the multimedia library creates a video window
for video display. Here we need to deal with giving this video
window overlay a proper z-order, otherwise it will never get
visible.

Change-Id: Ibff0382ebee5cda87408b91c8181a4104fc4a1a3
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
Reviewed-by: Kevin Krammer <kevin.krammer@kdab.com>
Reviewed-by: Robin Burchell <robin+qt@viroteck.net>
This commit is contained in:
Thomas McGuire 2012-03-29 16:13:52 +02:00 committed by Qt by Nokia
parent b5f343b367
commit 4efd61c3cf
8 changed files with 103 additions and 14 deletions

View File

@ -49,9 +49,11 @@
#include <cctype> #include <cctype>
QQnxEventThread::QQnxEventThread(screen_context_t context) QQnxEventThread::QQnxEventThread(screen_context_t context,
QQnxScreenEventHandler *screenEventHandler)
: QThread(), : QThread(),
m_screenContext(context), m_screenContext(context),
m_screenEventHandler(screenEventHandler),
m_quit(false) m_quit(false)
{ {
} }
@ -69,7 +71,6 @@ void QQnxEventThread::injectKeyboardEvent(int flags, int sym, int mod, int scan,
void QQnxEventThread::run() void QQnxEventThread::run()
{ {
QQnxScreenEventHandler eventHandler;
screen_event_t event; screen_event_t event;
// create screen event // create screen event
@ -106,7 +107,7 @@ void QQnxEventThread::run()
#endif #endif
m_quit = true; m_quit = true;
} else { } else {
eventHandler.handleEvent(event, qnxType); m_screenEventHandler->handleEvent(event, qnxType);
} }
} }

View File

@ -48,10 +48,12 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QQnxScreenEventHandler;
class QQnxEventThread : public QThread class QQnxEventThread : public QThread
{ {
public: public:
explicit QQnxEventThread(screen_context_t context); QQnxEventThread(screen_context_t context, QQnxScreenEventHandler *screenEventHandler);
virtual ~QQnxEventThread(); virtual ~QQnxEventThread();
static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap); static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
@ -63,6 +65,7 @@ private:
void shutdown(); void shutdown();
screen_context_t m_screenContext; screen_context_t m_screenContext;
QQnxScreenEventHandler *m_screenEventHandler;
bool m_quit; bool m_quit;
}; };

View File

@ -46,6 +46,7 @@
#include "qqnxnavigatoreventhandler.h" #include "qqnxnavigatoreventhandler.h"
#include "qqnxrasterbackingstore.h" #include "qqnxrasterbackingstore.h"
#include "qqnxscreen.h" #include "qqnxscreen.h"
#include "qqnxscreeneventhandler.h"
#include "qqnxwindow.h" #include "qqnxwindow.h"
#include "qqnxvirtualkeyboard.h" #include "qqnxvirtualkeyboard.h"
#include "qqnxclipboard.h" #include "qqnxclipboard.h"
@ -85,6 +86,7 @@ QQnxIntegration::QQnxIntegration()
, m_paintUsingOpenGL(false) , m_paintUsingOpenGL(false)
, m_eventDispatcher(createUnixEventDispatcher()) , m_eventDispatcher(createUnixEventDispatcher())
, m_services(0) , m_services(0)
, m_screenEventHandler(new QQnxScreenEventHandler())
#ifndef QT_NO_CLIPBOARD #ifndef QT_NO_CLIPBOARD
, m_clipboard(0) , m_clipboard(0)
#endif #endif
@ -106,7 +108,7 @@ QQnxIntegration::QQnxIntegration()
QQnxGLContext::initialize(); QQnxGLContext::initialize();
// Create/start event thread // Create/start event thread
m_eventThread = new QQnxEventThread(m_screenContext); m_eventThread = new QQnxEventThread(m_screenContext, m_screenEventHandler);
m_eventThread->start(); m_eventThread->start();
// Create/start navigator event handler // Create/start navigator event handler
@ -145,6 +147,8 @@ QQnxIntegration::~QQnxIntegration()
qDebug() << "QQnx: platform plugin shutdown begin"; qDebug() << "QQnx: platform plugin shutdown begin";
#endif #endif
delete m_screenEventHandler;
// Destroy input context // Destroy input context
delete m_inputContext; delete m_inputContext;
@ -342,6 +346,11 @@ void QQnxIntegration::createDisplays()
QQnxScreen *screen = new QQnxScreen(m_screenContext, displays[i], i==0); QQnxScreen *screen = new QQnxScreen(m_screenContext, displays[i], i==0);
m_screens.append(screen); m_screens.append(screen);
screenAdded(screen); screenAdded(screen);
QObject::connect(m_screenEventHandler, SIGNAL(newWindowCreated(void *)),
screen, SLOT(newWindowCreated(void *)));
QObject::connect(m_screenEventHandler, SIGNAL(windowClosed(void *)),
screen, SLOT(windowClosed(void *)));
} }
} }

View File

@ -57,6 +57,7 @@ class QQnxAbstractVirtualKeyboard;
class QQnxWindow; class QQnxWindow;
class QQnxServices; class QQnxServices;
class QQnxScreen; class QQnxScreen;
class QQnxScreenEventHandler;
#ifndef QT_NO_CLIPBOARD #ifndef QT_NO_CLIPBOARD
class QQnxClipboard; class QQnxClipboard;
@ -115,6 +116,7 @@ private:
QAbstractEventDispatcher *m_eventDispatcher; QAbstractEventDispatcher *m_eventDispatcher;
QQnxServices *m_services; QQnxServices *m_services;
QList<QQnxScreen*> m_screens; QList<QQnxScreen*> m_screens;
QQnxScreenEventHandler *m_screenEventHandler;
#ifndef QT_NO_CLIPBOARD #ifndef QT_NO_CLIPBOARD
mutable QQnxClipboard* m_clipboard; mutable QQnxClipboard* m_clipboard;
#endif #endif

View File

@ -42,6 +42,7 @@
#include "qqnxscreen.h" #include "qqnxscreen.h"
#include "qqnxwindow.h" #include "qqnxwindow.h"
#include <QtCore/QThread>
#ifdef QQNXSCREEN_DEBUG #ifdef QQNXSCREEN_DEBUG
# include <QtCore/QDebug> # include <QtCore/QDebug>
#endif #endif
@ -260,6 +261,13 @@ void QQnxScreen::updateHierarchy()
for (it = m_childWindows.constBegin(); it != m_childWindows.constEnd(); ++it) for (it = m_childWindows.constBegin(); it != m_childWindows.constEnd(); ++it)
(*it)->updateZorder(topZorder); (*it)->updateZorder(topZorder);
topZorder++;
Q_FOREACH (screen_window_t overlay, m_overlays) {
if (screen_set_window_property_iv(overlay, SCREEN_PROPERTY_ZORDER, &topZorder) != 0)
qWarning("QQnxScreen: failed to update z order for overlay, errno=%d", errno);
topZorder++;
}
// After a hierarchy update, we need to force a flush on all screens. // After a hierarchy update, we need to force a flush on all screens.
// Right now, all screens share a context. // Right now, all screens share a context.
screen_flush_context( m_screenContext, 0 ); screen_flush_context( m_screenContext, 0 );
@ -291,5 +299,44 @@ void QQnxScreen::keyboardHeightChanged(int height)
QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), availableGeometry()); QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), availableGeometry());
} }
void QQnxScreen::addOverlayWindow(screen_window_t window)
{
m_overlays.append(window);
updateHierarchy();
}
void QQnxScreen::removeOverlayWindow(screen_window_t window)
{
const int numOverlaysRemoved = m_overlays.removeAll(window);
if (numOverlaysRemoved > 0)
updateHierarchy();
}
void QQnxScreen::newWindowCreated(void *window)
{
Q_ASSERT(thread() == QThread::currentThread());
const screen_window_t windowHandle = reinterpret_cast<screen_window_t>(window);
screen_display_t display = NULL;
if (screen_get_window_property_pv(windowHandle, SCREEN_PROPERTY_DISPLAY, (void**)&display) != 0) {
qWarning("QQnx: Failed to get screen for window, errno=%d", errno);
return;
}
if (display == nativeDisplay()) {
// A window was created on this screen. If we don't know about this window yet, it means
// it was not created by Qt, but by some foreign library like the multimedia renderer, which
// creates an overlay window when playing a video.
// Treat all foreign windows as overlays here.
if (!findWindow(windowHandle))
addOverlayWindow(windowHandle);
}
}
void QQnxScreen::windowClosed(void *window)
{
Q_ASSERT(thread() == QThread::currentThread());
const screen_window_t windowHandle = reinterpret_cast<screen_window_t>(window);
removeOverlayWindow(windowHandle);
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -91,10 +91,17 @@ public:
QSharedPointer<QQnxRootWindow> rootWindow() const { return m_rootWindow; } QSharedPointer<QQnxRootWindow> rootWindow() const { return m_rootWindow; }
public Q_SLOTS:
void newWindowCreated(void *window);
void windowClosed(void *window);
private Q_SLOTS: private Q_SLOTS:
void keyboardHeightChanged(int height); void keyboardHeightChanged(int height);
private: private:
void addOverlayWindow(screen_window_t window);
void removeOverlayWindow(screen_window_t window);
screen_context_t m_screenContext; screen_context_t m_screenContext;
screen_display_t m_display; screen_display_t m_display;
QSharedPointer<QQnxRootWindow> m_rootWindow; QSharedPointer<QQnxRootWindow> m_rootWindow;
@ -111,6 +118,7 @@ private:
QPlatformOpenGLContext *m_platformContext; QPlatformOpenGLContext *m_platformContext;
QList<QQnxWindow *> m_childWindows; QList<QQnxWindow *> m_childWindows;
QList<screen_window_t> m_overlays;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -106,6 +106,10 @@ bool QQnxScreenEventHandler::handleEvent(screen_event_t event, int qnxType)
handlePointerEvent(event); handlePointerEvent(event);
break; break;
case SCREEN_EVENT_CREATE:
handleCreateEvent(event);
break;
case SCREEN_EVENT_CLOSE: case SCREEN_EVENT_CLOSE:
handleCloseEvent(event); handleCloseEvent(event);
break; break;
@ -456,19 +460,28 @@ void QQnxScreenEventHandler::handleTouchEvent(screen_event_t event, int qnxType)
void QQnxScreenEventHandler::handleCloseEvent(screen_event_t event) void QQnxScreenEventHandler::handleCloseEvent(screen_event_t event)
{ {
// Query the window that was closed screen_window_t window = 0;
void *handle; if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0)
int result = screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, &handle); qFatal("QQnx: failed to query window property, errno=%d", errno);
if (result != 0) {
qFatal("QQNX: failed to query event window, errno=%d", errno); Q_EMIT windowClosed(window);
}
screen_window_t qnxWindow = static_cast<screen_window_t>(handle);
// Map window handle to top-level QWindow // Map window handle to top-level QWindow
QWindow *w = QQnxIntegration::window(qnxWindow); QWindow *w = QQnxIntegration::window(window);
if (w != 0) { if (w != 0) {
QWindowSystemInterface::handleCloseEvent(w); QWindowSystemInterface::handleCloseEvent(w);
} }
} }
void QQnxScreenEventHandler::handleCreateEvent(screen_event_t event)
{
screen_window_t window = 0;
if (screen_get_event_property_pv(event, SCREEN_PROPERTY_WINDOW, (void**)&window) != 0)
qFatal("QQnx: failed to query window property, errno=%d", errno);
Q_EMIT newWindowCreated(window);
}
#include "moc_qqnxscreeneventhandler.cpp"
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -48,8 +48,9 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QQnxScreenEventHandler class QQnxScreenEventHandler : public QObject
{ {
Q_OBJECT
public: public:
QQnxScreenEventHandler(); QQnxScreenEventHandler();
@ -58,11 +59,16 @@ public:
static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap); static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap);
Q_SIGNALS:
void newWindowCreated(void *window);
void windowClosed(void *window);
private: private:
void handleKeyboardEvent(screen_event_t event); void handleKeyboardEvent(screen_event_t event);
void handlePointerEvent(screen_event_t event); void handlePointerEvent(screen_event_t event);
void handleTouchEvent(screen_event_t event, int qnxType); void handleTouchEvent(screen_event_t event, int qnxType);
void handleCloseEvent(screen_event_t event); void handleCloseEvent(screen_event_t event);
void handleCreateEvent(screen_event_t event);
private: private:
enum { enum {