OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/display/display_controller.h" | 5 #include "ash/display/display_controller.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "ash/ash_switches.h" | 9 #include "ash/ash_switches.h" |
10 #include "ash/display/multi_display_manager.h" | 10 #include "ash/display/multi_display_manager.h" |
11 #include "ash/root_window_controller.h" | 11 #include "ash/root_window_controller.h" |
12 #include "ash/screen_ash.h" | 12 #include "ash/screen_ash.h" |
13 #include "ash/shell.h" | 13 #include "ash/shell.h" |
14 #include "ash/wm/coordinate_conversion.h" | 14 #include "ash/wm/coordinate_conversion.h" |
15 #include "ash/wm/property_util.h" | 15 #include "ash/wm/property_util.h" |
16 #include "ash/wm/window_util.h" | 16 #include "ash/wm/window_util.h" |
17 #include "base/command_line.h" | 17 #include "base/command_line.h" |
| 18 #include "base/json/json_value_converter.h" |
| 19 #include "base/string_piece.h" |
| 20 #include "base/values.h" |
18 #include "ui/aura/client/screen_position_client.h" | 21 #include "ui/aura/client/screen_position_client.h" |
19 #include "ui/aura/env.h" | 22 #include "ui/aura/env.h" |
20 #include "ui/aura/root_window.h" | 23 #include "ui/aura/root_window.h" |
21 #include "ui/aura/window.h" | 24 #include "ui/aura/window.h" |
22 #include "ui/compositor/dip_util.h" | 25 #include "ui/compositor/dip_util.h" |
23 #include "ui/gfx/display.h" | 26 #include "ui/gfx/display.h" |
24 #include "ui/gfx/screen.h" | 27 #include "ui/gfx/screen.h" |
25 | 28 |
26 #if defined(OS_CHROMEOS) | 29 #if defined(OS_CHROMEOS) |
27 #include "base/chromeos/chromeos_version.h" | 30 #include "base/chromeos/chromeos_version.h" |
28 #endif | 31 #endif |
29 | 32 |
30 namespace ash { | 33 namespace ash { |
31 namespace internal { | |
32 namespace { | 34 namespace { |
33 | 35 |
| 36 // The maximum value for 'offset' in DisplayLayout in case of outliers. Need |
| 37 // to change this value in case to support even larger displays. |
| 38 const int kMaxValidOffset = 10000; |
| 39 |
34 // The number of pixels to overlap between the primary and secondary displays, | 40 // The number of pixels to overlap between the primary and secondary displays, |
35 // in case that the offset value is too large. | 41 // in case that the offset value is too large. |
36 const int kMinimumOverlapForInvalidOffset = 50; | 42 const int kMinimumOverlapForInvalidOffset = 50; |
37 | 43 |
| 44 bool GetPositionFromString(const base::StringPiece& position, |
| 45 DisplayLayout::Position* field) { |
| 46 if (position == "top") { |
| 47 *field = DisplayLayout::TOP; |
| 48 return true; |
| 49 } else if (position == "bottom") { |
| 50 *field = DisplayLayout::BOTTOM; |
| 51 return true; |
| 52 } else if (position == "right") { |
| 53 *field = DisplayLayout::RIGHT; |
| 54 return true; |
| 55 } else if (position == "left") { |
| 56 *field = DisplayLayout::LEFT; |
| 57 return true; |
| 58 } |
| 59 LOG(ERROR) << "Invalid position value: " << position; |
| 60 |
| 61 return false; |
38 } | 62 } |
39 | 63 |
40 DisplayController::DisplayController() | 64 } // namespace |
41 : secondary_display_layout_(RIGHT), | 65 |
42 secondary_display_offset_(0) { | 66 DisplayLayout::DisplayLayout() |
| 67 : position(RIGHT), |
| 68 offset(0) {} |
| 69 |
| 70 DisplayLayout::DisplayLayout(DisplayLayout::Position position, int offset) |
| 71 : position(position), |
| 72 offset(offset) { |
| 73 DCHECK_LE(TOP, position); |
| 74 DCHECK_GE(LEFT, position); |
| 75 |
| 76 // Set the default value to |position| in case position is invalid. DCHECKs |
| 77 // above doesn't stop in Release builds. |
| 78 if (TOP > position || LEFT < position) |
| 79 this->position = RIGHT; |
| 80 |
| 81 DCHECK_GE(kMaxValidOffset, abs(offset)); |
| 82 } |
| 83 |
| 84 // static |
| 85 bool DisplayLayout::ConvertFromValue(const base::Value& value, |
| 86 DisplayLayout* layout) { |
| 87 base::JSONValueConverter<DisplayLayout> converter; |
| 88 return converter.Convert(value, layout); |
| 89 } |
| 90 |
| 91 // static |
| 92 bool DisplayLayout::ConvertToValue(const DisplayLayout& layout, |
| 93 base::Value* value) { |
| 94 base::DictionaryValue* dict_value = NULL; |
| 95 if (!value->GetAsDictionary(&dict_value) || dict_value == NULL) |
| 96 return false; |
| 97 |
| 98 std::string position_value; |
| 99 switch (layout.position) { |
| 100 case TOP: |
| 101 position_value = "top"; |
| 102 break; |
| 103 case BOTTOM: |
| 104 position_value = "bottom"; |
| 105 break; |
| 106 case RIGHT: |
| 107 position_value = "right"; |
| 108 break; |
| 109 case LEFT: |
| 110 position_value = "left"; |
| 111 break; |
| 112 default: |
| 113 return false; |
| 114 } |
| 115 |
| 116 dict_value->SetString("position", position_value); |
| 117 dict_value->SetInteger("offset", layout.offset); |
| 118 return true; |
| 119 } |
| 120 |
| 121 // static |
| 122 void DisplayLayout::RegisterJSONConverter( |
| 123 base::JSONValueConverter<DisplayLayout>* converter) { |
| 124 converter->RegisterCustomField<Position>( |
| 125 "position", &DisplayLayout::position, &GetPositionFromString); |
| 126 converter->RegisterIntField("offset", &DisplayLayout::offset); |
| 127 } |
| 128 |
| 129 DisplayController::DisplayController() { |
43 aura::Env::GetInstance()->display_manager()->AddObserver(this); | 130 aura::Env::GetInstance()->display_manager()->AddObserver(this); |
44 } | 131 } |
45 | 132 |
46 DisplayController::~DisplayController() { | 133 DisplayController::~DisplayController() { |
47 aura::Env::GetInstance()->display_manager()->RemoveObserver(this); | 134 aura::Env::GetInstance()->display_manager()->RemoveObserver(this); |
48 // Delete all root window controllers, which deletes root window | 135 // Delete all root window controllers, which deletes root window |
49 // from the last so that the primary root window gets deleted last. | 136 // from the last so that the primary root window gets deleted last. |
50 for (std::map<int64, aura::RootWindow*>::const_reverse_iterator it = | 137 for (std::map<int64, aura::RootWindow*>::const_reverse_iterator it = |
51 root_windows_.rbegin(); it != root_windows_.rend(); ++it) { | 138 root_windows_.rbegin(); it != root_windows_.rend(); ++it) { |
52 internal::RootWindowController* controller = | 139 internal::RootWindowController* controller = |
(...skipping 20 matching lines...) Expand all Loading... |
73 Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root); | 160 Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root); |
74 } | 161 } |
75 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 162 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
76 if (command_line->HasSwitch(switches::kAshSecondaryDisplayLayout)) { | 163 if (command_line->HasSwitch(switches::kAshSecondaryDisplayLayout)) { |
77 std::string value = command_line->GetSwitchValueASCII( | 164 std::string value = command_line->GetSwitchValueASCII( |
78 switches::kAshSecondaryDisplayLayout); | 165 switches::kAshSecondaryDisplayLayout); |
79 char layout; | 166 char layout; |
80 int offset; | 167 int offset; |
81 if (sscanf(value.c_str(), "%c,%d", &layout, &offset) == 2) { | 168 if (sscanf(value.c_str(), "%c,%d", &layout, &offset) == 2) { |
82 if (layout == 't') | 169 if (layout == 't') |
83 secondary_display_layout_ = TOP; | 170 default_display_layout_.position = DisplayLayout::TOP; |
84 else if (layout == 'b') | 171 else if (layout == 'b') |
85 secondary_display_layout_ = BOTTOM; | 172 default_display_layout_.position = DisplayLayout::BOTTOM; |
86 else if (layout == 'r') | 173 else if (layout == 'r') |
87 secondary_display_layout_ = RIGHT; | 174 default_display_layout_.position = DisplayLayout::RIGHT; |
88 else if (layout == 'l') | 175 else if (layout == 'l') |
89 secondary_display_layout_ = LEFT; | 176 default_display_layout_.position = DisplayLayout::LEFT; |
90 secondary_display_offset_ = offset; | 177 default_display_layout_.offset = offset; |
91 } | 178 } |
92 } | 179 } |
93 UpdateDisplayBoundsForLayout(); | 180 UpdateDisplayBoundsForLayout(); |
94 } | 181 } |
95 | 182 |
96 aura::RootWindow* DisplayController::GetPrimaryRootWindow() { | 183 aura::RootWindow* DisplayController::GetPrimaryRootWindow() { |
97 DCHECK(!root_windows_.empty()); | 184 DCHECK(!root_windows_.empty()); |
98 aura::DisplayManager* display_manager = | 185 aura::DisplayManager* display_manager = |
99 aura::Env::GetInstance()->display_manager(); | 186 aura::Env::GetInstance()->display_manager(); |
100 return root_windows_[display_manager->GetDisplayAt(0)->id()]; | 187 return root_windows_[display_manager->GetDisplayAt(0)->id()]; |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
138 for (std::map<int64, aura::RootWindow*>::const_iterator it = | 225 for (std::map<int64, aura::RootWindow*>::const_iterator it = |
139 root_windows_.begin(); it != root_windows_.end(); ++it) { | 226 root_windows_.begin(); it != root_windows_.end(); ++it) { |
140 internal::RootWindowController* controller = | 227 internal::RootWindowController* controller = |
141 GetRootWindowController(it->second); | 228 GetRootWindowController(it->second); |
142 if (controller) | 229 if (controller) |
143 controllers.push_back(controller); | 230 controllers.push_back(controller); |
144 } | 231 } |
145 return controllers; | 232 return controllers; |
146 } | 233 } |
147 | 234 |
148 void DisplayController::SetSecondaryDisplayLayout( | 235 void DisplayController::SetDefaultDisplayLayout(const DisplayLayout& layout) { |
149 SecondaryDisplayLayout layout) { | 236 default_display_layout_ = layout; |
150 secondary_display_layout_ = layout; | |
151 UpdateDisplayBoundsForLayout(); | 237 UpdateDisplayBoundsForLayout(); |
152 } | 238 } |
153 | 239 |
154 void DisplayController::SetSecondaryDisplayOffset(int offset) { | 240 void DisplayController::SetLayoutForDisplayName(const std::string& name, |
155 secondary_display_offset_ = offset; | 241 const DisplayLayout& layout) { |
| 242 secondary_layouts_[name] = layout; |
156 UpdateDisplayBoundsForLayout(); | 243 UpdateDisplayBoundsForLayout(); |
157 } | 244 } |
158 | 245 |
| 246 const DisplayLayout& DisplayController::GetLayoutForDisplayName( |
| 247 const std::string& name) { |
| 248 std::map<std::string, DisplayLayout>::const_iterator it = |
| 249 secondary_layouts_.find(name); |
| 250 |
| 251 if (it != secondary_layouts_.end()) |
| 252 return it->second; |
| 253 return default_display_layout_; |
| 254 } |
159 | 255 |
160 void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) { | 256 void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) { |
161 root_windows_[display.id()]->SetHostBounds(display.bounds_in_pixel()); | 257 root_windows_[display.id()]->SetHostBounds(display.bounds_in_pixel()); |
162 UpdateDisplayBoundsForLayout(); | 258 UpdateDisplayBoundsForLayout(); |
163 } | 259 } |
164 | 260 |
165 void DisplayController::OnDisplayAdded(const gfx::Display& display) { | 261 void DisplayController::OnDisplayAdded(const gfx::Display& display) { |
166 DCHECK(!root_windows_.empty()); | 262 DCHECK(!root_windows_.empty()); |
167 aura::RootWindow* root = AddRootWindowForDisplay(display); | 263 aura::RootWindow* root = AddRootWindowForDisplay(display); |
168 Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root); | 264 Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 | 304 |
209 void DisplayController::UpdateDisplayBoundsForLayout() { | 305 void DisplayController::UpdateDisplayBoundsForLayout() { |
210 if (gfx::Screen::GetNumDisplays() <= 1) | 306 if (gfx::Screen::GetNumDisplays() <= 1) |
211 return; | 307 return; |
212 | 308 |
213 DCHECK_EQ(2, gfx::Screen::GetNumDisplays()); | 309 DCHECK_EQ(2, gfx::Screen::GetNumDisplays()); |
214 aura::DisplayManager* display_manager = | 310 aura::DisplayManager* display_manager = |
215 aura::Env::GetInstance()->display_manager(); | 311 aura::Env::GetInstance()->display_manager(); |
216 const gfx::Rect& primary_bounds = display_manager->GetDisplayAt(0)->bounds(); | 312 const gfx::Rect& primary_bounds = display_manager->GetDisplayAt(0)->bounds(); |
217 gfx::Display* secondary_display = display_manager->GetDisplayAt(1); | 313 gfx::Display* secondary_display = display_manager->GetDisplayAt(1); |
| 314 const std::string& secondary_name = display_manager->GetDisplayNameAt(1); |
218 const gfx::Rect& secondary_bounds = secondary_display->bounds(); | 315 const gfx::Rect& secondary_bounds = secondary_display->bounds(); |
219 gfx::Point new_secondary_origin = primary_bounds.origin(); | 316 gfx::Point new_secondary_origin = primary_bounds.origin(); |
220 | 317 |
| 318 const DisplayLayout* layout = &default_display_layout_; |
| 319 std::map<std::string, DisplayLayout>::const_iterator iter = |
| 320 secondary_layouts_.find(secondary_name); |
| 321 if (iter != secondary_layouts_.end()) |
| 322 layout = &iter->second; |
| 323 |
| 324 DisplayLayout::Position position = layout->position; |
| 325 |
221 // Ignore the offset in case the secondary display doesn't share edges with | 326 // Ignore the offset in case the secondary display doesn't share edges with |
222 // the primary display. | 327 // the primary display. |
223 int offset = secondary_display_offset_; | 328 int offset = layout->offset; |
224 if (secondary_display_layout_ == TOP || secondary_display_layout_ == BOTTOM) { | 329 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM) { |
225 offset = std::min( | 330 offset = std::min( |
226 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset); | 331 offset, primary_bounds.width() - kMinimumOverlapForInvalidOffset); |
227 offset = std::max( | 332 offset = std::max( |
228 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset); | 333 offset, -secondary_bounds.width() + kMinimumOverlapForInvalidOffset); |
229 } else { | 334 } else { |
230 offset = std::min( | 335 offset = std::min( |
231 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset); | 336 offset, primary_bounds.height() - kMinimumOverlapForInvalidOffset); |
232 offset = std::max( | 337 offset = std::max( |
233 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset); | 338 offset, -secondary_bounds.height() + kMinimumOverlapForInvalidOffset); |
234 } | 339 } |
235 switch (secondary_display_layout_) { | 340 switch (position) { |
236 case TOP: | 341 case DisplayLayout::TOP: |
237 new_secondary_origin.Offset(offset, -secondary_bounds.height()); | 342 new_secondary_origin.Offset(offset, -secondary_bounds.height()); |
238 break; | 343 break; |
239 case RIGHT: | 344 case DisplayLayout::RIGHT: |
240 new_secondary_origin.Offset(primary_bounds.width(), offset); | 345 new_secondary_origin.Offset(primary_bounds.width(), offset); |
241 break; | 346 break; |
242 case BOTTOM: | 347 case DisplayLayout::BOTTOM: |
243 new_secondary_origin.Offset(offset, primary_bounds.height()); | 348 new_secondary_origin.Offset(offset, primary_bounds.height()); |
244 break; | 349 break; |
245 case LEFT: | 350 case DisplayLayout::LEFT: |
246 new_secondary_origin.Offset(-secondary_bounds.width(), offset); | 351 new_secondary_origin.Offset(-secondary_bounds.width(), offset); |
247 break; | 352 break; |
248 } | 353 } |
249 gfx::Insets insets = secondary_display->GetWorkAreaInsets(); | 354 gfx::Insets insets = secondary_display->GetWorkAreaInsets(); |
250 secondary_display->set_bounds( | 355 secondary_display->set_bounds( |
251 gfx::Rect(new_secondary_origin, secondary_bounds.size())); | 356 gfx::Rect(new_secondary_origin, secondary_bounds.size())); |
252 secondary_display->UpdateWorkAreaFromInsets(insets); | 357 secondary_display->UpdateWorkAreaFromInsets(insets); |
253 } | 358 } |
254 | 359 |
255 } // namespace internal | |
256 } // namespace ash | 360 } // namespace ash |
OLD | NEW |