Rabbit Remote Control 0.0.30
Loading...
Searching...
No Matches
DisplayXLib.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include <QLoggingCategory>
4#include "DisplayXLib.h"
5
6#ifdef HAVE_Xfixes
7#include <X11/extensions/Xfixes.h>
8#endif
9
10// xlib documents: https://www.x.org/releases/current/doc/libX11/libX11/libX11.html
11// X documents: https://www.x.org/releases/current/doc/index.html
12// X Window System Concepts: https://www.x.org/wiki/guide/concepts/
13// https://www.x.org
14
15#include <QPainter>
16#include <QBitmap>
17
18Q_DECLARE_LOGGING_CATEGORY(LogScreen)
19
20CDisplayXLib::CDisplayXLib() : CDisplay(),
21 m_pDisplay(NULL),
22 m_RootWindow(0),
23 m_Format(QImage::Format_Invalid),
24 m_pImage(NULL)
25{
26 Open();
27}
28
29CDisplayXLib::~CDisplayXLib()
30{
31 Close();
32}
33
34CDisplay* CDisplay::Instance()
35{
36 static CDisplay* p = nullptr;
37 if(!p) p = new CDisplayXLib();
38 return p;
39}
40
41int CDisplayXLib::Width()
42{
43 if(m_pDisplay)
44 return DisplayWidth(m_pDisplay, DefaultScreen(m_pDisplay));
45 return 0;
46}
47
48int CDisplayXLib::Height()
49{
50 if(m_pDisplay)
51 return DisplayHeight(m_pDisplay, DefaultScreen(m_pDisplay));
52 return 0;
53}
54
55QImage::Format CDisplayXLib::GetFormat()
56{
57 return m_Format;
58}
59
60QImage::Format CDisplayXLib::GetFormat(XImage* pImage)
61{
62 switch(pImage->bits_per_pixel)
63 {
64 case 32:
65 return QImage::Format_ARGB32;
66 case 24:
67 return QImage::Format_RGB888;
68 default:
69 qCritical(LogScreen) << "Don't support format:" << pImage->bits_per_pixel;
70 return QImage::Format_Invalid;
71 }
72}
73
74int CDisplayXLib::Open()
75{
76 int nRet = 0;
77 /* Connect to a local display.
78 * it defaults to the value of the DISPLAY environment variable. */
79 m_pDisplay = XOpenDisplay(NULL);
80 do{
81 if(!m_pDisplay)
82 {
83 nRet = -1;
84 }
85
86 if (strstr(ServerVendor(m_pDisplay), "X.Org")) {
87 int vendrel = VendorRelease(m_pDisplay);
88
89 QString version("X.Org version: ");
90 version += QString::number(vendrel / 10000000);
91 version += "." + QString::number((vendrel / 100000) % 100),
92 version += "." + QString::number((vendrel / 1000) % 100);
93 if (vendrel % 1000) {
94 version += "." + QString::number(vendrel % 1000);
95 }
96 qInfo(LogScreen) << version;
97 }
98
99 m_RootWindow = DefaultRootWindow(m_pDisplay); // RootWindow(dsp,0);/* Refer to the root window */
100 if(0 == m_RootWindow)
101 {
102 qCritical(LogScreen) << "cannot get root window";
103 nRet = -2;
104 break;
105 }
106 }while(0);
107
108 if(nRet)
109 {
110 Close();
111 return nRet;
112 }
113
114 // Initial QImage and XImage
115 Visual* vis = DefaultVisual(m_pDisplay, DefaultScreen(m_pDisplay));
116 if (vis && vis->c_class == TrueColor) {
117 m_pImage = XCreateImage(m_pDisplay, vis,
118 DefaultDepth(m_pDisplay, DefaultScreen(m_pDisplay)),
119 ZPixmap, 0, 0, Width(), Height(),
120 BitmapPad(m_pDisplay), 0);
121 if(m_pImage) {
122 m_pImage->data = (char *)malloc(m_pImage->bytes_per_line * m_pImage->height);
123 if (m_pImage->data) {
124 m_Format = GetFormat(m_pImage);
125 if(QImage::Format_Invalid != GetFormat()) {
126 m_Desktop = QImage((uchar*)m_pImage->data,
127 Width(), Height(), GetFormat());
128 //m_Desktop.fill(QColor(0,0,0,0));
129 }
130 }
131
132 if(!m_pImage->data || QImage::Format_Invalid == GetFormat()) {
133 DestroyImage(m_pImage);
134 m_pImage = NULL;
135 }
136 }
137 }
138
139 return nRet;
140}
141
142int CDisplayXLib::Close()
143{
144 int nRet = 0;
145 if(m_pDisplay)
146 {
147 XCloseDisplay(m_pDisplay);
148 m_pDisplay = NULL;
149 }
150
151 m_RootWindow = 0;
152
153 if(m_pImage)
154 {
155 DestroyImage(m_pImage);
156 m_pImage = NULL;
157 }
158
159 return nRet;
160}
161
162int CDisplayXLib::GetScreenCount()
163{
164 return ScreenCount(m_pDisplay);
165}
166
167void CDisplayXLib::DestroyImage(void *pImage)
168{
169 qDebug(LogScreen) << "void DestroyImage(void *info)";
170 XDestroyImage(static_cast<XImage*>(pImage));
171}
172
173QImage CDisplayXLib::GetDisplay(int x, int y, int width, int height)
174{
175 if(!m_pDisplay || 0 == m_RootWindow)
176 return QImage();
177
178 if(0 > width)
179 width = Width();
180 if(0 > height)
181 height = Height();
182 XImage *pImage = XGetImage(m_pDisplay, m_RootWindow, x, y, width, height,
183 AllPlanes, ZPixmap);
184 if(QImage::Format_Invalid == GetFormat())
185 m_Format = GetFormat(pImage);
186 if(QImage::Format_Invalid != GetFormat())
187 {
188 QImage img((uchar*)pImage->data,
189 pImage->width, pImage->height,
190 GetFormat(),
191 DestroyImage, pImage);
192
193 if(GetHasCursor())
194 {
195 QPoint pos, posHot;
196 QImage cursor = GetCursor(pos, posHot);
197 if(!cursor.isNull()
198 && pos.x() >= x && (pos.x() + cursor.width()) <= width
199 && pos.y() >= y && (pos.y() + cursor.height()) <= height)
200 {
201 QPainter painter(&img);
202 painter.drawImage(pos, cursor);
203 }
204 }
205
206 return img;
207 }
208 else
209 DestroyImage(pImage);
210
211 return QImage();
212}
213
214QImage CDisplayXLib::GetDisplay()
215{
216 if(QImage::Format_Invalid != GetFormat()
217 && m_pDisplay && m_RootWindow && m_pImage)
218 {
219 XImage* pImg = XGetSubImage(m_pDisplay, m_RootWindow,
220 0, 0, Width(), Height(),
221 AllPlanes, ZPixmap,
222 m_pImage, 0, 0);
223 if(NULL == pImg)
224 {
225 qCritical(LogScreen) << "Get desktop fail";
226 }
227 }
228
229 if(GetHasCursor())
230 {
231 QPoint pos, posHot;
232 QImage cursor = GetCursor(pos, posHot);
233 if(!cursor.isNull())
234 {
235 if(m_Desktop.format() != cursor.format())
236 cursor = cursor.convertToFormat(m_Desktop.format());
237 QPainter painter(&m_Desktop);
238 painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
239 painter.drawImage(pos, cursor);
240 }
241 }
242 return m_Desktop;
243}
244
245QImage CDisplayXLib::GetCursor(QPoint &pos, QPoint &posHot)
246{
247#ifdef HAVE_Xfixes
248
249 XFixesCursorImage* ci;
250 XLockDisplay(m_pDisplay);
251 ci = XFixesGetCursorImage(m_pDisplay);
252 XUnlockDisplay(m_pDisplay);
253 if (!ci)
254 return QImage();
255
256 pos = QPoint(ci->x, ci->y);
257 posHot = QPoint(ci->xhot, ci->yhot);
258 QImage img(ci->width, ci->height, QImage::Format_ARGB32);
259
260 unsigned char r = 0, g = 0, b = 0, a = 0;
261 unsigned short row = 0, col = 0, k = 0;
262
263 for(row = 0; row < ci->height; row++)
264 {
265 for(col = 0; col < ci->width; col++, k++)
266 {
267 a = (unsigned char)((ci->pixels[k] >> 24) & 0xff);
268 r = (unsigned char)((ci->pixels[k] >> 16) & 0xff);
269 g = (unsigned char)((ci->pixels[k] >> 8) & 0xff);
270 b = (unsigned char)((ci->pixels[k] >> 0) & 0xff);
271
272 QColor c(r, g, b, a);
273 img.setPixelColor(col, row, c);
274 }
275 }
276
277 XFree(ci);
278
279 return img;
280#else
281 pos = GetCursorPosition();
282#endif
283 return QImage();
284}
285
286QPoint CDisplayXLib::GetCursorPosition()
287{
288 unsigned int mask;
289 int win_x = 0, win_y = 0;
290 int root_x = 0, root_y = 0;
291 Window root, child;
292 XLockDisplay(m_pDisplay);
293
294 if (!XQueryPointer(m_pDisplay, m_RootWindow, &root, &child, &root_x,
295 &root_y, &win_x, &win_y, &mask))
296 {
297 XUnlockDisplay(m_pDisplay);
298 return QPoint();
299 }
300
301 XUnlockDisplay(m_pDisplay);
302 return QPoint(root_x, root_y);
303}