| 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 |