15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
9a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/memory.h"
105e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_gdi_object.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_hdc.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_select_object.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "remoting/host/client_session_control.h"
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "remoting/host/host_window.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "remoting/host/win/core_resource.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace remoting {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int DISCONNECT_HOTKEY_ID = 1000;
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Maximum length of "Your desktop is shared with ..." message in UTF-16
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// characters.
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const size_t kMaxSharingWithTextLength = 100;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const wchar_t kShellTrayWindowName[] = L"Shell_TrayWnd";
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kWindowBorderRadius = 14;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Margin between dialog controls (in dialog units).
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochconst int kWindowTextMargin = 8;
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class DisconnectWindowWin : public HostWindow {
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DisconnectWindowWin();
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~DisconnectWindowWin();
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // HostWindow overrides.
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void Start(
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      const base::WeakPtr<ClientSessionControl>& client_session_control)
43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      OVERRIDE;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) protected:
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  static INT_PTR CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wparam,
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                     LPARAM lparam);
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BOOL OnDialogMessage(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Creates the dialog window and registers the disconnect hot key.
52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool BeginDialog();
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Closes the dialog, unregisters the hot key and invokes the disconnect
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // callback, if set.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void EndDialog();
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Returns |control| rectangle in the dialog coordinates.
597dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  bool GetControlRect(HWND control, RECT* rect);
607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Trys to position the dialog window above the taskbar.
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void SetDialogPosition();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Applies localization string and resizes the dialog.
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool SetStrings();
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Used to disconnect the client session.
68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::WeakPtr<ClientSessionControl> client_session_control_;
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Specifies the remote user name.
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string username_;
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWND hwnd_;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool has_hotkey_;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedGDIObject<HPEN> border_pen_;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(DisconnectWindowWin);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Returns the text for the given dialog control window.
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GetControlText(HWND control, base::string16* text) {
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // GetWindowText truncates the text if it is longer than can fit into
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // the buffer.
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  WCHAR buffer[256];
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int result = GetWindowText(control, buffer, arraysize(buffer));
867dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!result)
877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  text->assign(buffer);
907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Returns width |text| rendered in |control| window.
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool GetControlTextWidth(HWND control,
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         const base::string16& text,
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                         LONG* width) {
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RECT rect = {0, 0, 0, 0};
987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::win::ScopedGetDC dc(control);
997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::win::ScopedSelectObject font(
1007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      dc, (HFONT)SendMessage(control, WM_GETFONT, 0, 0));
1017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!DrawText(dc, text.c_str(), -1, &rect, DT_CALCRECT | DT_SINGLELINE))
1027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
1037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  *width = rect.right;
1057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
108a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)DisconnectWindowWin::DisconnectWindowWin()
109a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    : hwnd_(NULL),
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      has_hotkey_(false),
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      border_pen_(CreatePen(PS_SOLID, 5,
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            RGB(0.13 * 255, 0.69 * 255, 0.11 * 255))) {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DisconnectWindowWin::~DisconnectWindowWin() {
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EndDialog();
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void DisconnectWindowWin::Start(
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::WeakPtr<ClientSessionControl>& client_session_control) {
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(CalledOnValidThread());
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(!client_session_control_);
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(client_session_control);
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  client_session_control_ = client_session_control;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string client_jid = client_session_control_->client_jid();
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  username_ = client_jid.substr(0, client_jid.find('/'));
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!BeginDialog())
130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EndDialog();
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)INT_PTR CALLBACK DisconnectWindowWin::DialogProc(HWND hwnd,
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 UINT message,
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 WPARAM wparam,
136c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                                 LPARAM lparam) {
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LONG_PTR self = NULL;
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (message == WM_INITDIALOG) {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self = lparam;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Store |this| to the window's user data.
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SetLastError(ERROR_SUCCESS);
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LONG_PTR result = SetWindowLongPtr(hwnd, DWLP_USER, self);
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (result == 0 && GetLastError() != ERROR_SUCCESS)
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      reinterpret_cast<DisconnectWindowWin*>(self)->EndDialog();
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self = GetWindowLongPtr(hwnd, DWLP_USER);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (self) {
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return reinterpret_cast<DisconnectWindowWin*>(self)->OnDialogMessage(
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        hwnd, message, wparam, lparam);
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return FALSE;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
157c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)BOOL DisconnectWindowWin::OnDialogMessage(HWND hwnd,
158c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                          UINT message,
159c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                          WPARAM wparam,
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                          LPARAM lparam) {
161c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(CalledOnValidThread());
162c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch (message) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ignore close messages.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WM_CLOSE:
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return TRUE;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Handle the Disconnect button.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WM_COMMAND:
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      switch (LOWORD(wparam)) {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        case IDC_DISCONNECT:
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          EndDialog();
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          return TRUE;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return FALSE;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ensure we don't try to use the HWND anymore.
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WM_DESTROY:
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hwnd_ = NULL;
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // Ensure that the disconnect callback is invoked even if somehow our
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      // window gets destroyed.
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      EndDialog();
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return TRUE;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ensure the dialog stays visible if the work area dimensions change.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WM_SETTINGCHANGE:
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (wparam == SPI_SETWORKAREA)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        SetDialogPosition();
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return TRUE;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Ensure the dialog stays visible if the display dimensions change.
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WM_DISPLAYCHANGE:
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SetDialogPosition();
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return TRUE;
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Handle the disconnect hot-key.
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WM_HOTKEY:
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EndDialog();
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return TRUE;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Let the window be draggable by its client area by responding
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that the entire window is the title bar.
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WM_NCHITTEST:
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      SetWindowLongPtr(hwnd, DWLP_MSGRESULT, HTCAPTION);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return TRUE;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case WM_PAINT: {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      PAINTSTRUCT ps;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      HDC hdc = BeginPaint(hwnd_, &ps);
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      RECT rect;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetClientRect(hwnd_, &rect);
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::win::ScopedSelectObject border(hdc, border_pen_);
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::win::ScopedSelectObject brush(hdc, GetStockObject(NULL_BRUSH));
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        RoundRect(hdc, rect.left, rect.top, rect.right - 1, rect.bottom - 1,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  kWindowBorderRadius, kWindowBorderRadius);
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      EndPaint(hwnd_, &ps);
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return TRUE;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return FALSE;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
227c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DisconnectWindowWin::BeginDialog() {
228c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(CalledOnValidThread());
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!hwnd_);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HMODULE module = base::GetModuleFromAddress(&DialogProc);
232a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  hwnd_ = CreateDialogParam(module, MAKEINTRESOURCE(IDD_DISCONNECT), NULL,
233a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                            DialogProc, reinterpret_cast<LPARAM>(this));
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!hwnd_)
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Set up handler for Ctrl-Alt-Esc shortcut.
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!has_hotkey_ && RegisterHotKey(hwnd_, DISCONNECT_HOTKEY_ID,
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                     MOD_ALT | MOD_CONTROL, VK_ESCAPE)) {
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    has_hotkey_ = true;
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
243c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (!SetStrings())
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetDialogPosition();
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShowWindow(hwnd_, SW_SHOW);
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return IsWindowVisible(hwnd_) != FALSE;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void DisconnectWindowWin::EndDialog() {
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(CalledOnValidThread());
253c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (has_hotkey_) {
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    UnregisterHotKey(hwnd_, DISCONNECT_HOTKEY_ID);
2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    has_hotkey_ = false;
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (hwnd_) {
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DestroyWindow(hwnd_);
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    hwnd_ = NULL;
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if (client_session_control_)
265c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    client_session_control_->DisconnectSession();
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch// Returns |control| rectangle in the dialog coordinates.
2697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbool DisconnectWindowWin::GetControlRect(HWND control, RECT* rect) {
2707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!GetWindowRect(control, rect))
2717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  SetLastError(ERROR_SUCCESS);
2737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int result = MapWindowPoints(HWND_DESKTOP, hwnd_,
2747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                               reinterpret_cast<LPPOINT>(rect), 2);
2757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!result && GetLastError() != ERROR_SUCCESS)
2767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
2777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return true;
2797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void DisconnectWindowWin::SetDialogPosition() {
282c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(CalledOnValidThread());
283c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Try to center the window above the task-bar. If that fails, use the
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // primary monitor. If that fails (very unlikely), use the default position.
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HWND taskbar = FindWindow(kShellTrayWindowName, NULL);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HMONITOR monitor = MonitorFromWindow(taskbar, MONITOR_DEFAULTTOPRIMARY);
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  MONITORINFO monitor_info = {sizeof(monitor_info)};
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RECT window_rect;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (GetMonitorInfo(monitor, &monitor_info) &&
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetWindowRect(hwnd_, &window_rect)) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int window_width = window_rect.right - window_rect.left;
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int window_height = window_rect.bottom - window_rect.top;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int top = monitor_info.rcWork.bottom - window_height;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int left = (monitor_info.rcWork.right + monitor_info.rcWork.left -
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        window_width) / 2;
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetWindowPos(hwnd_, NULL, left, top, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
301c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)bool DisconnectWindowWin::SetStrings() {
302c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DCHECK(CalledOnValidThread());
303c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Localize the disconnect button text and measure length of the old and new
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // labels.
3067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  HWND hwnd_button = GetDlgItem(hwnd_, IDC_DISCONNECT);
3077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  HWND hwnd_message = GetDlgItem(hwnd_, IDC_DISCONNECT_SHARINGWITH);
3087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!hwnd_button || !hwnd_message)
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 button_text;
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 message_text;
3137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!GetControlText(hwnd_button, &button_text) ||
3147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      !GetControlText(hwnd_message, &message_text)) {
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Format and truncate "Your desktop is shared with ..." message.
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  message_text = ReplaceStringPlaceholders(message_text,
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                           base::UTF8ToUTF16(username_),
3217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                           NULL);
3227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (message_text.length() > kMaxSharingWithTextLength)
3237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    message_text.erase(kMaxSharingWithTextLength);
3247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!SetWindowText(hwnd_message, message_text.c_str()))
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Calculate the margin between controls in pixels.
3297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  RECT rect = {0};
3307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  rect.right = kWindowTextMargin;
3317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!MapDialogRect(hwnd_, &rect))
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int margin = rect.right;
3347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Resize |hwnd_message| so that the text is not clipped.
3367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  RECT message_rect;
3377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!GetControlRect(hwnd_message, &message_rect))
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  LONG control_width;
3417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!GetControlTextWidth(hwnd_message, message_text, &control_width))
3427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return false;
3437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  message_rect.right = message_rect.left + control_width + margin;
3447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!SetWindowPos(hwnd_message, NULL,
3467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    message_rect.left, message_rect.top,
3477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    message_rect.right - message_rect.left,
3487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    message_rect.bottom - message_rect.top,
3497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    SWP_NOZORDER)) {
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Reposition and resize |hwnd_button| as well.
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RECT button_rect;
3557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!GetControlRect(hwnd_button, &button_rect))
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!GetControlTextWidth(hwnd_button, button_text, &control_width))
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3607dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3617dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  button_rect.left = message_rect.right;
3627dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  button_rect.right = button_rect.left + control_width + margin * 2;
3637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!SetWindowPos(hwnd_button, NULL,
3647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    button_rect.left, button_rect.top,
3657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    button_rect.right - button_rect.left,
3667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    button_rect.bottom - button_rect.top,
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    SWP_NOZORDER)) {
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Resize the whole window to fit the resized controls.
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RECT window_rect;
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!GetWindowRect(hwnd_, &window_rect))
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  int width = button_rect.right + margin;
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int height = window_rect.bottom - window_rect.top;
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!SetWindowPos(hwnd_, NULL, 0, 0, width, height,
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    SWP_NOMOVE | SWP_NOZORDER)) {
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Make the corners of the disconnect window rounded.
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  HRGN rgn = CreateRoundRectRgn(0, 0, width, height, kWindowBorderRadius,
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                kWindowBorderRadius);
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!rgn)
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!SetWindowRgn(hwnd_, rgn, TRUE))
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
393c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} // namespace
394c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
395c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// static
396a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)scoped_ptr<HostWindow> HostWindow::CreateDisconnectWindow() {
397a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return scoped_ptr<HostWindow>(new DisconnectWindowWin());
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace remoting
401