Lomiri
Screens.cpp
1 /*
2  * Copyright (C) 2016-2017 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it under
5  * the terms of the GNU Lesser General Public License version 3, as published by
6  * the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10  * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include "Screens.h"
18 #include "ScreensConfiguration.h"
19 #include "Screen.h"
20 #include "WorkspaceManager.h"
21 
22 // qtmirserver
23 #include <qtmir/screens.h>
24 #include <QGuiApplication>
25 #include <QQmlEngine>
26 
27 // Qt
28 #include <QScreen>
29 #include <QWindow>
30 
31 ConcreteScreens* ConcreteScreens::m_self{nullptr};
32 
33 Screens::Screens(const QSharedPointer<qtmir::Screens>& model)
34  : m_wrapped(model)
35 {
36 }
37 
38 Screens::~Screens()
39 {
40  qDeleteAll(m_screens);
41  m_screens.clear();
42 }
43 
44 QHash<int, QByteArray> Screens::roleNames() const
45 {
46  QHash<int, QByteArray> roles;
47  roles[ScreenRole] = "screen";
48  return roles;
49 }
50 
51 QVariant Screens::data(const QModelIndex &index, int role) const
52 {
53  if (!index.isValid() || index.row() >= m_screens.size()) {
54  return QVariant();
55  }
56 
57  switch(role) {
58  case ScreenRole:
59  return QVariant::fromValue(m_screens.at(index.row()));
60  } // switch
61 
62  return QVariant();
63 }
64 
65 int Screens::rowCount(const QModelIndex &) const
66 {
67  return count();
68 }
69 
70 int Screens::indexOf(Screen *screen) const
71 {
72  return m_screens.indexOf(screen);
73 }
74 
75 Screen *Screens::get(int index) const
76 {
77  return m_screens.at(index);
78 }
79 
80 int Screens::count() const
81 {
82  return m_screens.size();
83 }
84 
85 QVariant Screens::activeScreen() const
86 {
87  for (int i = 0; i < m_screens.count(); i++) {
88  if (m_screens[i]->isActive()) return i;
89  }
90  return QVariant();
91 }
92 
93 void Screens::activateScreen(const QVariant& vindex)
94 {
95  bool ok = false;
96  int index = vindex.toInt(&ok);
97  if (!ok || index < 0 || m_screens.count() <= index) return;
98 
99  auto screen = m_screens.at(index);
100  screen->setActive(true);
101 }
102 
103 
104 ConcreteScreens::ConcreteScreens(const QSharedPointer<qtmir::Screens> &model, ScreensConfiguration* config)
105  : Screens(model)
106  , m_config(config)
107 {
108  m_self = this;
109  connect(m_wrapped.data(), &qtmir::Screens::screenAdded, this, &ConcreteScreens::onScreenAdded);
110  connect(m_wrapped.data(), &qtmir::Screens::screenRemoved, this, &ConcreteScreens::onScreenRemoved);
111  connect(m_wrapped.data(), &qtmir::Screens::activeScreenChanged, this, &ConcreteScreens::activeScreenChanged);
112 
113  Q_FOREACH(qtmir::Screen* screen, m_wrapped->screens()) {
114  auto screenWrapper(new ConcreteScreen(screen));
115  m_config->load(screenWrapper);
116 
117  QQmlEngine::setObjectOwnership(screenWrapper, QQmlEngine::CppOwnership);
118  m_screens.push_back(screenWrapper);
119  }
120 }
121 
122 ConcreteScreens::~ConcreteScreens()
123 {
124  Q_FOREACH(Screen* screen, m_screens) {
125  m_config->save(screen);
126  }
127  delete m_config;
128 }
129 
130 ConcreteScreens *ConcreteScreens::self()
131 {
132  return ConcreteScreens::m_self;
133 }
134 
135 ProxyScreens *ConcreteScreens::createProxy()
136 {
137  return new ProxyScreens(this);
138 }
139 
140 void ConcreteScreens::sync(ProxyScreens *proxy)
141 {
142  if (!proxy) return;
143  proxy->setSyncing(true);
144 
145  const auto& proxyList = proxy->list();
146  for (int i = 0; i < m_screens.count() && i < proxyList.count(); ++i) {
147  m_screens[i]->sync(proxyList[i]);
148  }
149 
150  proxy->setSyncing(false);
151 }
152 
153 void ConcreteScreens::onScreenAdded(qtmir::Screen *added)
154 {
155  Q_FOREACH(auto screenWrapper, m_screens) {
156  if (screenWrapper->wrapped() == added) return;
157  }
158 
159  beginInsertRows(QModelIndex(), count(), count());
160  auto screenWrapper(new ConcreteScreen(added));
161  m_config->load(screenWrapper);
162 
163  QQmlEngine::setObjectOwnership(screenWrapper, QQmlEngine::CppOwnership);
164  m_screens.push_back(screenWrapper);
165  endInsertRows();
166  Q_EMIT screenAdded(screenWrapper);
167  Q_EMIT countChanged();
168 }
169 
170 void ConcreteScreens::onScreenRemoved(qtmir::Screen *removed)
171 {
172  int index = 0;
173  QMutableVectorIterator<Screen*> iter(m_screens);
174  while(iter.hasNext()) {
175  auto screenWrapper = iter.next();
176  if (screenWrapper->wrapped() == removed) {
177  m_config->save(screenWrapper);
178 
179  beginRemoveRows(QModelIndex(), index, index);
180  iter.remove();
181  endRemoveRows();
182 
183  Q_EMIT screenRemoved(screenWrapper);
184  Q_EMIT countChanged();
185 
186  screenWrapper->deleteLater();
187  break;
188  }
189  index++;
190  }
191 }
192 
193 
194 ProxyScreens::ProxyScreens(Screens * const screens)
195  : Screens(screens->m_wrapped)
196  , m_original(screens)
197  , m_syncing(false)
198 {
199  connect(screens, &Screens::screenAdded, this, [this](Screen *added) {
200  Q_FOREACH(auto screen, m_screens) {
201  auto proxy = static_cast<ProxyScreen*>(screen);
202  if (proxy->proxyObject() == added) return;
203  }
204 
205  beginInsertRows(QModelIndex(), count(), count());
206  auto screenWrapper(new ProxyScreen(added, this));
207  QQmlEngine::setObjectOwnership(screenWrapper, QQmlEngine::CppOwnership);
208  m_screens.push_back(screenWrapper);
209  endInsertRows();
210  Q_EMIT screenAdded(screenWrapper);
211  Q_EMIT countChanged();
212  });
213 
214  connect(screens, &Screens::screenRemoved, this, [this](Screen *removed) {
215  int index = 0;
216  QMutableVectorIterator<Screen*> iter(m_screens);
217  while(iter.hasNext()) {
218  auto proxy = static_cast<ProxyScreen*>(iter.next());
219  if (proxy->proxyObject() == removed) {
220 
221  beginRemoveRows(QModelIndex(), index, index);
222  iter.remove();
223  endRemoveRows();
224 
225  Q_EMIT screenRemoved(proxy);
226  Q_EMIT countChanged();
227 
228  delete proxy;
229  break;
230  }
231  index++;
232  }
233  });
234 
235  Q_FOREACH(Screen* screen, screens->list()) {
236  auto screenWrapper(new ProxyScreen(screen, this));
237  QQmlEngine::setObjectOwnership(screenWrapper, QQmlEngine::CppOwnership);
238  m_screens.push_back(screenWrapper);
239  }
240 }
241 
242 void ProxyScreens::setSyncing(bool syncing)
243 {
244  m_syncing = syncing;
245 }