Unity 8
ScreenAttached.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 "ScreenAttached.h"
18 #include "ScreenWindow.h"
19 #include "Screens.h"
20 
21 #include <QQuickItem>
22 #include <QScreen>
23 
24 namespace
25 {
26 QQuickItem* itemForOwner(QObject* obj) {
27  QObject* parent = obj;
28  while(parent) {
29  auto item = qobject_cast<QQuickItem*>(parent);
30  if (item) return item;
31  parent = parent->parent();
32  }
33  return nullptr;
34 }
35 } // namesapce
36 
37 ScreenAttached::ScreenAttached(QObject *owner)
38  : Screen(owner)
39  , m_window(nullptr)
40 {
41  if (auto item = itemForOwner(owner)) {
42  connect(item, &QQuickItem::windowChanged, this, &ScreenAttached::windowChanged);
43  windowChanged(item->window());
44  } else if (auto window = qobject_cast<QQuickWindow*>(owner)) {
45  windowChanged(window);
46  }
47 }
48 
49 WorkspaceModel *ScreenAttached::workspaces() const
50 {
51  if (!m_screen) return nullptr;
52  return m_screen->workspaces();
53 }
54 
55 Workspace *ScreenAttached::currentWorkspace() const
56 {
57  if (!m_screen) return nullptr;
58  return m_screen->currentWorkspace();
59 }
60 
61 void ScreenAttached::setCurrentWorkspace(Workspace *workspace)
62 {
63  if (!m_screen) return;
64  return m_screen->setCurrentWorkspace(workspace);
65 }
66 
67 void ScreenAttached::windowChanged(QQuickWindow *window)
68 {
69  if (m_window) {
70  disconnect(m_window, &QWindow::screenChanged, this, &ScreenAttached::screenChanged);
71  }
72 
73  m_window = window;
74  auto screenWindow = qobject_cast<ScreenWindow*>(window);
75 
76  if (screenWindow) {
77  screenChanged2(screenWindow->screenWrapper());
78  connect(screenWindow, &ScreenWindow::screenWrapperChanged, this, &ScreenAttached::screenChanged2);
79  } else {
80  screenChanged(window ? window->screen() : NULL);
81  if (window) {
82  connect(window, &QWindow::screenChanged, this, &ScreenAttached::screenChanged);
83  }
84  }
85 }
86 
87 void ScreenAttached::screenChanged(QScreen *qscreen)
88 {
89  // Find a screen that matches.
90  // Should only get here in mocks if we don't have a ScreenWindow
91  Screen* screen{nullptr};
92  Q_FOREACH(auto s, ConcreteScreens::self()->list()) {
93  if (s->qscreen() == qscreen) {
94  screen = s;
95  }
96  }
97  screenChanged2(screen);
98 }
99 
100 void ScreenAttached::screenChanged2(Screen* screen)
101 {
102  if (screen == m_screen) return;
103 
104  Screen* oldScreen = m_screen;
105  m_screen = screen;
106 
107  if (oldScreen)
108  oldScreen->disconnect(this);
109 
110  if (!screen)
111  return; //Don't bother emitting signals, because the new values are garbage anyways
112 
113  if (!oldScreen || screen->isActive() != oldScreen->isActive())
114  Q_EMIT activeChanged(screen->isActive());
115  if (!oldScreen || screen->used() != oldScreen->used())
116  Q_EMIT usedChanged();
117  if (!oldScreen || screen->name() != oldScreen->name())
118  Q_EMIT nameChanged();
119  if (!oldScreen || screen->outputType() != oldScreen->outputType())
120  Q_EMIT outputTypeChanged();
121  if (!oldScreen || screen->scale() != oldScreen->scale())
122  Q_EMIT scaleChanged();
123  if (!oldScreen || screen->formFactor() != oldScreen->formFactor())
124  Q_EMIT formFactorChanged();
125  if (!oldScreen || screen->powerMode() != oldScreen->powerMode())
126  Q_EMIT powerModeChanged();
127  if (!oldScreen || screen->orientation() != oldScreen->orientation())
128  Q_EMIT orientationChanged();
129  if (!oldScreen || screen->position() != oldScreen->position())
130  Q_EMIT positionChanged();
131  if (!oldScreen || screen->currentModeIndex() != oldScreen->currentModeIndex())
132  Q_EMIT currentModeIndexChanged();
133  if (!oldScreen || screen->physicalSize() != oldScreen->physicalSize())
134  Q_EMIT physicalSizeChanged();
135  if (!oldScreen || screen->currentWorkspace() != oldScreen->currentWorkspace())
136  Q_EMIT currentWorkspaceChanged(currentWorkspace());
137 
138  if (oldScreen) {
139  QVector<qtmir::ScreenMode*> oldModes;
140  auto oldModesQmlList = oldScreen->availableModes();
141  for (int i = 0; i < oldModesQmlList.count(&oldModesQmlList); i++) {
142  oldModes << oldModesQmlList.at(&oldModesQmlList, i);
143  }
144 
145  QVector<qtmir::ScreenMode*> newModes;
146  auto newModesQmlList = screen->availableModes();
147  for (int i = 0; i < newModesQmlList.count(&newModesQmlList); i++) {
148  newModes << newModesQmlList.at(&newModesQmlList, i);
149  }
150 
151  if (newModes != newModes) {
152  Q_EMIT availableModesChanged();
153  }
154  } else {
155  Q_EMIT availableModesChanged();
156  }
157 
158  connectToScreen(screen);
159 }
160 
161 ScreenAttached *WMScreen::qmlAttachedProperties(QObject *owner)
162 {
163  return new ScreenAttached(owner);
164 }