Index: ash/display/display_controller.cc |
diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc |
index 7a3d786b0d69d5016040165ded1126aa468c6f85..39b788a58d6fc99aefceda591ed3520f4275eb93 100644 |
--- a/ash/display/display_controller.cc |
+++ b/ash/display/display_controller.cc |
@@ -35,6 +35,7 @@ |
#include "ui/aura/window_tracker.h" |
#include "ui/compositor/compositor.h" |
#include "ui/compositor/compositor_vsync_manager.h" |
+#include "ui/events/touch_ctm.h" |
#include "ui/gfx/display.h" |
#include "ui/gfx/screen.h" |
@@ -45,6 +46,7 @@ |
#include "ash/display/output_configurator_animation.h" |
#include "chromeos/display/output_configurator.h" |
#include "ui/base/x/x11_util.h" |
+#include "ui/events/x/device_data_manager.h" |
#include "ui/gfx/x/x11_types.h" |
// Including this at the bottom to avoid other |
@@ -132,6 +134,108 @@ void SetDisplayPropertiesOnHost(aura::WindowTreeHost* host, |
} |
} |
+#if defined(OS_CHROMEOS) && defined(USE_X11) |
+// This function computes the extended mode TouchCTM for |touch_display|. |
+// An example of how to calculate the extended CTM. |
+// Suppose we have 2 monitors, the first one has size 1366 x 768. |
+// The second one has size 2560 x 1600 |
+// The total size of framebuffer is 2560 x 2428 |
+// where 2428 = 768 + 60 (hidden gap) + 1600 |
+// and the sceond monitor is translated to Point (0, 828) in the |
+// framebuffer. |
+// X will first map input event location to [0, 2560) x [0, 2428), |
+// Then the TouchCTM should map touch events from framebuffer space |
+// to root window space. |
+// For monitor1, we have |
+// x_scale = (1366 - 1) / (2560 - 1) |
+// x_offset = 0 |
+// y_scale = (768 - 1) / (2428 - 1) |
+// y_offset = 0 |
+// For Monitor 2, we have |
+// x_scale = (2560 - 1) / (2560 - 1) |
+// x_offset = 0 |
+// y_scale = (1600 - 1) / (2428 - 1) |
+// y_offset = 0 |
+// See DisplayControllerTest.TouchCTMExtendedMode for the test. |
+ui::TouchCTM GetExtendedModeTouchCTM( |
+ const internal::DisplayInfo& touch_display, |
+ const internal::DisplayInfo& second_display) { |
+ ui::TouchCTM ctm; |
+ float width = touch_display.bounds_in_native().width(); |
+ float height = touch_display.bounds_in_native().height(); |
+ // float origin_x = touch_display.bounds_in_native().origin().x(); |
+ // float origin_y = touch_display.bounds_in_native().origin().y(); |
+ float framebuffer_width = std::max<int>( |
+ width, second_display.bounds_in_native().width()); |
+ float framebuffer_height = |
+ height + chromeos::OutputConfigurator::kVerticalGap + |
+ second_display.bounds_in_native().height(); |
+ ctm.x_scale = (width - 1) / (framebuffer_width - 1); |
+ ctm.x_offset = 0; |
+ ctm.y_scale = (height -1) / (framebuffer_height - 1); |
+ ctm.y_offset = 0; |
+ return ctm; |
+} |
+ |
+// This function computes the mirror mode TouchCTM for |touch_display|. |
+// When internal monitor is applied a resolution that does not have |
+// the same aspect ratio as its native resolution, there would be |
+// blank regions in the letterboxing/pillarboxing mode. |
+// The TouchCTM will make sure the touch events on the blank region |
+// have negative coordinates and touch events within the chrome region |
+// have the correct positive coordinates. |
+ui::TouchCTM GetMirrorModeTouchCTM( |
+ const internal::DisplayInfo& touch_display) { |
+ ui::TouchCTM ctm; |
+ // For external monitor, assuming no letterboxing or pillarboxing |
+ // and just use the default TouchCTM. |
+ if (touch_display.id() != gfx::Display::InternalDisplayId()) |
+ return ctm; |
+ |
+ float mirror_width = touch_display.bounds_in_native().width(); |
+ float mirror_height = touch_display.bounds_in_native().height(); |
+ float native_width = 0; |
+ float native_height = 0; |
+ |
+ internal::DisplayMode native_mode; |
+ std::vector<internal::DisplayMode> modes = touch_display.display_modes(); |
+ for (size_t i = 0; i < modes.size(); i++) { |
+ if (modes[i].native) { |
+ native_width = modes[i].size.width(); |
+ native_height = modes[i].size.height(); |
+ break; |
+ } |
+ } |
+ |
+ if (native_height == 0.0 || mirror_height == 0.0 || |
+ native_width == 0.0 || mirror_width == 0.0) |
+ return ctm; |
+ |
+ float native_ar = static_cast<float>(native_width) / |
+ static_cast<float>(native_height); |
+ float mirror_ar = static_cast<float>(mirror_width) / |
+ static_cast<float>(mirror_height); |
+ |
+ if (mirror_ar > native_ar) { // Letterboxing |
+ ctm.x_scale = 1.0; |
+ ctm.x_offset = 0.0; |
+ ctm.y_scale = mirror_ar / native_ar; |
+ ctm.y_offset = (1.0 / mirror_ar - 1.0 / native_ar) * 0.5 * mirror_width; |
+ return ctm; |
+ } |
+ |
+ if (native_ar > mirror_ar) { // Pillarboxing |
+ ctm.y_scale = 1.0; |
+ ctm.y_offset = 0.0; |
+ ctm.x_scale = native_ar / mirror_ar; |
+ ctm.x_offset = (mirror_ar - native_ar) * 0.5 * mirror_height; |
+ return ctm; |
+ } |
+ |
+ return ctm; // Same aspect ratio - return identity |
+} |
+#endif // defined(OS_CHROMEOS) && defined(USE_X11) |
+ |
} // namespace |
namespace internal { |
@@ -280,6 +384,7 @@ void DisplayController::InitPrimaryDisplay() { |
GetDisplayManager()->GetPrimaryDisplayCandidate(); |
primary_display_id = primary_candidate.id(); |
AddWindowTreeHostForDisplay(primary_candidate); |
+ UpdateTouchCTM(); |
} |
void DisplayController::InitSecondaryDisplays() { |
@@ -292,6 +397,7 @@ void DisplayController::InitSecondaryDisplays() { |
} |
} |
UpdateHostWindowNames(); |
+ UpdateTouchCTM(); |
} |
void DisplayController::AddObserver(Observer* observer) { |
@@ -692,6 +798,112 @@ void DisplayController::PostDisplayConfigurationChange() { |
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
|
UpdateHostWindowNames(); |
EnsurePointerInDisplays(); |
+ UpdateTouchCTM(); |
+} |
+ |
+void DisplayController::UpdateTouchCTM() { |
+#if defined(OS_CHROMEOS) && defined(USE_X11) |
+ ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
+ device_manager->ClearTouchCTM(); |
+ device_manager->ClearTouchDeviceToDisplayMap(); |
+ |
+ // Display IDs and DisplayInfo for mirror or extended mode. |
+ int64 display1_id = gfx::Display::kInvalidDisplayID; |
+ int64 display2_id = gfx::Display::kInvalidDisplayID; |
+ internal::DisplayInfo display1; |
+ internal::DisplayInfo display2; |
+ // Display ID and DisplayInfo for single display mode. |
+ int64 single_display_id = gfx::Display::kInvalidDisplayID; |
+ internal::DisplayInfo single_display; |
+ |
+ ui::OutputState output_state = |
+ Shell::GetInstance()->output_configurator()->output_state(); |
+ if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR || |
+ output_state == ui::OUTPUT_STATE_DUAL_EXTENDED) { |
+ DisplayIdPair id_pair = GetDisplayManager()->GetCurrentDisplayIdPair(); |
+ display1_id = id_pair.first; |
+ display2_id = id_pair.second; |
+ if (display1_id == gfx::Display::kInvalidDisplayID || |
+ display2_id == gfx::Display::kInvalidDisplayID) |
+ return; |
+ display1 = GetDisplayManager()->GetDisplayInfo(display1_id); |
+ display2 = GetDisplayManager()->GetDisplayInfo(display2_id); |
+ } else { |
+ single_display_id = GetDisplayManager()->first_display_id(); |
+ if (single_display_id == gfx::Display::kInvalidDisplayID) |
+ return; |
+ single_display = GetDisplayManager()->GetDisplayInfo(single_display_id); |
+ } |
+ |
+ if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR) { |
+ std::map<int64, aura::Window*>::iterator it = root_windows_.begin(); |
+ // In mirror mode, both displays share the same root window so |
+ // both display ids are associated with the root window. |
+ for (; it != root_windows_.end(); it++) |
+ it->second->GetHost()->UpdateDisplayID(display1_id, display2_id); |
+ // Update the associated display id and TouchCTM in device manager |
+ // if the display is a touch device. |
+ if (display1.touch_device_id() != 0) { |
+ device_manager->MapTouchDeviceToDisplay(display1.touch_device_id(), |
+ display1.id()); |
+ device_manager->SetTouchCTM(display1.touch_device_id(), |
+ GetMirrorModeTouchCTM(display1)); |
+ } |
+ if (display2.touch_device_id() != 0) { |
+ device_manager->MapTouchDeviceToDisplay(display2.touch_device_id(), |
+ display2.id()); |
+ device_manager->SetTouchCTM(display2.touch_device_id(), |
+ GetMirrorModeTouchCTM(display2)); |
+ } |
+ return; |
+ } |
+ |
+ if (output_state == ui::OUTPUT_STATE_DUAL_EXTENDED) { |
+ std::map<int64, aura::Window*>::iterator it = root_windows_.begin(); |
+ // In extended mode, each display has one associated root window. |
+ for (; it != root_windows_.end(); it++) { |
+ if (it->first == display1_id) { |
+ it->second->GetHost()->UpdateDisplayID(display1_id, |
+ gfx::Display::kInvalidDisplayID); |
+ } else if (it->first == display2_id) { |
+ it->second->GetHost()->UpdateDisplayID(display2_id, |
+ gfx::Display::kInvalidDisplayID); |
+ } |
+ } |
+ // Update the associated display id and TouchCTM in device manager |
+ // if the display is a touch device. |
+ if (display1.touch_device_id() != 0) { |
+ device_manager->MapTouchDeviceToDisplay(display1.touch_device_id(), |
+ display1.id()); |
+ device_manager->SetTouchCTM(display1.touch_device_id(), |
+ GetExtendedModeTouchCTM(display1, display2)); |
+ } |
+ if (display2.touch_device_id() != 0) { |
+ device_manager->MapTouchDeviceToDisplay(display2.touch_device_id(), |
+ display2.id()); |
+ device_manager->SetTouchCTM(display2.touch_device_id(), |
+ GetExtendedModeTouchCTM(display2, display1)); |
+ } |
+ return; |
+ } |
+ |
+ // Single display mode. The root window has one associated display id. |
+ std::map<int64, aura::Window*>::iterator it = root_windows_.begin(); |
+ for (; it != root_windows_.end(); it++) { |
+ if (it->first == single_display.id()) { |
+ it->second->GetHost()->UpdateDisplayID(single_display.id(), |
+ gfx::Display::kInvalidDisplayID); |
+ } |
+ } |
+ // If the display is a touch display, we add a deafult TouchCTM to the |
+ // according root window. |
+ if (single_display.touch_device_id() != 0) { |
+ device_manager->MapTouchDeviceToDisplay(single_display.touch_device_id(), |
+ single_display.id()); |
+ device_manager->SetTouchCTM(single_display.touch_device_id(), |
+ ui::TouchCTM()); |
+ } |
+#endif |
} |
aura::WindowTreeHost* DisplayController::AddWindowTreeHostForDisplay( |