Revert "Move QWindowSystemInterface out of qpa."
[profile/ivi/qtbase.git] / src / plugins / platforms / xcb / qxcbscreen.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qxcbscreen.h"
43 #include "qxcbwindow.h"
44 #include "qxcbcursor.h"
45 #include "qxcbimage.h"
46
47 #include <stdio.h>
48
49 #include <QDebug>
50
51 #include <xcb/randr.h>
52
53 #include <qpa/qwindowsysteminterface.h>
54
55 QT_BEGIN_NAMESPACE
56
57 QXcbScreen::QXcbScreen(QXcbConnection *connection, xcb_screen_t *screen, int number)
58     : QXcbObject(connection)
59     , m_screen(screen)
60     , m_number(number)
61     , m_refreshRate(60)
62 {
63     if (connection->hasXRandr())
64         xcb_randr_select_input(xcb_connection(), screen->root, true);
65
66     updateRefreshRate();
67
68 #ifdef Q_XCB_DEBUG
69     qDebug();
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);
77     qDebug();
78 #endif
79
80     const quint32 mask = XCB_CW_EVENT_MASK;
81     const quint32 values[] = {
82         // XCB_CW_EVENT_MASK
83         XCB_EVENT_MASK_ENTER_WINDOW
84         | XCB_EVENT_MASK_LEAVE_WINDOW
85         | XCB_EVENT_MASK_PROPERTY_CHANGE
86     };
87
88     xcb_change_window_attributes(xcb_connection(), screen->root, mask, values);
89
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);
95
96     if (reply && reply->format == 32 && reply->type == XCB_ATOM_WINDOW) {
97         xcb_window_t windowManager = *((xcb_window_t *)xcb_get_property_value(reply));
98
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));
107 #ifdef Q_XCB_DEBUG
108                 qDebug("Running window manager: %s", qPrintable(m_windowManagerName));
109 #endif
110             }
111
112             free(windowManagerReply);
113         }
114     }
115
116     free(reply);
117
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;
121     else
122         m_syncRequestSupported = m_windowManagerName != QLatin1String("KWin");
123
124     m_clientLeader = xcb_generate_id(xcb_connection());
125     Q_XCB_CALL2(xcb_create_window(xcb_connection(),
126                                   XCB_COPY_FROM_PARENT,
127                                   m_clientLeader,
128                                   m_screen->root,
129                                   0, 0, 1, 1,
130                                   0,
131                                   XCB_WINDOW_CLASS_INPUT_OUTPUT,
132                                   m_screen->root_visual,
133                                   0, 0), connection);
134
135     Q_XCB_CALL2(xcb_change_property(xcb_connection(),
136                                     XCB_PROP_MODE_REPLACE,
137                                     m_clientLeader,
138                                     atom(QXcbAtom::WM_CLIENT_LEADER),
139                                     XCB_ATOM_WINDOW,
140                                     32,
141                                     1,
142                                     &m_clientLeader), connection);
143
144     xcb_depth_iterator_t depth_iterator =
145         xcb_screen_allowed_depths_iterator(screen);
146
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);
151
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);
156         }
157
158         xcb_depth_next(&depth_iterator);
159     }
160
161     m_cursor = new QXcbCursor(connection, this);
162 }
163
164 QXcbScreen::~QXcbScreen()
165 {
166     delete m_cursor;
167 }
168
169
170 QWindow *QXcbScreen::topLevelAt(const QPoint &p) const
171 {
172     xcb_window_t root = m_screen->root;
173
174     int x = p.x();
175     int y = p.y();
176
177     xcb_window_t parent = root;
178     xcb_window_t child = root;
179
180     do {
181         xcb_translate_coordinates_cookie_t translate_cookie =
182             xcb_translate_coordinates_unchecked(xcb_connection(), parent, child, x, y);
183
184         xcb_translate_coordinates_reply_t *translate_reply =
185             xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, NULL);
186
187         if (!translate_reply) {
188             return 0;
189         }
190
191         parent = child;
192         child = translate_reply->child;
193         x = translate_reply->dst_x;
194         y = translate_reply->dst_y;
195
196         free(translate_reply);
197
198         if (!child || child == root)
199             return 0;
200
201         QPlatformWindow *platformWindow = connection()->platformWindowFromId(child);
202         if (platformWindow)
203             return platformWindow->window();
204     } while (parent != child);
205
206     return 0;
207 }
208
209 const xcb_visualtype_t *QXcbScreen::visualForId(xcb_visualid_t visualid) const
210 {
211     QMap<xcb_visualid_t, xcb_visualtype_t>::const_iterator it = m_visuals.find(visualid);
212     if (it == m_visuals.constEnd())
213         return 0;
214     return &*it;
215 }
216
217 QRect QXcbScreen::geometry() const
218 {
219     return QRect(0, 0, m_screen->width_in_pixels, m_screen->height_in_pixels);
220 }
221
222 int QXcbScreen::depth() const
223 {
224     return m_screen->root_depth;
225 }
226
227 QImage::Format QXcbScreen::format() const
228 {
229     return QImage::Format_RGB32;
230 }
231
232 QSizeF QXcbScreen::physicalSize() const
233 {
234     return QSizeF(m_screen->width_in_millimeters, m_screen->height_in_millimeters);
235 }
236
237 QPlatformCursor *QXcbScreen::cursor() const
238 {
239     return m_cursor;
240 }
241
242 qreal QXcbScreen::refreshRate() const
243 {
244     return m_refreshRate;
245 }
246
247 void QXcbScreen::updateRefreshRate()
248 {
249     if (!connection()->hasXRandr())
250         return;
251
252     int rate = m_refreshRate;
253
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);
256
257     if (screenInfoReply) {
258         rate = screenInfoReply->rate;
259         free(screenInfoReply);
260     }
261
262     if (rate == m_refreshRate)
263         return;
264
265     m_refreshRate = rate;
266
267     QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), rate);
268 }
269
270 int QXcbScreen::screenNumber() const
271 {
272     return m_number;
273 }
274
275 QPixmap QXcbScreen::grabWindow(WId window, int x, int y, int width, int height) const
276 {
277     if (width == 0 || height == 0)
278         return QPixmap();
279
280     xcb_get_geometry_cookie_t geometry_cookie = xcb_get_geometry_unchecked(xcb_connection(), window);
281
282     xcb_get_geometry_reply_t *reply =
283         xcb_get_geometry_reply(xcb_connection(), geometry_cookie, NULL);
284
285     if (!reply) {
286         return QPixmap();
287     }
288
289     if (width < 0)
290         width = reply->width - x;
291     if (height < 0)
292         height = reply->height - y;
293
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);
300
301     if (!root_reply) {
302         free(reply);
303         return QPixmap();
304     }
305
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)
310
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);
314
315         xcb_translate_coordinates_reply_t *translate_reply =
316             xcb_translate_coordinates_reply(xcb_connection(), translate_cookie, NULL);
317
318         if (!translate_reply) {
319             free(reply);
320             free(root_reply);
321             return QPixmap();
322         }
323
324         x = translate_reply->dst_x;
325         y = translate_reply->dst_y;
326
327         window = root;
328
329         free(translate_reply);
330         free(reply);
331         reply = root_reply;
332     } else {
333         free(root_reply);
334         root_reply = 0;
335     }
336
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);
339
340     if (!attributes_reply) {
341         free(reply);
342         return QPixmap();
343     }
344
345     const xcb_visualtype_t *visual = screen->visualForId(attributes_reply->visual);
346     free(attributes_reply);
347
348     xcb_pixmap_t pixmap = xcb_generate_id(xcb_connection());
349     xcb_create_pixmap(xcb_connection(), reply->depth, pixmap, window, width, height);
350
351     uint32_t gc_value_mask = XCB_GC_SUBWINDOW_MODE;
352     uint32_t gc_value_list[] = { XCB_SUBWINDOW_MODE_INCLUDE_INFERIORS };
353
354     xcb_gcontext_t gc = xcb_generate_id(xcb_connection());
355     xcb_create_gc(xcb_connection(), gc, pixmap, gc_value_mask, gc_value_list);
356
357     xcb_copy_area(xcb_connection(), window, pixmap, gc, x, y, 0, 0, width, height);
358
359     QPixmap result = qt_xcb_pixmapFromXPixmap(connection(), pixmap, width, height, reply->depth, visual);
360
361     free(reply);
362     xcb_free_gc(xcb_connection(), gc);
363     xcb_free_pixmap(xcb_connection(), pixmap);
364
365     return result;
366 }
367
368 QString QXcbScreen::name() const
369 {
370     QByteArray displayName = connection()->displayName();
371     int dotPos = displayName.lastIndexOf('.');
372     if (dotPos != -1)
373         displayName.truncate(dotPos);
374     return displayName + QLatin1Char('.') + QString::number(screenNumber());
375 }
376
377 QT_END_NAMESPACE