Chromium Code Reviews| 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 #include <cmath> | 8 #include <cmath> |
| 9 #include <map> | 9 #include <map> |
| 10 | 10 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 #include "ui/aura/client/capture_client.h" | 28 #include "ui/aura/client/capture_client.h" |
| 29 #include "ui/aura/client/focus_client.h" | 29 #include "ui/aura/client/focus_client.h" |
| 30 #include "ui/aura/client/screen_position_client.h" | 30 #include "ui/aura/client/screen_position_client.h" |
| 31 #include "ui/aura/root_window_transformer.h" | 31 #include "ui/aura/root_window_transformer.h" |
| 32 #include "ui/aura/window.h" | 32 #include "ui/aura/window.h" |
| 33 #include "ui/aura/window_event_dispatcher.h" | 33 #include "ui/aura/window_event_dispatcher.h" |
| 34 #include "ui/aura/window_property.h" | 34 #include "ui/aura/window_property.h" |
| 35 #include "ui/aura/window_tracker.h" | 35 #include "ui/aura/window_tracker.h" |
| 36 #include "ui/compositor/compositor.h" | 36 #include "ui/compositor/compositor.h" |
| 37 #include "ui/compositor/compositor_vsync_manager.h" | 37 #include "ui/compositor/compositor_vsync_manager.h" |
| 38 #include "ui/events/touch_ctm.h" | |
| 38 #include "ui/gfx/display.h" | 39 #include "ui/gfx/display.h" |
| 39 #include "ui/gfx/screen.h" | 40 #include "ui/gfx/screen.h" |
| 40 | 41 |
| 41 #if defined(OS_CHROMEOS) | 42 #if defined(OS_CHROMEOS) |
| 42 #include "base/sys_info.h" | 43 #include "base/sys_info.h" |
| 43 #include "base/time/time.h" | 44 #include "base/time/time.h" |
| 44 #if defined(USE_X11) | 45 #if defined(USE_X11) |
| 45 #include "ash/display/output_configurator_animation.h" | 46 #include "ash/display/output_configurator_animation.h" |
| 46 #include "chromeos/display/output_configurator.h" | 47 #include "chromeos/display/output_configurator.h" |
| 47 #include "ui/base/x/x11_util.h" | 48 #include "ui/base/x/x11_util.h" |
| 49 #include "ui/events/x/device_data_manager.h" | |
| 48 #include "ui/gfx/x/x11_types.h" | 50 #include "ui/gfx/x/x11_types.h" |
| 49 | 51 |
| 50 // Including this at the bottom to avoid other | 52 // Including this at the bottom to avoid other |
| 51 // potential conflict with chrome headers. | 53 // potential conflict with chrome headers. |
| 52 #include <X11/extensions/Xrandr.h> | 54 #include <X11/extensions/Xrandr.h> |
| 53 #undef RootWindow | 55 #undef RootWindow |
| 54 #endif // defined(USE_X11) | 56 #endif // defined(USE_X11) |
| 55 #endif // defined(OS_CHROMEOS) | 57 #endif // defined(OS_CHROMEOS) |
| 56 | 58 |
| 57 namespace ash { | 59 namespace ash { |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 125 | 127 |
| 126 internal::DisplayMode mode; | 128 internal::DisplayMode mode; |
| 127 if (GetDisplayManager()->GetSelectedModeForDisplayId(display.id(), &mode) && | 129 if (GetDisplayManager()->GetSelectedModeForDisplayId(display.id(), &mode) && |
| 128 mode.refresh_rate > 0.0f) { | 130 mode.refresh_rate > 0.0f) { |
| 129 host->compositor()->vsync_manager()->SetAuthoritativeVSyncInterval( | 131 host->compositor()->vsync_manager()->SetAuthoritativeVSyncInterval( |
| 130 base::TimeDelta::FromMicroseconds( | 132 base::TimeDelta::FromMicroseconds( |
| 131 base::Time::kMicrosecondsPerSecond / mode.refresh_rate)); | 133 base::Time::kMicrosecondsPerSecond / mode.refresh_rate)); |
| 132 } | 134 } |
| 133 } | 135 } |
| 134 | 136 |
| 137 #if defined(OS_CHROMEOS) && defined(USE_X11) | |
| 138 // This function computes the extended mode TouchCTM for |touch_display|. | |
| 139 // An example of how to calculate the extended CTM. | |
| 140 // Suppose we have 2 monitors, the first one has size 1366 x 768. | |
| 141 // The second one has size 2560 x 1600 | |
| 142 // The total size of framebuffer is 2560 x 2428 | |
| 143 // where 2428 = 768 + 60 (hidden gap) + 1600 | |
| 144 // and the sceond monitor is translated to Point (0, 828) in the | |
| 145 // framebuffer. | |
| 146 // X will first map input event location to [0, 2560) x [0, 2428), | |
| 147 // Then the TouchCTM should map touch events from framebuffer space | |
| 148 // to root window space. | |
| 149 // For monitor1, we have | |
| 150 // x_scale = (1366 - 1) / (2560 - 1) | |
| 151 // x_offset = 0 | |
| 152 // y_scale = (768 - 1) / (2428 - 1) | |
| 153 // y_offset = 0 | |
| 154 // For Monitor 2, we have | |
| 155 // x_scale = (2560 - 1) / (2560 - 1) | |
| 156 // x_offset = 0 | |
| 157 // y_scale = (1600 - 1) / (2428 - 1) | |
| 158 // y_offset = 0 | |
| 159 // See DisplayControllerTest.TouchCTMExtendedMode for the test. | |
| 160 ui::TouchCTM GetExtendedModeTouchCTM( | |
| 161 const internal::DisplayInfo& touch_display, | |
| 162 const internal::DisplayInfo& second_display) { | |
| 163 ui::TouchCTM ctm; | |
| 164 float width = touch_display.bounds_in_native().width(); | |
| 165 float height = touch_display.bounds_in_native().height(); | |
| 166 // float origin_x = touch_display.bounds_in_native().origin().x(); | |
| 167 // float origin_y = touch_display.bounds_in_native().origin().y(); | |
| 168 float framebuffer_width = std::max<int>( | |
| 169 width, second_display.bounds_in_native().width()); | |
| 170 float framebuffer_height = | |
| 171 height + chromeos::OutputConfigurator::kVerticalGap + | |
| 172 second_display.bounds_in_native().height(); | |
| 173 ctm.x_scale = (width - 1) / (framebuffer_width - 1); | |
| 174 ctm.x_offset = 0; | |
| 175 ctm.y_scale = (height -1) / (framebuffer_height - 1); | |
| 176 ctm.y_offset = 0; | |
| 177 return ctm; | |
| 178 } | |
| 179 | |
| 180 // This function computes the mirror mode TouchCTM for |touch_display|. | |
| 181 // When internal monitor is applied a resolution that does not have | |
| 182 // the same aspect ratio as its native resolution, there would be | |
| 183 // blank regions in the letterboxing/pillarboxing mode. | |
| 184 // The TouchCTM will make sure the touch events on the blank region | |
| 185 // have negative coordinates and touch events within the chrome region | |
| 186 // have the correct positive coordinates. | |
| 187 ui::TouchCTM GetMirrorModeTouchCTM( | |
| 188 const internal::DisplayInfo& touch_display) { | |
| 189 ui::TouchCTM ctm; | |
| 190 // For external monitor, assuming no letterboxing or pillarboxing | |
| 191 // and just use the default TouchCTM. | |
| 192 if (touch_display.id() != gfx::Display::InternalDisplayId()) | |
| 193 return ctm; | |
| 194 | |
| 195 float mirror_width = touch_display.bounds_in_native().width(); | |
| 196 float mirror_height = touch_display.bounds_in_native().height(); | |
| 197 float native_width = 0; | |
| 198 float native_height = 0; | |
| 199 | |
| 200 internal::DisplayMode native_mode; | |
| 201 std::vector<internal::DisplayMode> modes = touch_display.display_modes(); | |
| 202 for (size_t i = 0; i < modes.size(); i++) { | |
| 203 if (modes[i].native) { | |
| 204 native_width = modes[i].size.width(); | |
| 205 native_height = modes[i].size.height(); | |
| 206 break; | |
| 207 } | |
| 208 } | |
| 209 | |
| 210 if (native_height == 0.0 || mirror_height == 0.0 || | |
| 211 native_width == 0.0 || mirror_width == 0.0) | |
| 212 return ctm; | |
| 213 | |
| 214 float native_ar = static_cast<float>(native_width) / | |
| 215 static_cast<float>(native_height); | |
| 216 float mirror_ar = static_cast<float>(mirror_width) / | |
| 217 static_cast<float>(mirror_height); | |
| 218 | |
| 219 if (mirror_ar > native_ar) { // Letterboxing | |
| 220 ctm.x_scale = 1.0; | |
| 221 ctm.x_offset = 0.0; | |
| 222 ctm.y_scale = mirror_ar / native_ar; | |
| 223 ctm.y_offset = (1.0 / mirror_ar - 1.0 / native_ar) * 0.5 * mirror_width; | |
| 224 return ctm; | |
| 225 } | |
| 226 | |
| 227 if (native_ar > mirror_ar) { // Pillarboxing | |
| 228 ctm.y_scale = 1.0; | |
| 229 ctm.y_offset = 0.0; | |
| 230 ctm.x_scale = native_ar / mirror_ar; | |
| 231 ctm.x_offset = (mirror_ar - native_ar) * 0.5 * mirror_height; | |
| 232 return ctm; | |
| 233 } | |
| 234 | |
| 235 return ctm; // Same aspect ratio - return identity | |
| 236 } | |
| 237 #endif // defined(OS_CHROMEOS) && defined(USE_X11) | |
| 238 | |
| 135 } // namespace | 239 } // namespace |
| 136 | 240 |
| 137 namespace internal { | 241 namespace internal { |
| 138 | 242 |
| 139 // A utility class to store/restore focused/active window | 243 // A utility class to store/restore focused/active window |
| 140 // when the display configuration has changed. | 244 // when the display configuration has changed. |
| 141 class FocusActivationStore { | 245 class FocusActivationStore { |
| 142 public: | 246 public: |
| 143 FocusActivationStore() | 247 FocusActivationStore() |
| 144 : activation_client_(NULL), | 248 : activation_client_(NULL), |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 DCHECK(controller); | 377 DCHECK(controller); |
| 274 delete controller; | 378 delete controller; |
| 275 } | 379 } |
| 276 } | 380 } |
| 277 | 381 |
| 278 void DisplayController::InitPrimaryDisplay() { | 382 void DisplayController::InitPrimaryDisplay() { |
| 279 const gfx::Display& primary_candidate = | 383 const gfx::Display& primary_candidate = |
| 280 GetDisplayManager()->GetPrimaryDisplayCandidate(); | 384 GetDisplayManager()->GetPrimaryDisplayCandidate(); |
| 281 primary_display_id = primary_candidate.id(); | 385 primary_display_id = primary_candidate.id(); |
| 282 AddWindowTreeHostForDisplay(primary_candidate); | 386 AddWindowTreeHostForDisplay(primary_candidate); |
| 387 UpdateTouchCTM(); | |
| 283 } | 388 } |
| 284 | 389 |
| 285 void DisplayController::InitSecondaryDisplays() { | 390 void DisplayController::InitSecondaryDisplays() { |
| 286 internal::DisplayManager* display_manager = GetDisplayManager(); | 391 internal::DisplayManager* display_manager = GetDisplayManager(); |
| 287 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { | 392 for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) { |
| 288 const gfx::Display& display = display_manager->GetDisplayAt(i); | 393 const gfx::Display& display = display_manager->GetDisplayAt(i); |
| 289 if (primary_display_id != display.id()) { | 394 if (primary_display_id != display.id()) { |
| 290 aura::WindowTreeHost* host = AddWindowTreeHostForDisplay(display); | 395 aura::WindowTreeHost* host = AddWindowTreeHostForDisplay(display); |
| 291 internal::RootWindowController::CreateForSecondaryDisplay(host); | 396 internal::RootWindowController::CreateForSecondaryDisplay(host); |
| 292 } | 397 } |
| 293 } | 398 } |
| 294 UpdateHostWindowNames(); | 399 UpdateHostWindowNames(); |
| 400 UpdateTouchCTM(); | |
| 295 } | 401 } |
| 296 | 402 |
| 297 void DisplayController::AddObserver(Observer* observer) { | 403 void DisplayController::AddObserver(Observer* observer) { |
| 298 observers_.AddObserver(observer); | 404 observers_.AddObserver(observer); |
| 299 } | 405 } |
| 300 | 406 |
| 301 void DisplayController::RemoveObserver(Observer* observer) { | 407 void DisplayController::RemoveObserver(Observer* observer) { |
| 302 observers_.RemoveObserver(observer); | 408 observers_.RemoveObserver(observer); |
| 303 } | 409 } |
| 304 | 410 |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 682 primary_id == gfx::Display::kInvalidDisplayID ? | 788 primary_id == gfx::Display::kInvalidDisplayID ? |
| 683 pair.first : primary_id); | 789 pair.first : primary_id); |
| 684 // Update the primary_id in case the above call is | 790 // Update the primary_id in case the above call is |
| 685 // ignored. Happens when a) default layout's primary id | 791 // ignored. Happens when a) default layout's primary id |
| 686 // doesn't exist, or b) the primary_id has already been | 792 // doesn't exist, or b) the primary_id has already been |
| 687 // set to the same and didn't update it. | 793 // set to the same and didn't update it. |
| 688 layout_store->UpdatePrimaryDisplayId( | 794 layout_store->UpdatePrimaryDisplayId( |
| 689 pair, Shell::GetScreen()->GetPrimaryDisplay().id()); | 795 pair, Shell::GetScreen()->GetPrimaryDisplay().id()); |
| 690 } | 796 } |
| 691 } | 797 } |
| 692 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanged()); | 798 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanged()); |
|
oshima
2014/03/13 20:43:54
Looks like new code don't have to be in DisplayCon
Yufeng Shen (Slow to review)
2014/03/13 20:55:46
but is OnDisplayConfigurationChanged() is always c
oshima
2014/03/13 21:34:48
It's always called when display configuration chan
| |
| 693 UpdateHostWindowNames(); | 799 UpdateHostWindowNames(); |
| 694 EnsurePointerInDisplays(); | 800 EnsurePointerInDisplays(); |
| 801 UpdateTouchCTM(); | |
| 802 } | |
| 803 | |
| 804 void DisplayController::UpdateTouchCTM() { | |
| 805 #if defined(OS_CHROMEOS) && defined(USE_X11) | |
| 806 ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); | |
| 807 device_manager->ClearTouchCTM(); | |
| 808 device_manager->ClearTouchDeviceToDisplayMap(); | |
| 809 | |
| 810 // Display IDs and DisplayInfo for mirror or extended mode. | |
| 811 int64 display1_id = gfx::Display::kInvalidDisplayID; | |
| 812 int64 display2_id = gfx::Display::kInvalidDisplayID; | |
| 813 internal::DisplayInfo display1; | |
| 814 internal::DisplayInfo display2; | |
| 815 // Display ID and DisplayInfo for single display mode. | |
| 816 int64 single_display_id = gfx::Display::kInvalidDisplayID; | |
| 817 internal::DisplayInfo single_display; | |
| 818 | |
| 819 ui::OutputState output_state = | |
| 820 Shell::GetInstance()->output_configurator()->output_state(); | |
| 821 if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR || | |
| 822 output_state == ui::OUTPUT_STATE_DUAL_EXTENDED) { | |
| 823 DisplayIdPair id_pair = GetDisplayManager()->GetCurrentDisplayIdPair(); | |
| 824 display1_id = id_pair.first; | |
| 825 display2_id = id_pair.second; | |
| 826 if (display1_id == gfx::Display::kInvalidDisplayID || | |
| 827 display2_id == gfx::Display::kInvalidDisplayID) | |
| 828 return; | |
| 829 display1 = GetDisplayManager()->GetDisplayInfo(display1_id); | |
| 830 display2 = GetDisplayManager()->GetDisplayInfo(display2_id); | |
| 831 } else { | |
| 832 single_display_id = GetDisplayManager()->first_display_id(); | |
| 833 if (single_display_id == gfx::Display::kInvalidDisplayID) | |
| 834 return; | |
| 835 single_display = GetDisplayManager()->GetDisplayInfo(single_display_id); | |
| 836 } | |
| 837 | |
| 838 if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR) { | |
| 839 std::map<int64, aura::Window*>::iterator it = root_windows_.begin(); | |
| 840 // In mirror mode, both displays share the same root window so | |
| 841 // both display ids are associated with the root window. | |
| 842 for (; it != root_windows_.end(); it++) | |
| 843 it->second->GetHost()->UpdateDisplayID(display1_id, display2_id); | |
| 844 // Update the associated display id and TouchCTM in device manager | |
| 845 // if the display is a touch device. | |
| 846 if (display1.touch_device_id() != 0) { | |
| 847 device_manager->MapTouchDeviceToDisplay(display1.touch_device_id(), | |
| 848 display1.id()); | |
| 849 device_manager->SetTouchCTM(display1.touch_device_id(), | |
| 850 GetMirrorModeTouchCTM(display1)); | |
| 851 } | |
| 852 if (display2.touch_device_id() != 0) { | |
| 853 device_manager->MapTouchDeviceToDisplay(display2.touch_device_id(), | |
| 854 display2.id()); | |
| 855 device_manager->SetTouchCTM(display2.touch_device_id(), | |
| 856 GetMirrorModeTouchCTM(display2)); | |
| 857 } | |
| 858 return; | |
| 859 } | |
| 860 | |
| 861 if (output_state == ui::OUTPUT_STATE_DUAL_EXTENDED) { | |
| 862 std::map<int64, aura::Window*>::iterator it = root_windows_.begin(); | |
| 863 // In extended mode, each display has one associated root window. | |
| 864 for (; it != root_windows_.end(); it++) { | |
| 865 if (it->first == display1_id) { | |
| 866 it->second->GetHost()->UpdateDisplayID(display1_id, | |
| 867 gfx::Display::kInvalidDisplayID); | |
| 868 } else if (it->first == display2_id) { | |
| 869 it->second->GetHost()->UpdateDisplayID(display2_id, | |
| 870 gfx::Display::kInvalidDisplayID); | |
| 871 } | |
| 872 } | |
| 873 // Update the associated display id and TouchCTM in device manager | |
| 874 // if the display is a touch device. | |
| 875 if (display1.touch_device_id() != 0) { | |
| 876 device_manager->MapTouchDeviceToDisplay(display1.touch_device_id(), | |
| 877 display1.id()); | |
| 878 device_manager->SetTouchCTM(display1.touch_device_id(), | |
| 879 GetExtendedModeTouchCTM(display1, display2)); | |
| 880 } | |
| 881 if (display2.touch_device_id() != 0) { | |
| 882 device_manager->MapTouchDeviceToDisplay(display2.touch_device_id(), | |
| 883 display2.id()); | |
| 884 device_manager->SetTouchCTM(display2.touch_device_id(), | |
| 885 GetExtendedModeTouchCTM(display2, display1)); | |
| 886 } | |
| 887 return; | |
| 888 } | |
| 889 | |
| 890 // Single display mode. The root window has one associated display id. | |
| 891 std::map<int64, aura::Window*>::iterator it = root_windows_.begin(); | |
| 892 for (; it != root_windows_.end(); it++) { | |
| 893 if (it->first == single_display.id()) { | |
| 894 it->second->GetHost()->UpdateDisplayID(single_display.id(), | |
| 895 gfx::Display::kInvalidDisplayID); | |
| 896 } | |
| 897 } | |
| 898 // If the display is a touch display, we add a deafult TouchCTM to the | |
| 899 // according root window. | |
| 900 if (single_display.touch_device_id() != 0) { | |
| 901 device_manager->MapTouchDeviceToDisplay(single_display.touch_device_id(), | |
| 902 single_display.id()); | |
| 903 device_manager->SetTouchCTM(single_display.touch_device_id(), | |
| 904 ui::TouchCTM()); | |
| 905 } | |
| 906 #endif | |
| 695 } | 907 } |
| 696 | 908 |
| 697 aura::WindowTreeHost* DisplayController::AddWindowTreeHostForDisplay( | 909 aura::WindowTreeHost* DisplayController::AddWindowTreeHostForDisplay( |
| 698 const gfx::Display& display) { | 910 const gfx::Display& display) { |
| 699 static int host_count = 0; | 911 static int host_count = 0; |
| 700 const internal::DisplayInfo& display_info = | 912 const internal::DisplayInfo& display_info = |
| 701 GetDisplayManager()->GetDisplayInfo(display.id()); | 913 GetDisplayManager()->GetDisplayInfo(display.id()); |
| 702 const gfx::Rect& bounds_in_native = display_info.bounds_in_native(); | 914 const gfx::Rect& bounds_in_native = display_info.bounds_in_native(); |
| 703 aura::WindowTreeHost* host = | 915 aura::WindowTreeHost* host = |
| 704 Shell::GetInstance()->window_tree_host_factory()->CreateWindowTreeHost( | 916 Shell::GetInstance()->window_tree_host_factory()->CreateWindowTreeHost( |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 742 std::string name = | 954 std::string name = |
| 743 root_windows[i] == primary ? "aura_root_0" : "aura_root_x"; | 955 root_windows[i] == primary ? "aura_root_0" : "aura_root_x"; |
| 744 gfx::AcceleratedWidget xwindow = | 956 gfx::AcceleratedWidget xwindow = |
| 745 root_windows[i]->GetHost()->GetAcceleratedWidget(); | 957 root_windows[i]->GetHost()->GetAcceleratedWidget(); |
| 746 XStoreName(gfx::GetXDisplay(), xwindow, name.c_str()); | 958 XStoreName(gfx::GetXDisplay(), xwindow, name.c_str()); |
| 747 } | 959 } |
| 748 #endif | 960 #endif |
| 749 } | 961 } |
| 750 | 962 |
| 751 } // namespace ash | 963 } // namespace ash |
| OLD | NEW |