1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qscreenmulti_qws_p.h"
43
44 #ifndef QT_NO_QWS_MULTISCREEN
45
46 #include <qlist.h>
47 #include <qstringlist.h>
48 #include <qwidget.h>
49 #include <qdebug.h>
50
51 QT_BEGIN_NAMESPACE
52
53 #ifndef QT_NO_QWS_CURSOR
54
55 class QMultiScreenCursor : public QScreenCursor
56 {
57 public:
QMultiScreenCursor()58 QMultiScreenCursor() : currentCursor(qt_screencursor) { enable = false; }
~QMultiScreenCursor()59 ~QMultiScreenCursor() { qt_screencursor = 0; }
60
61 void set(const QImage &image, int hotx, int hoty);
62 void move(int x, int y);
63 void show();
64 void hide();
65
66 void addCursor(QScreenCursor *cursor);
67
68 private:
69 void setCurrentCursor(QScreenCursor *newCursor);
70
71 QScreenCursor *currentCursor;
72 QList<QScreenCursor*> cursors;
73 };
74
set(const QImage & image,int hotx,int hoty)75 void QMultiScreenCursor::set(const QImage &image, int hotx, int hoty)
76 {
77 QScreenCursor::set(image, hotx, hoty);
78 if (currentCursor)
79 currentCursor->set(image, hotx, hoty);
80 }
81
setCurrentCursor(QScreenCursor * newCursor)82 void QMultiScreenCursor::setCurrentCursor(QScreenCursor *newCursor)
83 {
84 *((QScreenCursor*)this) = *newCursor;
85 currentCursor = newCursor;
86 }
87
88 // XXX: this is a mess!
move(int x,int y)89 void QMultiScreenCursor::move(int x, int y)
90 {
91 const int oldIndex = qt_screen->subScreenIndexAt(pos);
92 QScreenCursor::move(x, y); // updates pos
93 const int newIndex = qt_screen->subScreenIndexAt(pos);
94
95 if (!currentCursor && oldIndex != -1)
96 setCurrentCursor(cursors.at(oldIndex));
97 QScreenCursor *oldCursor = currentCursor;
98
99 if (oldIndex != -1) {
100 const QScreen *oldScreen = qt_screen->subScreens().at(oldIndex);
101 if (newIndex == -1 || oldScreen->region().contains(pos)) {
102 oldCursor->move(x, y);
103 return;
104 }
105 }
106
107 if (newIndex != -1) {
108 QScreenCursor *newCursor = cursors.at(newIndex);
109 newCursor->set(cursor, hotspot.x(), hotspot.y());
110
111 if (oldCursor) {
112 if (oldCursor->isVisible())
113 newCursor->show();
114 oldCursor->hide();
115 }
116
117 newCursor->move(x, y);
118
119 setCurrentCursor(newCursor);
120 }
121 }
122
show()123 void QMultiScreenCursor::show()
124 {
125 if (currentCursor)
126 currentCursor->show();
127 }
128
hide()129 void QMultiScreenCursor::hide()
130 {
131 if (currentCursor)
132 currentCursor->hide();
133 }
134
addCursor(QScreenCursor * cursor)135 void QMultiScreenCursor::addCursor(QScreenCursor *cursor)
136 {
137 cursors.append(cursor);
138 }
139
140 #endif
141
142 class QMultiScreenPrivate
143 {
144 public:
QMultiScreenPrivate()145 QMultiScreenPrivate()
146 #ifndef QT_NO_QWS_CURSOR
147 : cursor(0)
148 #endif
149 {}
~QMultiScreenPrivate()150 ~QMultiScreenPrivate()
151 {
152 #ifndef QT_NO_QWS_CURSOR
153 delete cursor;
154 #endif
155 }
156
157 QList<QScreen*> screens;
158 QRegion region;
159 #ifndef QT_NO_QWS_CURSOR
160 QMultiScreenCursor *cursor;
161 #endif
162 };
163
QMultiScreen(int displayId)164 QMultiScreen::QMultiScreen(int displayId)
165 : QScreen(displayId, MultiClass), d_ptr(new QMultiScreenPrivate)
166 {
167 }
168
~QMultiScreen()169 QMultiScreen::~QMultiScreen()
170 {
171 delete d_ptr;
172 }
173
initDevice()174 bool QMultiScreen::initDevice()
175 {
176 bool ok = true;
177
178 #ifndef QT_NO_QWS_CURSOR
179 d_ptr->cursor = new QMultiScreenCursor;
180 #endif
181
182 const int n = d_ptr->screens.count();
183 for (int i = 0; i < n; ++i) {
184 QScreen *s = d_ptr->screens.at(i);
185 ok = s->initDevice() && ok;
186 #ifndef QT_NO_QWS_CURSOR
187 d_ptr->cursor->addCursor(qt_screencursor); // XXX
188 #endif
189 }
190
191 #ifndef QT_NO_QWS_CURSOR
192 // XXX
193 qt_screencursor = d_ptr->cursor;
194 #endif
195
196 return ok;
197 }
198
getDisplayId(const QString & spec)199 static int getDisplayId(const QString &spec)
200 {
201 QRegExp regexp(QLatin1String(":(\\d+)\\b"));
202 if (regexp.lastIndexIn(spec) != -1) {
203 const QString capture = regexp.cap(1);
204 return capture.toInt();
205 }
206 return 0;
207 }
208
filterDisplayOffset(QString & spec)209 static QPoint filterDisplayOffset(QString &spec)
210 {
211 QRegExp regexp(QLatin1String(":offset=(\\d+),(\\d+)\\b"));
212 if (regexp.indexIn(spec) == -1)
213 return QPoint();
214
215 const int x = regexp.cap(1).toInt();
216 const int y = regexp.cap(2).toInt();
217 spec.remove(regexp.pos(0), regexp.matchedLength());
218 return QPoint(x, y);
219 }
220
connect(const QString & displaySpec)221 bool QMultiScreen::connect(const QString &displaySpec)
222 {
223 QString dSpec = displaySpec;
224 if (dSpec.startsWith(QLatin1String("Multi:"), Qt::CaseInsensitive))
225 dSpec = dSpec.mid(QString::fromLatin1("Multi:").size());
226
227 const QString displayIdSpec = QString::fromLatin1(" :%1").arg(displayId);
228 if (dSpec.endsWith(displayIdSpec))
229 dSpec = dSpec.left(dSpec.size() - displayIdSpec.size());
230
231 QStringList specs = dSpec.split(QLatin1Char(' '), QString::SkipEmptyParts);
232 foreach (QString spec, specs) {
233 const int id = getDisplayId(spec);
234 if (spec.startsWith("vnc:", Qt::CaseInsensitive)) {
235 spec.append(":noDisablePainting");
236 }
237 const QPoint offset = filterDisplayOffset(spec);
238 QScreen *s = qt_get_screen(id, spec.toLatin1().constData());
239 s->setOffset(offset);
240 addSubScreen(s);
241 }
242
243 QScreen *firstScreen = d_ptr->screens.at(0);
244 Q_ASSERT(firstScreen);
245
246 // XXX
247 QScreen::d = firstScreen->depth();
248
249 QScreen::lstep = 0;
250 QScreen::data = 0;
251 QScreen::size = 0;
252
253 QScreen::w = d_ptr->region.boundingRect().width();
254 QScreen::h = d_ptr->region.boundingRect().height();
255
256 QScreen::dw = QScreen::w;
257 QScreen::dh = QScreen::h;
258
259 // XXX - Extend the physical size based on the first screen
260 // to encompass all screens, so that code that uses the multi
261 // screen to calculate dpi values will get the right numbers.
262 QScreen::physWidth = firstScreen->physicalWidth() * w / firstScreen->width();
263 QScreen::physHeight = firstScreen->physicalHeight() * h / firstScreen->height();
264
265 // XXXXX
266 qt_screen = this;
267
268 return true;
269 }
270
disconnect()271 void QMultiScreen::disconnect()
272 {
273 const int n = d_ptr->screens.size();
274 for (int i = 0; i < n; ++i)
275 d_ptr->screens.at(i)->disconnect();
276 }
277
shutdownDevice()278 void QMultiScreen::shutdownDevice()
279 {
280 const int n = d_ptr->screens.size();
281 for (int i = 0; i < n; ++i)
282 d_ptr->screens.at(i)->shutdownDevice();
283 }
284
setMode(int,int,int)285 void QMultiScreen::setMode(int, int, int)
286 {
287 return;
288 }
289
supportsDepth(int) const290 bool QMultiScreen::supportsDepth(int) const
291 {
292 return false;
293 }
294
save()295 void QMultiScreen::save()
296 {
297 const int n = d_ptr->screens.size();
298 for (int i = 0; i < n; ++i)
299 d_ptr->screens.at(i)->save();
300 }
301
restore()302 void QMultiScreen::restore()
303 {
304 const int n = d_ptr->screens.size();
305 for (int i = 0; i < n; ++i)
306 d_ptr->screens.at(i)->restore();
307 }
308
blank(bool on)309 void QMultiScreen::blank(bool on)
310 {
311 const int n = d_ptr->screens.size();
312 for (int i = 0; i < n; ++i)
313 d_ptr->screens.at(i)->blank(on);
314 }
315
onCard(const unsigned char * ptr) const316 bool QMultiScreen::onCard(const unsigned char *ptr) const
317 {
318 const int n = d_ptr->screens.size();
319 for (int i = 0; i < n; ++i)
320 if (d_ptr->screens.at(i)->onCard(ptr))
321 return true;
322 return false;
323 }
324
onCard(const unsigned char * ptr,ulong & offset) const325 bool QMultiScreen::onCard(const unsigned char *ptr, ulong &offset) const
326 {
327 const int n = d_ptr->screens.size();
328 for (int i = 0; i < n; ++i)
329 if (d_ptr->screens.at(i)->onCard(ptr, offset))
330 return true;
331 return false;
332 }
333
isInterlaced() const334 bool QMultiScreen::isInterlaced() const
335 {
336 const int n = d_ptr->screens.size();
337 for (int i = 0; i < n; ++i)
338 if (d_ptr->screens.at(i)->isInterlaced())
339 return true;
340
341 return false;
342 }
343
memoryNeeded(const QString & string)344 int QMultiScreen::memoryNeeded(const QString &string)
345 {
346 int total = 0;
347 const int n = d_ptr->screens.size();
348 for (int i = 0; i < n; ++i)
349 total += d_ptr->screens.at(i)->memoryNeeded(string);
350 return total;
351 }
352
sharedRamSize(void * arg)353 int QMultiScreen::sharedRamSize(void *arg)
354 {
355 int total = 0;
356 const int n = d_ptr->screens.size();
357 for (int i = 0; i < n; ++i)
358 total += d_ptr->screens.at(i)->sharedRamSize(arg);
359 return total;
360 }
361
haltUpdates()362 void QMultiScreen::haltUpdates()
363 {
364 const int n = d_ptr->screens.size();
365 for (int i = 0; i < n; ++i)
366 d_ptr->screens.at(i)->haltUpdates();
367 }
368
resumeUpdates()369 void QMultiScreen::resumeUpdates()
370 {
371 const int n = d_ptr->screens.size();
372 for (int i = 0; i < n; ++i)
373 d_ptr->screens.at(i)->resumeUpdates();
374 }
375
exposeRegion(QRegion region,int changing)376 void QMultiScreen::exposeRegion(QRegion region, int changing)
377 {
378 const int n = d_ptr->screens.size();
379 for (int i = 0; i < n; ++i) {
380 QScreen *screen = d_ptr->screens.at(i);
381 const QRegion r = region & screen->region();
382 if (r.isEmpty())
383 continue;
384 screen->exposeRegion(r, changing);
385 }
386 }
387
solidFill(const QColor & color,const QRegion & region)388 void QMultiScreen::solidFill(const QColor &color, const QRegion ®ion)
389 {
390 const int n = d_ptr->screens.size();
391 for (int i = 0; i < n; ++i) {
392 QScreen *screen = d_ptr->screens.at(i);
393 const QRegion r = region & screen->region();
394 if (r.isEmpty())
395 continue;
396 screen->solidFill(color, r);
397 }
398 }
399
blit(const QImage & img,const QPoint & topLeft,const QRegion & region)400 void QMultiScreen::blit(const QImage &img, const QPoint &topLeft,
401 const QRegion ®ion)
402 {
403 const int n = d_ptr->screens.size();
404 for (int i = 0; i < n; ++i) {
405 QScreen *screen = d_ptr->screens.at(i);
406 const QRegion r = region & screen->region();
407 if (r.isEmpty())
408 continue;
409 screen->blit(img, topLeft, r);
410 }
411 }
412
blit(QWSWindow * bs,const QRegion & clip)413 void QMultiScreen::blit(QWSWindow *bs, const QRegion &clip)
414 {
415 const int n = d_ptr->screens.size();
416 for (int i = 0; i < n; ++i) {
417 QScreen *screen = d_ptr->screens.at(i);
418 const QRegion r = clip & screen->region();
419 if (r.isEmpty())
420 continue;
421 screen->blit(bs, r);
422 }
423 }
424
setDirty(const QRect & rect)425 void QMultiScreen::setDirty(const QRect &rect)
426 {
427 const int n = d_ptr->screens.size();
428 for (int i = 0; i < n; ++i) {
429 QScreen *screen = d_ptr->screens.at(i);
430 const QRegion r = screen->region() & rect;
431 if (r.isEmpty())
432 continue;
433 screen->setDirty(r.boundingRect());
434 }
435 }
436
437
createSurface(const QString & key) const438 QWSWindowSurface* QMultiScreen::createSurface(const QString &key) const
439 {
440 QWSWindowSurface* surf = 0;
441 const int n = d_ptr->screens.size();
442 for (int i = 0; i < n; ++i) {
443 QScreen *screen = d_ptr->screens.at(i);
444 surf = screen->createSurface(key);
445 if (surf)
446 break;
447 }
448 return surf;
449 }
450
451
createSurface(QWidget * widget) const452 QWSWindowSurface* QMultiScreen::createSurface(QWidget *widget) const
453 {
454 const QPoint midpoint = (widget->frameGeometry().topLeft()
455 + widget->frameGeometry().bottomRight()) / 2;
456 int index = subScreenIndexAt(midpoint);
457 if (index == -1)
458 index = 0; // XXX
459 return d_ptr->screens.at(index)->createSurface(widget);
460 }
461
subScreens() const462 QList<QScreen*> QMultiScreen::subScreens() const
463 {
464 return d_ptr->screens;
465 }
466
region() const467 QRegion QMultiScreen::region() const
468 {
469 return d_ptr->region;
470 }
471
addSubScreen(QScreen * screen)472 void QMultiScreen::addSubScreen(QScreen *screen)
473 {
474 d_ptr->screens.append(screen);
475 d_ptr->region += screen->region();
476 }
477
removeSubScreen(QScreen * screen)478 void QMultiScreen::removeSubScreen(QScreen *screen)
479 {
480 d_ptr->screens.removeAll(screen);
481 d_ptr->region -= screen->region();
482 }
483
484 QT_END_NAMESPACE
485
486 #endif // QT_NO_QWS_MULTISCREEN
487