From d8103d0e629f1d8f6c2b9d5b0dcc95b6ff20b99d Mon Sep 17 00:00:00 2001 From: Bernd Weimer Date: Wed, 18 Jun 2014 11:23:05 +0200 Subject: QNX: Override QPlatformScreen::grabWindow The grabWindow API basically should return a screenshot at the window location. On QNX only the SCREEN_DISPLAY_MANAGER_CONTEXT can read from the screen which will require root privileges. At least this will fix some QWidget auto tests that rely on this API. Change-Id: I350233173d3aecd376f48af9f650606a5cce6205 Reviewed-by: Fabian Bumberger --- src/plugins/platforms/qnx/qqnxscreen.cpp | 99 +++++++++++++++++++++++++++++++- src/plugins/platforms/qnx/qqnxscreen.h | 4 +- 2 files changed, 101 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp index add45ecbe5..59dc84ebc8 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.cpp +++ b/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -209,6 +209,103 @@ QQnxScreen::~QQnxScreen() delete m_cursor; } +QPixmap QQnxScreen::grabWindow(WId window, int x, int y, int width, int height) const +{ + QQnxWindow *qnxWin = findWindow(reinterpret_cast(window)); + if (!qnxWin) { + qWarning("grabWindow: unknown window"); + return QPixmap(); + } + + QRect bound = qnxWin->geometry(); + + if (width < 0) + width = bound.width(); + if (height < 0) + height = bound.height(); + + bound &= QRect(x + bound.x(), y + bound.y(), width, height); + + if (bound.width() <= 0 || bound.height() <= 0) { + qWarning("grabWindow: size is null"); + return QPixmap(); + } + + // Create new context, only SCREEN_DISPLAY_MANAGER_CONTEXT can read from screen + screen_context_t context; + if (screen_create_context(&context, SCREEN_DISPLAY_MANAGER_CONTEXT)) { + if (errno == EPERM) + qWarning("grabWindow: root privileges required"); + else + qWarning("grabWindow: cannot create context"); + return QPixmap(); + } + + // Find corresponding display in SCREEN_DISPLAY_MANAGER_CONTEXT + int count = 0; + screen_display_t display = 0; + screen_get_context_property_iv(context, SCREEN_PROPERTY_DISPLAY_COUNT, &count); + if (count > 0) { + const size_t idLen = 30; + char matchId[idLen]; + char id[idLen]; + bool found = false; + + screen_display_t *displays = static_cast + (calloc(count, sizeof(screen_display_t))); + screen_get_context_property_pv(context, SCREEN_PROPERTY_DISPLAYS, (void **)displays); + screen_get_display_property_cv(m_display, SCREEN_PROPERTY_ID_STRING, idLen, matchId); + + while (count && !found) { + --count; + screen_get_display_property_cv(displays[count], SCREEN_PROPERTY_ID_STRING, idLen, id); + found = !strncmp(id, matchId, idLen); + } + + if (found) + display = displays[count]; + + free(displays); + } + + // Create screen and Qt pixmap + screen_pixmap_t pixmap; + QPixmap result; + if (display && !screen_create_pixmap(&pixmap, context)) { + screen_buffer_t buffer; + void *pointer; + int stride; + const int rect[4] = { bound.x(), bound.y(), bound.width(), bound.height() }; + + int val = SCREEN_USAGE_READ | SCREEN_USAGE_NATIVE; + screen_set_pixmap_property_iv(pixmap, SCREEN_PROPERTY_USAGE, &val); + val = SCREEN_FORMAT_RGBA8888; + screen_set_pixmap_property_iv(pixmap, SCREEN_PROPERTY_FORMAT, &val); + + int err = screen_set_pixmap_property_iv(pixmap, SCREEN_PROPERTY_BUFFER_SIZE, rect+2); + err = err || screen_create_pixmap_buffer(pixmap); + err = err || screen_get_pixmap_property_pv(pixmap, SCREEN_PROPERTY_RENDER_BUFFERS, + reinterpret_cast(&buffer)); + err = err || screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, &pointer); + err = err || screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride); + err = err || screen_read_display(display, buffer, 1, rect, 0); + + if (!err) { + const QImage img(static_cast(pointer), + bound.width(), bound.height(), stride, QImage::Format_ARGB32); + result = QPixmap::fromImage(img); + } else { + qWarning("grabWindow: capture error"); + } + screen_destroy_pixmap(pixmap); + } else { + qWarning("grabWindow: display/pixmap error "); + } + screen_destroy_context(context); + + return result; +} + static int defaultDepth() { qScreenDebug() << Q_FUNC_INFO; @@ -463,7 +560,7 @@ void QQnxScreen::resizeWindows(const QRect &previousScreenGeometry) } } -QQnxWindow *QQnxScreen::findWindow(screen_window_t windowHandle) +QQnxWindow *QQnxScreen::findWindow(screen_window_t windowHandle) const { Q_FOREACH (QQnxWindow *window, m_childWindows) { QQnxWindow * const result = window->findWindow(windowHandle); diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h index 6b2281f7b9..a8a18c6240 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.h +++ b/src/plugins/platforms/qnx/qqnxscreen.h @@ -62,6 +62,8 @@ public: QQnxScreen(screen_context_t context, screen_display_t display, bool primaryScreen); ~QQnxScreen(); + QPixmap grabWindow(WId window, int x, int y, int width, int height) const; + QRect geometry() const { return m_currentGeometry; } QRect availableGeometry() const; int depth() const; @@ -86,7 +88,7 @@ public: screen_context_t nativeContext() const { return m_screenContext; } const char *windowGroupName() const { return m_rootWindow ? m_rootWindow->groupName().constData() : 0; } - QQnxWindow *findWindow(screen_window_t windowHandle); + QQnxWindow *findWindow(screen_window_t windowHandle) const; /* Window hierarchy management */ void addWindow(QQnxWindow *child); -- cgit v1.2.3