1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qxcbscreen.h"
43 #include "qxcbwindow.h"
44 #include "qxcbcursor.h"
45 #include "qxcbimage.h"
51 #include <xcb/randr.h>
53 #include <qpa/qwindowsysteminterface.h>
57 QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int number)
58 : QXcbObject(connection)
63 if (connection->hasXRandr())
64 xcb_randr_select_input(xcb_connection(), screen->root, true);
70 qDebug("Information of screen %d:", screen->root);
71 qDebug(" width.........: %d", screen->width_in_pixels);
72 qDebug(" height........: %d", screen->height_in_pixels);
73 qDebug(" depth.........: %d", screen->root_depth);
74 qDebug(" white pixel...: %x", screen->white_pixel);
75 qDebug(" black pixel...: %x", screen->black_pixel);
76 qDebug(" refresh rate...: %d", m_refreshRate);
80 const quint32 mask = XCB_CW_EVENT_MASK;
81 const quint32 values[] = {
83 XCB_EVENT_MASK_ENTER_WINDOW
84 | XCB_EVENT_MASK_LEAVE_WINDOW
85 | XCB_EVENT_MASK_PROPERTY_CHANGE
88 xcb_change_window_attributes(xcb_connection(), screen->root, mask, values);
90 xcb_get_property_reply_t *reply =
91 xcb_get_property_reply(xcb_connection(),
92 xcb_get_property_unchecked(xcb_connection(), false, screen->root,
93 atom(QXcbAtom::_NET_SUPPORTING_WM_CHECK),
94 XCB_ATOM_WINDOW, 0, 1024), NULL);
96 if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) {
97 xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply));
99 if (windowManager != XCB_WINDOW_NONE) {
100 xcb_get_property_reply_t *windowManagerReply =
101 xcb_get_property_reply(xcb_connection(),
102 xcb_get_property_unchecked(xcb_connection(), false, windowManager,
103 atom(QXcbAtom::_NET_WM_NAME),
104 atom(QXcbAtom::UTF8_STRING), 0, 1024), NULL);
105 if (windowManagerReply && windowManagerReply->format == 8 && windowManagerReply->type == atom(QXcbAtom::UTF8_STRING)) {
106 m_windowManagerName = QString::fromUtf8((const char *)xcb_get_property_value(windowManagerReply), xcb_get_property_value_length(windowManagerReply));
108 qDebug("Running window manager: %s", qPrintable(m_windowManagerName));
112 free(windowManagerReply);
118 const xcb_query_extension_reply_t *sync_reply = xcb_get_extension_data(xcb_connection(), &xcb_sync_id);
119 if (!sync_reply || !sync_reply->present)
120 m_syncRequestSupported = false;
122 m_syncRequestSupported = m_windowManagerName != QLatin1String("KWin");
124 m_clientLeader = xcb_generate_id(xcb_connection());
125 Q_XCB_CALL2(xcb_create_window(xcb_connection(),
126 XCB_COPY_FROM_PARENT,
131 XCB_WINDOW_CLASS_INPUT_OUTPUT,
132 m_screen->root_visual,
135 Q_XCB_CALL2(xcb_change_property(xcb_connection(),
136 XCB_PROP_MODE_REPLACE,
138 atom(QXcbAtom::WM_CLIENT_LEADER),
142 &m_clientLeader), connection);
144 xcb_depth_iterator_t depth_iterator =
145 xcb_screen_allowed_depths_iterator(screen);
147 while (depth_iterator.rem) {
148 xcb_depth_t *depth = depth_iterator.data;
149 xcb_visualtype_iterator_t visualtype_iterator =
150 xcb_depth_visuals_iterator(depth);
152 while (visualtype_iterator.rem) {
153 xcb_visualtype_t *visualtype = visualtype_iterator.data;
154 m_visuals.insert(visualtype->visual_id, *visualtype);
155 xcb_visualtype_next(&visualtype_iterator);
158 xcb_depth_next(&depth_iterator);
161 m_cursor = new QXcbCursor(connection, this);
164 QXcbScreen::~QXcbScreen()
170 QWindow *QXcbScreen::topLevelAt(const QPoint &p) const
172 xcb_window_t root = m_screen->root;
177 xcb_window_t parent = root;
178 xcb_window_t child = root;
181 xcb_translate_coordinates_cookie_t translate_cookie =
182 xcb_translate_coordinates_unchecked(xcb_connection(), parent, child, x, y);
184 xcb_translate_coordinates_reply_t *translate_reply =
185 xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, NULL);
187 if (!translate_reply) {
192 child = translate_reply->child;
193 x = translate_reply->dst_x;
194 y = translate_reply->dst_y;
196 free(translate_reply);
198 if (!child || child == root)
201 QPlatformWindow *platformWindow = connection()->platformWindowFromId(child);
203 return platformWindow->window();
204 } while (parent != child);
209 const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const
211 QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid);
212 if (it == m_visuals.constEnd())
217 QRect QXcbScreen::geometry() const
219 return QRect(0, 0, m_screen->width_in_pixels, m_screen->height_in_pixels);
222 int QXcbScreen::depth() const
224 return m_screen->root_depth;
227 QImage::Format QXcbScreen::format() const
229 return QImage::Format_RGB32;
232 QSizeF QXcbScreen::physicalSize() const
234 return QSizeF(m_screen->width_in_millimeters, m_screen->height_in_millimeters);
237 QPlatformCursor *QXcbScreen::cursor() const
242 qreal QXcbScreen::refreshRate() const
244 return m_refreshRate;
247 void QXcbScreen::updateRefreshRate()
249 if (!connection()->hasXRandr())
252 int rate = m_refreshRate;
254 xcb_randr_get_screen_info_reply_t *screenInfoReply =
255 xcb_randr_get_screen_info_reply(xcb_connection(), xcb_randr_get_screen_info_unchecked(xcb_connection(), m_screen->root), 0);
257 if (screenInfoReply) {
258 rate = screenInfoReply->rate;
259 free(screenInfoReply);
262 if (rate == m_refreshRate)
265 m_refreshRate = rate;
267 QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), rate);
270 int QXcbScreen::screenNumber() const
275 QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) const
277 if (width == 0 || height == 0)
280 xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry_unchecked(xcb_connection(), window);
282 xcb_get_geometry_reply_t *reply =
283 xcb_get_geometry_reply(xcb_connection(), geometry_cookie, NULL);
290 width = reply->width - x;
292 height = reply->height - y;
294 // TODO: handle multiple screens
295 QXcbScreen *screen = const_cast<QXcbScreen *>(this);
296 xcb_window_t root = screen->root();
297 geometry_cookie = xcb_get_geometry_unchecked(xcb_connection(), root);
298 xcb_get_geometry_reply_t *root_reply =
299 xcb_get_geometry_reply(xcb_connection(), geometry_cookie, NULL);
306 if (reply->depth == root_reply->depth) {
307 // if the depth of the specified window and the root window are the
308 // same, grab pixels from the root window (so that we get the any
309 // overlapping windows and window manager frames)
311 // map x and y to the root window
312 xcb_translate_coordinates_cookie_t translate_cookie =
313 xcb_translate_coordinates_unchecked(xcb_connection(), window, root, x, y);
315 xcb_translate_coordinates_reply_t *translate_reply =
316 xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, NULL);
318 if (!translate_reply) {
324 x = translate_reply->dst_x;
325 y = translate_reply->dst_y;
329 free(translate_reply);
337 xcb_get_window_attributes_reply_t *attributes_reply =
338 xcb_get_window_attributes_reply(xcb_connection(), xcb_get_window_attributes_unchecked(xcb_connection(), window), NULL);
340 if (!attributes_reply) {
345 const xcb_visualtype_t *visual = screen->visualForId(attributes_reply->visual);
346 free(attributes_reply);
348 xcb_pixmap_t pixmap = xcb_generate_id(xcb_connection());
349 xcb_create_pixmap(xcb_connection(), reply->depth, pixmap, window, width, height);
351 uint32_t gc_value_mask = XCB_GC_SUBWINDOW_MODE;
352 uint32_t gc_value_list[] = { XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS };
354 xcb_gcontext_t gc = xcb_generate_id(xcb_connection());
355 xcb_create_gc(xcb_connection(), gc, pixmap, gc_value_mask, gc_value_list);
357 xcb_copy_area(xcb_connection(), window, pixmap, gc, x, y, 0, 0, width, height);
359 QPixmap result = qt_xcb_pixmapFromXPixmap(connection(), pixmap, width, height, reply->depth, visual);
362 xcb_free_gc(xcb_connection(), gc);
363 xcb_free_pixmap(xcb_connection(), pixmap);
368 QString QXcbScreen::name() const
370 QByteArray displayName = connection()->displayName();
371 int dotPos = displayName.lastIndexOf('.');
373 displayName.truncate(dotPos);
374 return displayName + QLatin1Char('.') + QString::number(screenNumber());