Lomiri
Screen.cpp
1 /*
2  * Copyright (C) 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 "Screen.h"
18 #include "Screens.h"
19 #include "WorkspaceManager.h"
20 #include "Workspace.h"
21 
22 Screen::Screen(QObject *parent)
23  : QObject(parent)
24 {
25 }
26 
27 void Screen::connectToScreen(qtmir::Screen *screen)
28 {
29  m_wrapped = screen;
30  connect(screen, &qtmir::Screen::usedChanged, this, &Screen::usedChanged);
31  connect(screen, &qtmir::Screen::nameChanged, this, &Screen::nameChanged);
32  connect(screen, &qtmir::Screen::outputTypeChanged, this, &Screen::outputTypeChanged);
33  connect(screen, &qtmir::Screen::outputTypeChanged, this, &Screen::outputTypeNameChanged);
34  connect(screen, &qtmir::Screen::scaleChanged, this, &Screen::scaleChanged);
35  connect(screen, &qtmir::Screen::formFactorChanged, this, &Screen::formFactorChanged);
36  connect(screen, &qtmir::Screen::physicalSizeChanged, this, &Screen::physicalSizeChanged);
37  connect(screen, &qtmir::Screen::positionChanged, this, &Screen::positionChanged);
38  connect(screen, &qtmir::Screen::activeChanged, this, &Screen::activeChanged);
39  connect(screen, &qtmir::Screen::currentModeIndexChanged, this, &Screen::currentModeIndexChanged);
40  connect(screen, &qtmir::Screen::availableModesChanged, this, &Screen::availableModesChanged);
41 }
42 
43 void Screen::connectToScreen(Screen *screen)
44 {
45  connectToScreen(screen->wrapped());
46  connect(screen, &Screen::currentWorkspaceChanged, this, &Screen::currentWorkspaceChanged);
47 }
48 
49 void Screen::setCurrentWorkspace2(Workspace *workspace)
50 {
51  // Make sure we use the correct concrete class. Don't want to use a Proxy.
52  workspace->setCurrentOn(this);
53 }
54 
55 bool Screen::used() const
56 {
57  if (!m_wrapped) return false;
58  return m_wrapped->used();
59 }
60 
61 QString Screen::name() const
62 {
63  if (!m_wrapped) return QString();
64  return m_wrapped->name();
65 }
66 
67 float Screen::scale() const
68 {
69  if (!m_wrapped) return 1.0;
70  return m_wrapped->scale();
71 }
72 
73 QSizeF Screen::physicalSize() const
74 {
75  if (!m_wrapped) return QSizeF();
76  return m_wrapped->physicalSize();
77 }
78 
79 Screen::FormFactor Screen::formFactor() const
80 {
81  if (!m_wrapped) return static_cast<Screen::FormFactor>(qtmir::FormFactorUnknown);
82  return static_cast<Screen::FormFactor>(m_wrapped->formFactor());
83 }
84 
85 qtmir::OutputTypes Screen::outputType() const
86 {
87  if (!m_wrapped) return qtmir::Unknown;
88  return m_wrapped->outputType();
89 }
90 
91 MirPowerMode Screen::powerMode() const
92 {
93  if (!m_wrapped) return mir_power_mode_on;
94  return m_wrapped->powerMode();
95 }
96 
97 Qt::ScreenOrientation Screen::orientation() const
98 {
99  if (!m_wrapped) return Qt::PrimaryOrientation;
100  return m_wrapped->orientation();
101 }
102 
103 QPoint Screen::position() const
104 {
105  if (!m_wrapped) return QPoint();
106  return m_wrapped->position();
107 }
108 
109 QQmlListProperty<qtmir::ScreenMode> Screen::availableModes()
110 {
111  if (!m_wrapped) return QQmlListProperty<qtmir::ScreenMode>();
112  return m_wrapped->availableModes();
113 }
114 
115 uint Screen::currentModeIndex() const
116 {
117  if (!m_wrapped) return -1;
118  return m_wrapped->currentModeIndex();
119 }
120 
121 bool Screen::isActive() const
122 {
123  if (!m_wrapped) return false;
124  return m_wrapped->isActive();
125 }
126 
127 void Screen::activate()
128 {
129  setActive(true);
130 }
131 
132 void Screen::setActive(bool active)
133 {
134  if (!m_wrapped) return;
135  m_wrapped->setActive(active);
136 }
137 
138 QScreen *Screen::qscreen() const
139 {
140  if (!m_wrapped) return nullptr;
141  return m_wrapped->qscreen();
142 }
143 
144 ScreenConfig *Screen::beginConfiguration() const
145 {
146  if (!m_wrapped) return nullptr;
147  return new ScreenConfig(m_wrapped->beginConfiguration());
148 }
149 
150 bool Screen::applyConfiguration(ScreenConfig *configuration)
151 {
152  if (!m_wrapped) return false;
153  return m_wrapped->applyConfiguration(configuration->m_config);
154 }
155 
156 QString Screen::outputTypeName() const
157 {
158  switch (m_wrapped->outputType()) {
159  case qtmir::Unknown:
160  return tr("Unknown");
161  case qtmir::VGA:
162  return tr("VGA");
163  case qtmir::DVII:
164  case qtmir::DVID:
165  case qtmir::DVIA:
166  return tr("DVI");
167  case qtmir::Composite:
168  return tr("Composite");
169  case qtmir::SVideo:
170  return tr("S-Video");
171  case qtmir::LVDS:
172  case qtmir::NinePinDIN:
173  case qtmir::EDP:
174  return tr("Internal");
175  case qtmir::Component:
176  return tr("Component");
177  case qtmir::DisplayPort:
178  return tr("DisplayPort");
179  case qtmir::HDMIA:
180  case qtmir::HDMIB:
181  return tr("HDMI");
182  case qtmir::TV:
183  return tr("TV");
184  }
185  return QString();
186 }
187 
188 bool Screen::isSameAs(Screen *screen) const
189 {
190  if (!screen) return false;
191  if (screen == this) return true;
192  return wrapped() == screen->wrapped();
193 }
194 
195 void Screen::sync(Screen *proxy)
196 {
197  if (!proxy) return;
198  workspaces()->sync(proxy->workspaces());
199 }
200 
201 ConcreteScreen::ConcreteScreen(qtmir::Screen* wrapped)
202  : m_workspaces(new WorkspaceModel)
203 {
204  connectToScreen(wrapped);
205 
206  // Connect the active workspace to activate the screen.
207  connect(m_workspaces.data(), &WorkspaceModel::workspaceInserted, this, [this](int, Workspace* workspace) {
208  connect(workspace, &Workspace::activeChanged, this, [this, workspace](bool active) {
209  if (active) {
210  setCurrentWorkspace(workspace);
211  activate();
212  }
213  });
214  if (workspace->isActive()) {
215  activate();
216  setCurrentWorkspace(workspace);
217  }
218  if (!m_currentWorspace) {
219  setCurrentWorkspace(workspace);
220  }
221  });
222  connect(m_workspaces.data(), &WorkspaceModel::workspaceRemoved, this, [this](Workspace* workspace) {
223  disconnect(workspace, &Workspace::activeChanged, this, 0);
224  if (workspace == m_currentWorspace) {
225  resetCurrentWorkspace();
226  }
227  });
228  connect(this, &ConcreteScreen::activeChanged, this, [this](bool active) {
229  if (active && m_currentWorspace) {
230  m_currentWorspace->activate();
231  }
232  });
233 }
234 
235 void ConcreteScreen::resetCurrentWorkspace()
236 {
237  auto newCurrent = m_workspaces->rowCount() > 0 ? m_workspaces->get(0) : nullptr;
238  if (m_currentWorspace != newCurrent) {
239  m_currentWorspace = newCurrent;
240  Q_EMIT currentWorkspaceChanged(newCurrent);
241  }
242 }
243 
244 
245 WorkspaceModel *ConcreteScreen::workspaces() const
246 {
247  return m_workspaces.data();
248 }
249 
250 Workspace *ConcreteScreen::currentWorkspace() const
251 {
252  return m_currentWorspace.data();
253 }
254 
255 void ConcreteScreen::setCurrentWorkspace(Workspace *workspace)
256 {
257  if (m_currentWorspace != workspace) {
258  m_currentWorspace = workspace;
259  Q_EMIT currentWorkspaceChanged(workspace);
260  }
261 }
262 
263 ProxyScreen::ProxyScreen(Screen *const screen, ProxyScreens* screens)
264  : m_workspaces(new ProxyWorkspaceModel(screen->workspaces(), this))
265  , m_original(screen)
266  , m_screens(screens)
267 {
268  connectToScreen(screen);
269 
270  auto updateCurrentWorkspaceFn = [this](Workspace* realWorkspace) {
271  Q_FOREACH(Workspace* workspace, m_workspaces->list()) {
272  auto p = qobject_cast<ProxyWorkspace*>(workspace);
273  if (p && p->proxyObject() == realWorkspace) {
274  if (m_currentWorspace != p) {
275  m_currentWorspace = p;
276  Q_EMIT currentWorkspaceChanged(p);
277  }
278  }
279  }
280  };
281  connect(screen, &Screen::currentWorkspaceChanged, this, updateCurrentWorkspaceFn);
282  updateCurrentWorkspaceFn(screen->currentWorkspace());
283 }
284 
285 WorkspaceModel *ProxyScreen::workspaces() const
286 {
287  return m_workspaces.data();
288 }
289 
290 Workspace *ProxyScreen::currentWorkspace() const
291 {
292  return m_currentWorspace.data();
293 }
294 
295 void ProxyScreen::setCurrentWorkspace(Workspace *workspace)
296 {
297  auto p = qobject_cast<ProxyWorkspace*>(workspace);
298  if (p) {
299  m_original->setCurrentWorkspace(p->proxyObject());
300  }
301 }
302 
303 bool ProxyScreen::isSyncing() const
304 {
305  return m_screens->isSyncing();
306 }
307 
308 ScreenConfig::ScreenConfig(qtmir::ScreenConfiguration *config)
309  : m_config(config)
310 {
311 }
312 
313 ScreenConfig::~ScreenConfig()
314 {
315  delete m_config;
316 }