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 &region)
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 &region)
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