Home | History | Annotate | Download | only in aura
      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 "ui/aura/remote_root_window_host_win.h"
      6 
      7 #include <windows.h>
      8 
      9 #include <algorithm>
     10 
     11 #include "base/message_loop/message_loop.h"
     12 #include "ipc/ipc_message.h"
     13 #include "ipc/ipc_sender.h"
     14 #include "ui/aura/client/capture_client.h"
     15 #include "ui/aura/client/cursor_client.h"
     16 #include "ui/aura/root_window.h"
     17 #include "ui/base/cursor/cursor_loader_win.h"
     18 #include "ui/base/events/event_utils.h"
     19 #include "ui/base/keycodes/keyboard_code_conversion_win.h"
     20 #include "ui/base/view_prop.h"
     21 #include "ui/gfx/insets.h"
     22 #include "ui/metro_viewer/metro_viewer_messages.h"
     23 
     24 namespace aura {
     25 
     26 namespace {
     27 
     28 const char* kRootWindowHostWinKey = "__AURA_REMOTE_ROOT_WINDOW_HOST_WIN__";
     29 
     30 // Sets the keystate for the virtual key passed in to down or up.
     31 void SetKeyState(uint8* key_states, bool key_down, uint32 virtual_key_code) {
     32   DCHECK(key_states);
     33 
     34   if (key_down)
     35     key_states[virtual_key_code] |= 0x80;
     36   else
     37     key_states[virtual_key_code] &= 0x7F;
     38 }
     39 
     40 // Sets the keyboard states for the Shift/Control/Alt/Caps lock keys.
     41 void SetVirtualKeyStates(uint32 flags) {
     42   uint8 keyboard_state[256] = {0};
     43   ::GetKeyboardState(keyboard_state);
     44 
     45   SetKeyState(keyboard_state, !!(flags & ui::EF_SHIFT_DOWN), VK_SHIFT);
     46   SetKeyState(keyboard_state, !!(flags & ui::EF_CONTROL_DOWN), VK_CONTROL);
     47   SetKeyState(keyboard_state, !!(flags & ui::EF_ALT_DOWN), VK_MENU);
     48   SetKeyState(keyboard_state, !!(flags & ui::EF_CAPS_LOCK_DOWN), VK_CAPITAL);
     49 
     50   ::SetKeyboardState(keyboard_state);
     51 }
     52 
     53 }  // namespace
     54 
     55 void HandleOpenFile(const base::string16& title,
     56                     const base::FilePath& default_path,
     57                     const base::string16& filter,
     58                     const OpenFileCompletion& on_success,
     59                     const FileSelectionCanceled& on_failure) {
     60   DCHECK(aura::RemoteRootWindowHostWin::Instance());
     61   aura::RemoteRootWindowHostWin::Instance()->HandleOpenFile(title,
     62                                                             default_path,
     63                                                             filter,
     64                                                             on_success,
     65                                                             on_failure);
     66 }
     67 
     68 void HandleOpenMultipleFiles(const base::string16& title,
     69                              const base::FilePath& default_path,
     70                              const base::string16& filter,
     71                              const OpenMultipleFilesCompletion& on_success,
     72                              const FileSelectionCanceled& on_failure) {
     73   DCHECK(aura::RemoteRootWindowHostWin::Instance());
     74   aura::RemoteRootWindowHostWin::Instance()->HandleOpenMultipleFiles(
     75       title,
     76       default_path,
     77       filter,
     78       on_success,
     79       on_failure);
     80 }
     81 
     82 void HandleSaveFile(const base::string16& title,
     83                     const base::FilePath& default_path,
     84                     const base::string16& filter,
     85                     int filter_index,
     86                     const base::string16& default_extension,
     87                     const SaveFileCompletion& on_success,
     88                     const FileSelectionCanceled& on_failure) {
     89   DCHECK(aura::RemoteRootWindowHostWin::Instance());
     90   aura::RemoteRootWindowHostWin::Instance()->HandleSaveFile(title,
     91                                                             default_path,
     92                                                             filter,
     93                                                             filter_index,
     94                                                             default_extension,
     95                                                             on_success,
     96                                                             on_failure);
     97 }
     98 
     99 void HandleSelectFolder(const base::string16& title,
    100                         const SelectFolderCompletion& on_success,
    101                         const FileSelectionCanceled& on_failure) {
    102   DCHECK(aura::RemoteRootWindowHostWin::Instance());
    103   aura::RemoteRootWindowHostWin::Instance()->HandleSelectFolder(title,
    104                                                                 on_success,
    105                                                                 on_failure);
    106 }
    107 
    108 RemoteRootWindowHostWin* g_instance = NULL;
    109 
    110 RemoteRootWindowHostWin* RemoteRootWindowHostWin::Instance() {
    111   return g_instance;
    112 }
    113 
    114 RemoteRootWindowHostWin* RemoteRootWindowHostWin::Create(
    115     const gfx::Rect& bounds) {
    116   g_instance = new RemoteRootWindowHostWin(bounds);
    117   return g_instance;
    118 }
    119 
    120 RemoteRootWindowHostWin::RemoteRootWindowHostWin(const gfx::Rect& bounds)
    121     : delegate_(NULL),
    122       host_(NULL),
    123       ignore_mouse_moves_until_set_cursor_ack_(false) {
    124   prop_.reset(new ui::ViewProp(NULL, kRootWindowHostWinKey, this));
    125 }
    126 
    127 RemoteRootWindowHostWin::~RemoteRootWindowHostWin() {
    128 }
    129 
    130 void RemoteRootWindowHostWin::Connected(IPC::Sender* host) {
    131   CHECK(host_ == NULL);
    132   host_ = host;
    133 }
    134 
    135 void RemoteRootWindowHostWin::Disconnected() {
    136   CHECK(host_ != NULL);
    137   host_ = NULL;
    138 }
    139 
    140 bool RemoteRootWindowHostWin::OnMessageReceived(const IPC::Message& message) {
    141   bool handled = true;
    142   IPC_BEGIN_MESSAGE_MAP(RemoteRootWindowHostWin, message)
    143     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseMoved, OnMouseMoved)
    144     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MouseButton, OnMouseButton)
    145     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyDown, OnKeyDown)
    146     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_KeyUp, OnKeyUp)
    147     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_Character, OnChar)
    148     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_VisibilityChanged,
    149                         OnVisibilityChanged)
    150     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchDown,
    151                         OnTouchDown)
    152     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchUp,
    153                         OnTouchUp)
    154     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_TouchMoved,
    155                         OnTouchMoved)
    156     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileSaveAsDone,
    157                         OnFileSaveAsDone)
    158     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_FileOpenDone,
    159                         OnFileOpenDone)
    160     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_MultiFileOpenDone,
    161                         OnMultiFileOpenDone)
    162     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SelectFolderDone,
    163                         OnSelectFolderDone)
    164     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowActivated,
    165                         OnWindowActivated)
    166     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_SetCursorPosAck,
    167                         OnSetCursorPosAck)
    168     IPC_MESSAGE_HANDLER(MetroViewerHostMsg_WindowSizeChanged,
    169                         OnWindowSizeChanged)
    170     IPC_MESSAGE_UNHANDLED(handled = false)
    171   IPC_END_MESSAGE_MAP()
    172   return handled;
    173 }
    174 
    175 void RemoteRootWindowHostWin::HandleOpenFile(
    176     const base::string16& title,
    177     const base::FilePath& default_path,
    178     const base::string16& filter,
    179     const OpenFileCompletion& on_success,
    180     const FileSelectionCanceled& on_failure) {
    181   if (!host_)
    182     return;
    183 
    184   // Can only have one of these operations in flight.
    185   DCHECK(file_open_completion_callback_.is_null());
    186   DCHECK(failure_callback_.is_null());
    187 
    188   file_open_completion_callback_ = on_success;
    189   failure_callback_ = on_failure;
    190 
    191   host_->Send(new MetroViewerHostMsg_DisplayFileOpen(title,
    192                                                      filter,
    193                                                      default_path,
    194                                                      false));
    195 }
    196 
    197 void RemoteRootWindowHostWin::HandleOpenMultipleFiles(
    198     const base::string16& title,
    199     const base::FilePath& default_path,
    200     const base::string16& filter,
    201     const OpenMultipleFilesCompletion& on_success,
    202     const FileSelectionCanceled& on_failure) {
    203   if (!host_)
    204     return;
    205 
    206   // Can only have one of these operations in flight.
    207   DCHECK(multi_file_open_completion_callback_.is_null());
    208   DCHECK(failure_callback_.is_null());
    209   multi_file_open_completion_callback_ = on_success;
    210   failure_callback_ = on_failure;
    211 
    212   host_->Send(new MetroViewerHostMsg_DisplayFileOpen(title,
    213                                                      filter,
    214                                                      default_path,
    215                                                      true));
    216 }
    217 
    218 void RemoteRootWindowHostWin::HandleSaveFile(
    219     const base::string16& title,
    220     const base::FilePath& default_path,
    221     const base::string16& filter,
    222     int filter_index,
    223     const base::string16& default_extension,
    224     const SaveFileCompletion& on_success,
    225     const FileSelectionCanceled& on_failure) {
    226   if (!host_)
    227     return;
    228 
    229   MetroViewerHostMsg_SaveAsDialogParams params;
    230   params.title = title;
    231   params.default_extension = default_extension;
    232   params.filter = filter;
    233   params.filter_index = filter_index;
    234   params.suggested_name = default_path;
    235 
    236   // Can only have one of these operations in flight.
    237   DCHECK(file_saveas_completion_callback_.is_null());
    238   DCHECK(failure_callback_.is_null());
    239   file_saveas_completion_callback_ = on_success;
    240   failure_callback_ = on_failure;
    241 
    242   host_->Send(new MetroViewerHostMsg_DisplayFileSaveAs(params));
    243 }
    244 
    245 void RemoteRootWindowHostWin::HandleSelectFolder(
    246     const base::string16& title,
    247     const SelectFolderCompletion& on_success,
    248     const FileSelectionCanceled& on_failure) {
    249   if (!host_)
    250     return;
    251 
    252   // Can only have one of these operations in flight.
    253   DCHECK(select_folder_completion_callback_.is_null());
    254   DCHECK(failure_callback_.is_null());
    255   select_folder_completion_callback_ = on_success;
    256   failure_callback_ = on_failure;
    257 
    258   host_->Send(new MetroViewerHostMsg_DisplaySelectFolder(title));
    259 }
    260 
    261 Window* RemoteRootWindowHostWin::GetAshWindow() {
    262   return GetRootWindow();
    263 }
    264 
    265 void RemoteRootWindowHostWin::SetDelegate(RootWindowHostDelegate* delegate) {
    266   delegate_ = delegate;
    267 }
    268 
    269 RootWindow* RemoteRootWindowHostWin::GetRootWindow() {
    270   return delegate_->AsRootWindow();
    271 }
    272 
    273 gfx::AcceleratedWidget RemoteRootWindowHostWin::GetAcceleratedWidget() {
    274   // TODO(cpu): This is bad. Chrome's compositor needs a valid window
    275   // initially and then later on we swap it. Since the compositor never
    276   // uses this initial window we tell ourselves this hack is ok to get
    277   // thing off the ground.
    278   return ::GetDesktopWindow();
    279 }
    280 
    281 void RemoteRootWindowHostWin::Show() {
    282 }
    283 
    284 void RemoteRootWindowHostWin::Hide() {
    285   NOTIMPLEMENTED();
    286 }
    287 
    288 void RemoteRootWindowHostWin::ToggleFullScreen() {
    289 }
    290 
    291 gfx::Rect RemoteRootWindowHostWin::GetBounds() const {
    292   gfx::Rect r(gfx::Point(0, 0), aura::RootWindowHost::GetNativeScreenSize());
    293   return r;
    294 }
    295 
    296 void RemoteRootWindowHostWin::SetBounds(const gfx::Rect& bounds) {
    297   delegate_->OnHostResized(bounds.size());
    298 }
    299 
    300 gfx::Insets RemoteRootWindowHostWin::GetInsets() const {
    301   return gfx::Insets();
    302 }
    303 
    304 void RemoteRootWindowHostWin::SetInsets(const gfx::Insets& insets) {
    305 }
    306 
    307 gfx::Point RemoteRootWindowHostWin::GetLocationOnNativeScreen() const {
    308   return gfx::Point(0, 0);
    309 }
    310 
    311 void RemoteRootWindowHostWin::SetCursor(gfx::NativeCursor native_cursor) {
    312   if (!host_)
    313     return;
    314   host_->Send(
    315       new MetroViewerHostMsg_SetCursor(uint64(native_cursor.platform())));
    316 }
    317 
    318 void RemoteRootWindowHostWin::SetCapture() {
    319 }
    320 
    321 void RemoteRootWindowHostWin::ReleaseCapture() {
    322 }
    323 
    324 bool RemoteRootWindowHostWin::QueryMouseLocation(gfx::Point* location_return) {
    325   aura::client::CursorClient* cursor_client =
    326       aura::client::GetCursorClient(GetRootWindow());
    327   if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
    328     *location_return = gfx::Point(0, 0);
    329     return false;
    330   }
    331   POINT pt;
    332   GetCursorPos(&pt);
    333   *location_return =
    334       gfx::Point(static_cast<int>(pt.x), static_cast<int>(pt.y));
    335   return true;
    336 }
    337 
    338 bool RemoteRootWindowHostWin::ConfineCursorToRootWindow() {
    339   return true;
    340 }
    341 
    342 bool RemoteRootWindowHostWin::CopyAreaToSkCanvas(const gfx::Rect& source_bounds,
    343                                                  const gfx::Point& dest_offset,
    344                                                  SkCanvas* canvas) {
    345   NOTIMPLEMENTED();
    346   return false;
    347 }
    348 
    349 void RemoteRootWindowHostWin::UnConfineCursor() {
    350 }
    351 
    352 void RemoteRootWindowHostWin::OnCursorVisibilityChanged(bool show) {
    353   NOTIMPLEMENTED();
    354 }
    355 
    356 void RemoteRootWindowHostWin::MoveCursorTo(const gfx::Point& location) {
    357   VLOG(1) << "In MoveCursorTo: " << location.x() << ", " << location.y();
    358   if (!host_)
    359     return;
    360 
    361   // This function can be called in cases like when the mouse cursor is
    362   // restricted within a viewport (For e.g. LockCursor) which assumes that
    363   // subsequent mouse moves would be received starting with the new cursor
    364   // coordinates. This is a challenge for Windows ASH for the reasons
    365   // outlined below.
    366   // Other cases which don't expect this behavior should continue to work
    367   // without issues.
    368 
    369   // The mouse events are received by the viewer process and sent to the
    370   // browser. If we invoke the SetCursor API here we continue to receive
    371   // mouse messages from the viewer which were posted before the SetCursor
    372   // API executes which messes up the state in the browser. To workaround
    373   // this we invoke the SetCursor API in the viewer process and ignore
    374   // mouse messages until we received an ACK from the viewer indicating that
    375   // the SetCursor operation completed.
    376   ignore_mouse_moves_until_set_cursor_ack_ = true;
    377   VLOG(1) << "In MoveCursorTo. Sending IPC";
    378   host_->Send(new MetroViewerHostMsg_SetCursorPos(location.x(), location.y()));
    379 }
    380 
    381 void RemoteRootWindowHostWin::SetFocusWhenShown(bool focus_when_shown) {
    382   NOTIMPLEMENTED();
    383 }
    384 
    385 void RemoteRootWindowHostWin::PostNativeEvent(
    386     const base::NativeEvent& native_event) {
    387 }
    388 
    389 void RemoteRootWindowHostWin::OnDeviceScaleFactorChanged(
    390     float device_scale_factor) {
    391   NOTIMPLEMENTED();
    392 }
    393 
    394 void RemoteRootWindowHostWin::PrepareForShutdown() {
    395 }
    396 
    397 void RemoteRootWindowHostWin::OnMouseMoved(int32 x, int32 y, int32 flags) {
    398   if (ignore_mouse_moves_until_set_cursor_ack_)
    399     return;
    400 
    401   gfx::Point location(x, y);
    402   ui::MouseEvent event(ui::ET_MOUSE_MOVED, location, location, flags);
    403   delegate_->OnHostMouseEvent(&event);
    404 }
    405 
    406 void RemoteRootWindowHostWin::OnMouseButton(
    407     int32 x, int32 y, int32 extra, ui::EventType type, ui::EventFlags flags) {
    408   gfx::Point location(x, y);
    409   ui::MouseEvent mouse_event(type, location, location, flags);
    410 
    411   if (type == ui::ET_MOUSEWHEEL) {
    412     ui::MouseWheelEvent wheel_event(mouse_event, 0, extra);
    413     delegate_->OnHostMouseEvent(&wheel_event);
    414   } else if (type == ui::ET_MOUSE_PRESSED) {
    415     // TODO(shrikant): Ideally modify code in event.cc by adding automatic
    416     // tracking of double clicks in synthetic MouseEvent constructor code.
    417     // Non-synthetic MouseEvent constructor code does automatically track
    418     // this. Need to use some caution while modifying synthetic constructor
    419     // as many tests and other code paths depend on it and apparently
    420     // specifically depend on non implicit tracking of previous mouse event.
    421     if (last_mouse_click_event_ &&
    422         ui::MouseEvent::IsRepeatedClickEvent(mouse_event,
    423                                              *last_mouse_click_event_)) {
    424       mouse_event.SetClickCount(2);
    425     } else {
    426       mouse_event.SetClickCount(1);
    427     }
    428     last_mouse_click_event_ .reset(new ui::MouseEvent(mouse_event));
    429     delegate_->OnHostMouseEvent(&mouse_event);
    430   } else {
    431     delegate_->OnHostMouseEvent(&mouse_event);
    432   }
    433 }
    434 
    435 void RemoteRootWindowHostWin::OnKeyDown(uint32 vkey,
    436                                         uint32 repeat_count,
    437                                         uint32 scan_code,
    438                                         uint32 flags) {
    439   DispatchKeyboardMessage(ui::ET_KEY_PRESSED, vkey, repeat_count, scan_code,
    440                           flags, false);
    441 }
    442 
    443 void RemoteRootWindowHostWin::OnKeyUp(uint32 vkey,
    444                                       uint32 repeat_count,
    445                                       uint32 scan_code,
    446                                       uint32 flags) {
    447   DispatchKeyboardMessage(ui::ET_KEY_RELEASED, vkey, repeat_count, scan_code,
    448                           flags, false);
    449 }
    450 
    451 void RemoteRootWindowHostWin::OnChar(uint32 key_code,
    452                                      uint32 repeat_count,
    453                                      uint32 scan_code,
    454                                      uint32 flags) {
    455   DispatchKeyboardMessage(ui::ET_KEY_PRESSED, key_code, repeat_count,
    456                           scan_code, flags, true);
    457 }
    458 
    459 void RemoteRootWindowHostWin::OnVisibilityChanged(bool visible) {
    460   if (visible)
    461     delegate_->OnHostActivated();
    462 }
    463 
    464 void RemoteRootWindowHostWin::OnTouchDown(int32 x,
    465                                           int32 y,
    466                                           uint64 timestamp,
    467                                           uint32 pointer_id) {
    468   ui::TouchEvent event(ui::ET_TOUCH_PRESSED,
    469                        gfx::Point(x, y),
    470                        pointer_id,
    471                        base::TimeDelta::FromMicroseconds(timestamp));
    472   delegate_->OnHostTouchEvent(&event);
    473 }
    474 
    475 void RemoteRootWindowHostWin::OnTouchUp(int32 x,
    476                                         int32 y,
    477                                         uint64 timestamp,
    478                                         uint32 pointer_id) {
    479   ui::TouchEvent event(ui::ET_TOUCH_RELEASED,
    480                        gfx::Point(x, y),
    481                        pointer_id,
    482                        base::TimeDelta::FromMicroseconds(timestamp));
    483   delegate_->OnHostTouchEvent(&event);
    484 }
    485 
    486 void RemoteRootWindowHostWin::OnTouchMoved(int32 x,
    487                                            int32 y,
    488                                            uint64 timestamp,
    489                                            uint32 pointer_id) {
    490   ui::TouchEvent event(ui::ET_TOUCH_MOVED,
    491                        gfx::Point(x, y),
    492                        pointer_id,
    493                        base::TimeDelta::FromMicroseconds(timestamp));
    494   delegate_->OnHostTouchEvent(&event);
    495 }
    496 
    497 void RemoteRootWindowHostWin::OnFileSaveAsDone(bool success,
    498                                                const base::FilePath& filename,
    499                                                int filter_index) {
    500   if (success)
    501     file_saveas_completion_callback_.Run(filename, filter_index, NULL);
    502   else
    503     failure_callback_.Run(NULL);
    504   file_saveas_completion_callback_.Reset();
    505   failure_callback_.Reset();
    506 }
    507 
    508 
    509 void RemoteRootWindowHostWin::OnFileOpenDone(bool success,
    510                                              const base::FilePath& filename) {
    511   if (success)
    512     file_open_completion_callback_.Run(base::FilePath(filename), 0, NULL);
    513   else
    514     failure_callback_.Run(NULL);
    515   file_open_completion_callback_.Reset();
    516   failure_callback_.Reset();
    517 }
    518 
    519 void RemoteRootWindowHostWin::OnMultiFileOpenDone(
    520     bool success,
    521     const std::vector<base::FilePath>& files) {
    522   if (success)
    523     multi_file_open_completion_callback_.Run(files, NULL);
    524   else
    525     failure_callback_.Run(NULL);
    526   multi_file_open_completion_callback_.Reset();
    527   failure_callback_.Reset();
    528 }
    529 
    530 void RemoteRootWindowHostWin::OnSelectFolderDone(
    531     bool success,
    532     const base::FilePath& folder) {
    533   if (success)
    534     select_folder_completion_callback_.Run(base::FilePath(folder), 0, NULL);
    535   else
    536     failure_callback_.Run(NULL);
    537   select_folder_completion_callback_.Reset();
    538   failure_callback_.Reset();
    539 }
    540 
    541 void RemoteRootWindowHostWin::OnWindowActivated(bool active) {
    542   active ? GetRootWindow()->Focus() : GetRootWindow()->Blur();
    543 }
    544 
    545 void RemoteRootWindowHostWin::OnSetCursorPosAck() {
    546   DCHECK(ignore_mouse_moves_until_set_cursor_ack_);
    547   ignore_mouse_moves_until_set_cursor_ack_ = false;
    548 }
    549 
    550 void RemoteRootWindowHostWin::OnWindowSizeChanged(uint32 width, uint32 height) {
    551   SetBounds(gfx::Rect(0, 0, width, height));
    552 }
    553 
    554 void RemoteRootWindowHostWin::DispatchKeyboardMessage(ui::EventType type,
    555                                                       uint32 vkey,
    556                                                       uint32 repeat_count,
    557                                                       uint32 scan_code,
    558                                                       uint32 flags,
    559                                                       bool is_character) {
    560   if (base::MessageLoop::current()->IsNested()) {
    561     SetVirtualKeyStates(flags);
    562 
    563     uint32 message = is_character ? WM_CHAR :
    564         (type == ui::ET_KEY_PRESSED ? WM_KEYDOWN : WM_KEYUP);
    565     ::PostThreadMessage(::GetCurrentThreadId(),
    566                         message,
    567                         vkey,
    568                         repeat_count | scan_code >> 15);
    569   } else {
    570     ui::KeyEvent event(type,
    571                        ui::KeyboardCodeForWindowsKeyCode(vkey),
    572                        flags,
    573                        is_character);
    574     delegate_->OnHostKeyEvent(&event);
    575   }
    576 }
    577 
    578 }  // namespace aura
    579