OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "ash/monitor/multi_monitor_manager.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/command_line.h" | |
11 #include "base/stl_util.h" | |
12 #include "base/string_split.h" | |
13 #include "ui/aura/aura_switches.h" | |
14 #include "ui/aura/env.h" | |
15 #include "ui/aura/root_window.h" | |
16 #include "ui/aura/root_window_host.h" | |
17 #include "ui/aura/window_property.h" | |
18 #include "ui/gfx/display.h" | |
19 #include "ui/gfx/rect.h" | |
20 | |
21 DECLARE_WINDOW_PROPERTY_TYPE(int); | |
22 | |
23 namespace ash { | |
24 namespace internal { | |
25 namespace { | |
26 | |
27 gfx::Display& GetInvalidDisplay() { | |
28 static gfx::Display* invalid_display = new gfx::Display(); | |
29 return *invalid_display; | |
30 } | |
31 | |
32 } // namespace | |
33 | |
34 using aura::RootWindow; | |
35 using aura::Window; | |
36 using std::string; | |
37 using std::vector; | |
38 | |
39 DEFINE_WINDOW_PROPERTY_KEY(int, kMonitorIdKey, -1); | |
40 | |
41 MultiMonitorManager::MultiMonitorManager() { | |
42 Init(); | |
43 } | |
44 | |
45 MultiMonitorManager::~MultiMonitorManager() { | |
46 } | |
47 | |
48 // static | |
49 void MultiMonitorManager::AddRemoveMonitor() { | |
50 MultiMonitorManager* manager = static_cast<MultiMonitorManager*>( | |
51 aura::Env::GetInstance()->monitor_manager()); | |
52 manager->AddRemoveMonitorImpl(); | |
53 } | |
54 | |
55 void MultiMonitorManager::CycleMonitor() { | |
56 MultiMonitorManager* manager = static_cast<MultiMonitorManager*>( | |
57 aura::Env::GetInstance()->monitor_manager()); | |
58 manager->CycleMonitorImpl(); | |
59 } | |
60 | |
61 void MultiMonitorManager::ToggleMonitorScale() { | |
62 MultiMonitorManager* manager = static_cast<MultiMonitorManager*>( | |
63 aura::Env::GetInstance()->monitor_manager()); | |
64 manager->ScaleMonitorImpl(); | |
65 } | |
66 | |
67 void MultiMonitorManager::OnNativeMonitorsChanged( | |
68 const std::vector<gfx::Display>& new_displays) { | |
69 size_t min = std::min(displays_.size(), new_displays.size()); | |
70 | |
71 // For m19, we only care about 1st monitor as primary, and | |
72 // don't differentiate the rest of monitors as all secondary | |
73 // monitors have the same content. ID for primary monitor stays the same | |
74 // because we never remove it, we don't update IDs for other monitors | |
75 // , for now, because they're the same. | |
76 // TODO(oshima): Fix this so that we can differentiate outputs | |
77 // and keep a content on one monitor stays on the same monitor | |
78 // when a monitor is added or removed. | |
79 for (size_t i = 0; i < min; ++i) { | |
80 gfx::Display& current_display = displays_[i]; | |
81 const gfx::Display& new_display = new_displays[i]; | |
82 if (current_display.bounds_in_pixel() != new_display.bounds_in_pixel() || | |
83 current_display.device_scale_factor() != | |
84 new_display.device_scale_factor()) { | |
85 current_display.SetScaleAndBounds(new_display.device_scale_factor(), | |
86 new_display.bounds_in_pixel()); | |
87 NotifyBoundsChanged(current_display); | |
88 } | |
89 } | |
90 | |
91 if (displays_.size() < new_displays.size()) { | |
92 // New monitors added | |
93 for (size_t i = min; i < new_displays.size(); ++i) { | |
94 const gfx::Display& new_display = new_displays[i]; | |
95 displays_.push_back(gfx::Display(new_display.id())); | |
96 gfx::Display& display = displays_.back(); | |
97 // Force the primary display's ID to be 0. | |
98 if (i == 0) | |
99 display.set_id(0); | |
100 display.SetScaleAndBounds(new_display.device_scale_factor(), | |
101 new_display.bounds_in_pixel()); | |
102 NotifyDisplayAdded(display); | |
103 } | |
104 } else { | |
105 // Monitors are removed. We keep the monitor for the primary | |
106 // monitor (at index 0) because it needs the monitor information | |
107 // even if it doesn't exit. | |
108 while (displays_.size() > new_displays.size() && displays_.size() > 1) { | |
109 Displays::reverse_iterator iter = displays_.rbegin(); | |
110 NotifyDisplayRemoved(*iter); | |
111 displays_.erase(iter.base() - 1); | |
112 } | |
113 } | |
114 } | |
115 | |
116 RootWindow* MultiMonitorManager::CreateRootWindowForMonitor( | |
117 const gfx::Display& display) { | |
118 RootWindow* root_window = new RootWindow(display.bounds_in_pixel()); | |
119 // No need to remove RootWindowObserver because | |
120 // the MonitorManager object outlives RootWindow objects. | |
121 root_window->AddRootWindowObserver(this); | |
122 root_window->SetProperty(kMonitorIdKey, display.id()); | |
123 root_window->Init(); | |
124 return root_window; | |
125 } | |
126 | |
127 const gfx::Display& MultiMonitorManager::GetDisplayAt(size_t index) { | |
128 return index < displays_.size() ? displays_[index] : GetInvalidDisplay(); | |
129 } | |
130 | |
131 size_t MultiMonitorManager::GetNumDisplays() const { | |
132 return displays_.size(); | |
133 } | |
134 | |
135 const gfx::Display& MultiMonitorManager::GetDisplayNearestWindow( | |
136 const Window* window) const { | |
137 if (!window) { | |
138 MultiMonitorManager* manager = const_cast<MultiMonitorManager*>(this); | |
139 return manager->GetDisplayAt(0); | |
140 } | |
141 const RootWindow* root = window->GetRootWindow(); | |
142 MultiMonitorManager* manager = const_cast<MultiMonitorManager*>(this); | |
143 return root ? manager->FindDisplayForRootWindow(root) : GetInvalidDisplay(); | |
144 } | |
145 | |
146 const gfx::Display& MultiMonitorManager::GetDisplayNearestPoint( | |
147 const gfx::Point& point) const { | |
148 // TODO(oshima): For m19, mouse is constrained within | |
149 // the primary window. | |
150 MultiMonitorManager* manager = const_cast<MultiMonitorManager*>(this); | |
151 return manager->GetDisplayAt(0); | |
152 } | |
153 | |
154 void MultiMonitorManager::OnRootWindowResized(const aura::RootWindow* root, | |
155 const gfx::Size& old_size) { | |
156 if (!use_fullscreen_host_window()) { | |
157 gfx::Display& display = FindDisplayForRootWindow(root); | |
158 display.SetSize(root->GetHostSize()); | |
159 NotifyBoundsChanged(display); | |
160 } | |
161 } | |
162 | |
163 bool MultiMonitorManager::UpdateWorkAreaOfMonitorNearestWindow( | |
164 const aura::Window* window, | |
165 const gfx::Insets& insets) { | |
166 const RootWindow* root = window->GetRootWindow(); | |
167 gfx::Display& display = FindDisplayForRootWindow(root); | |
168 gfx::Rect old_work_area = display.work_area(); | |
169 display.UpdateWorkAreaFromInsets(insets); | |
170 return old_work_area != display.work_area(); | |
171 } | |
172 | |
173 void MultiMonitorManager::Init() { | |
174 // TODO(oshima): Move this logic to MonitorChangeObserver. | |
175 const string size_str = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
176 switches::kAuraHostWindowSize); | |
177 vector<string> parts; | |
178 base::SplitString(size_str, ',', &parts); | |
179 for (vector<string>::const_iterator iter = parts.begin(); | |
180 iter != parts.end(); ++iter) { | |
181 displays_.push_back(CreateMonitorFromSpec(*iter)); | |
182 } | |
183 if (displays_.empty()) | |
184 displays_.push_back(CreateMonitorFromSpec("" /* default */)); | |
185 // Force the 1st display to be the primary display (id == 0). | |
186 displays_[0].set_id(0); | |
187 } | |
188 | |
189 void MultiMonitorManager::AddRemoveMonitorImpl() { | |
190 std::vector<gfx::Display> new_displays; | |
191 if (displays_.size() > 1) { | |
192 // Remove if there is more than one display. | |
193 int count = displays_.size() - 1; | |
194 for (Displays::const_iterator iter = displays_.begin(); count-- > 0; ++iter) | |
195 new_displays.push_back(*iter); | |
196 } else { | |
197 // Add if there is only one display. | |
198 new_displays.push_back(displays_[0]); | |
199 new_displays.push_back(CreateMonitorFromSpec("50+50-1280x768")); | |
200 } | |
201 if (new_displays.size()) | |
202 OnNativeMonitorsChanged(new_displays); | |
203 } | |
204 | |
205 void MultiMonitorManager::CycleMonitorImpl() { | |
206 if (displays_.size() > 1) { | |
207 std::vector<gfx::Display> new_displays; | |
208 for (Displays::const_iterator iter = displays_.begin() + 1; | |
209 iter != displays_.end(); ++iter) { | |
210 gfx::Display display = *iter; | |
211 new_displays.push_back(display); | |
212 } | |
213 new_displays.push_back(displays_.front()); | |
214 OnNativeMonitorsChanged(new_displays); | |
215 } | |
216 } | |
217 | |
218 void MultiMonitorManager::ScaleMonitorImpl() { | |
219 if (displays_.size() > 0) { | |
220 std::vector<gfx::Display> new_displays; | |
221 for (Displays::const_iterator iter = displays_.begin(); | |
222 iter != displays_.end(); ++iter) { | |
223 gfx::Display display = *iter; | |
224 float factor = display.device_scale_factor() == 1.0f ? 2.0f : 1.0f; | |
225 display.SetScaleAndBounds( | |
226 factor, gfx::Rect(display.bounds_in_pixel().origin(), | |
227 display.size().Scale(factor))); | |
228 new_displays.push_back(display); | |
229 } | |
230 OnNativeMonitorsChanged(new_displays); | |
231 } | |
232 } | |
233 | |
234 gfx::Display& MultiMonitorManager::FindDisplayForRootWindow( | |
235 const aura::RootWindow* root_window) { | |
236 int id = root_window->GetProperty(kMonitorIdKey); | |
237 for (Displays::iterator iter = displays_.begin(); | |
238 iter != displays_.end(); ++iter) { | |
239 if ((*iter).id() == id) | |
240 return *iter; | |
241 } | |
242 DLOG(FATAL) << "Could not find display by id:" << id; | |
243 return GetInvalidDisplay(); | |
244 } | |
245 | |
246 } // namespace internal | |
247 } // namespace ash | |
OLD | NEW |