| Index: ash/display/display_controller.cc
|
| diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc
|
| index 138340037ebd9b0bf24d89358ad230a1862c446e..cd9a59aac0c22edb3089cf7dac45213f19480b2f 100644
|
| --- a/ash/display/display_controller.cc
|
| +++ b/ash/display/display_controller.cc
|
| @@ -29,6 +29,7 @@
|
| #include "ui/aura/client/focus_client.h"
|
| #include "ui/aura/client/screen_position_client.h"
|
| #include "ui/aura/root_window_transformer.h"
|
| +#include "ui/aura/touch_ctm.h"
|
| #include "ui/aura/window.h"
|
| #include "ui/aura/window_event_dispatcher.h"
|
| #include "ui/aura/window_property.h"
|
| @@ -133,6 +134,106 @@ void SetDisplayPropertiesOnHostWindow(aura::WindowEventDispatcher* dispatcher,
|
| }
|
| }
|
|
|
| +#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),
|
| +// So to compute CTM, 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 = 828
|
| +// See DisplayControllerTest.TouchCTMExtendedMode for the test.
|
| +aura::TouchCTM GetExtendedModeTouchCTM(
|
| + const internal::DisplayInfo& touch_display,
|
| + const internal::DisplayInfo& second_display) {
|
| + aura::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 = origin_x;
|
| + ctm.y_scale = (height -1) / (framebuffer_height - 1);
|
| + ctm.y_offset = origin_y;
|
| + 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.
|
| +aura::TouchCTM GetMirrorModeTouchCTM(
|
| + const internal::DisplayInfo& touch_display) {
|
| + aura::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
|
| +
|
| } // namespace
|
|
|
| namespace internal {
|
| @@ -281,6 +382,7 @@ void DisplayController::InitPrimaryDisplay() {
|
| GetDisplayManager()->GetPrimaryDisplayCandidate();
|
| primary_display_id = primary_candidate.id();
|
| AddRootWindowForDisplay(primary_candidate);
|
| + UpdateTouchCTM();
|
| }
|
|
|
| void DisplayController::InitSecondaryDisplays() {
|
| @@ -294,6 +396,7 @@ void DisplayController::InitSecondaryDisplays() {
|
| }
|
| }
|
| UpdateHostWindowNames();
|
| + UpdateTouchCTM();
|
| }
|
|
|
| void DisplayController::AddObserver(Observer* observer) {
|
| @@ -701,6 +804,80 @@ void DisplayController::PostDisplayConfigurationChange() {
|
| FOR_EACH_OBSERVER(Observer, observers_, OnDisplayConfigurationChanged());
|
| UpdateHostWindowNames();
|
| EnsurePointerInDisplays();
|
| + UpdateTouchCTM();
|
| +}
|
| +
|
| +void DisplayController::UpdateTouchCTM() {
|
| +#if defined(OS_CHROMEOS) && defined(USE_X11)
|
| + // Clear all the old TouchCTM on all the root windows.
|
| + std::map<int64, aura::Window*>::iterator it = root_windows_.begin();
|
| + for (; it != root_windows_.end(); it++)
|
| + it->second->GetDispatcher()->host()->ClearTouchCTM();
|
| +
|
| + 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();
|
| + internal::DisplayInfo display1 =
|
| + GetDisplayManager()->GetDisplayInfo(id_pair.first);
|
| + internal::DisplayInfo display2 =
|
| + GetDisplayManager()->GetDisplayInfo(id_pair.second);
|
| + // For mirror mode, there is one root window shared by two displays.
|
| + // We add the TouchCTM of the touch display to the only one root window.
|
| + // For extended mode, there is one root window for each display.
|
| + // We add the TouchCTM of the touch display to the according root window.
|
| + if (display1.id() != gfx::Display::kInvalidDisplayID &&
|
| + display1.touch_device_id() != 0) {
|
| + std::map<int64, aura::Window*>::iterator it = root_windows_.begin();
|
| + for (; it != root_windows_.end(); it++) {
|
| + if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR) {
|
| + it->second->GetDispatcher()->host()->SetTouchCTM(
|
| + display1.touch_device_id(),
|
| + GetMirrorModeTouchCTM(display1));
|
| + } else if (output_state == ui::OUTPUT_STATE_DUAL_EXTENDED &&
|
| + it->first == display1.id()) {
|
| + it->second->GetDispatcher()->host()->SetTouchCTM(
|
| + display1.touch_device_id(),
|
| + GetExtendedModeTouchCTM(display1, display2));
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (display2.id() != gfx::Display::kInvalidDisplayID &&
|
| + display2.touch_device_id() != 0) {
|
| + std::map<int64, aura::Window*>::iterator it = root_windows_.begin();
|
| + for (; it != root_windows_.end(); it++) {
|
| + if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR) {
|
| + it->second->GetDispatcher()->host()->SetTouchCTM(
|
| + display2.touch_device_id(),
|
| + GetMirrorModeTouchCTM(display2));
|
| + } else if (output_state == ui::OUTPUT_STATE_DUAL_EXTENDED &&
|
| + it->first == display2.id()) {
|
| + it->second->GetDispatcher()->host()->SetTouchCTM(
|
| + display2.touch_device_id(),
|
| + GetExtendedModeTouchCTM(display2, display1));
|
| + }
|
| + }
|
| + }
|
| + } else {
|
| + // Single display mode. If the display is a touch display, we add a deafult
|
| + // TouchCTM to the according root window.
|
| + int64 display_id = GetDisplayManager()->first_display_id();
|
| + if (display_id != gfx::Display::kInvalidDisplayID) {
|
| + internal::DisplayInfo display =
|
| + GetDisplayManager()->GetDisplayInfo(display_id);
|
| + std::map<int64, aura::Window*>::iterator it = root_windows_.begin();
|
| + for (; it != root_windows_.end(); it++) {
|
| + if (it->first == display_id && display.touch_device_id() != 0) {
|
| + it->second->GetDispatcher()->host()->SetTouchCTM(
|
| + display.touch_device_id(),
|
| + aura::TouchCTM());
|
| + }
|
| + }
|
| + }
|
| + }
|
| +#endif
|
| }
|
|
|
| aura::WindowEventDispatcher* DisplayController::AddRootWindowForDisplay(
|
|
|