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  case qtmir::DSI:
175  case qtmir::DPI:
176  return tr("Internal");
177  case qtmir::Component:
178  return tr("Component");
179  case qtmir::DisplayPort:
180  return tr("DisplayPort");
181  case qtmir::HDMIA:
182  case qtmir::HDMIB:
183  return tr("HDMI");
184  case qtmir::TV:
185  return tr("TV");
186  case qtmir::Virtual:
187  return tr("Virtual");
188  }
189  return QString();
190 }
191 
192 bool Screen::isSameAs(Screen *screen) const
193 {
194  if (!screen) return false;
195  if (screen == this) return true;
196  return wrapped() == screen->wrapped();
197 }
198 
199 void Screen::sync(Screen *proxy)
200 {
201  if (!proxy) return;
202  workspaces()->sync(proxy->workspaces());
203 }
204 
205 ConcreteScreen::ConcreteScreen(qtmir::Screen* wrapped)
206  : m_workspaces(new WorkspaceModel)
207 {
208  connectToScreen(wrapped);
209 
210  // Connect the active workspace to activate the screen.
211  connect(m_workspaces.data(), &WorkspaceModel::workspaceInserted, this, [this](int, Workspace* workspace) {
212  connect(workspace, &Workspace::activeChanged, this, [this, workspace](bool active) {
213  if (active) {
214  setCurrentWorkspace(workspace);
215  activate();
216  }
217  });
218  if (workspace->isActive()) {
219  activate();
220  setCurrentWorkspace(workspace);
221  }
222  if (!m_currentWorspace) {
223  setCurrentWorkspace(workspace);
224  }
225  });
226  connect(m_workspaces.data(), &WorkspaceModel::workspaceRemoved, this, [this](Workspace* workspace) {
227  disconnect(workspace, &Workspace::activeChanged, this, 0);
228  if (workspace == m_currentWorspace) {
229  resetCurrentWorkspace();
230  }
231  });
232  connect(this, &ConcreteScreen::activeChanged, this, [this](bool active) {
233  if (active && m_currentWorspace) {
234  m_currentWorspace->activate();
235  }
236  });
237 }
238 
239 void ConcreteScreen::resetCurrentWorkspace()
240 {
241  auto newCurrent = m_workspaces->rowCount() > 0 ? m_workspaces->get(0) : nullptr;
242  if (m_currentWorspace != newCurrent) {
243  m_currentWorspace = newCurrent;
244  Q_EMIT currentWorkspaceChanged(newCurrent);
245  }
246 }
247 
248 
249 WorkspaceModel *ConcreteScreen::workspaces() const
250 {
251  return m_workspaces.data();
252 }
253 
254 Workspace *ConcreteScreen::currentWorkspace() const
255 {
256  return m_currentWorspace.data();
257 }
258 
259 void ConcreteScreen::setCurrentWorkspace(Workspace *workspace)
260 {
261  if (m_currentWorspace != workspace) {
262  m_currentWorspace = workspace;
263  Q_EMIT currentWorkspaceChanged(workspace);
264  }
265 }
266 
267 ProxyScreen::ProxyScreen(Screen *const screen, ProxyScreens* screens)
268  : m_workspaces(new ProxyWorkspaceModel(screen->workspaces(), this))
269  , m_original(screen)
270  , m_screens(screens)
271 {
272  connectToScreen(screen);
273 
274  auto updateCurrentWorkspaceFn = [this](Workspace* realWorkspace) {
275  Q_FOREACH(Workspace* workspace, m_workspaces->list()) {
276  auto p = qobject_cast<ProxyWorkspace*>(workspace);
277  if (p && p->proxyObject() == realWorkspace) {
278  if (m_currentWorspace != p) {
279  m_currentWorspace = p;
280  Q_EMIT currentWorkspaceChanged(p);
281  }
282  }
283  }
284  };
285  connect(screen, &Screen::currentWorkspaceChanged, this, updateCurrentWorkspaceFn);
286  updateCurrentWorkspaceFn(screen->currentWorkspace());
287 }
288 
289 WorkspaceModel *ProxyScreen::workspaces() const
290 {
291  return m_workspaces.data();
292 }
293 
294 Workspace *ProxyScreen::currentWorkspace() const
295 {
296  return m_currentWorspace.data();
297 }
298 
299 void ProxyScreen::setCurrentWorkspace(Workspace *workspace)
300 {
301  auto p = qobject_cast<ProxyWorkspace*>(workspace);
302  if (p) {
303  m_original->setCurrentWorkspace(p->proxyObject());
304  }
305 }
306 
307 bool ProxyScreen::isSyncing() const
308 {
309  return m_screens->isSyncing();
310 }
311 
312 ScreenConfig::ScreenConfig(qtmir::ScreenConfiguration *config)
313  : m_config(config)
314 {
315 }
316 
317 ScreenConfig::~ScreenConfig()
318 {
319  delete m_config;
320 }