Index: remoting/host/disconnect_window_win.cc |
diff --git a/remoting/host/disconnect_window_win.cc b/remoting/host/disconnect_window_win.cc |
index abe739a34b8b7c6204959171d242babf90443542..e81ed6580504ceb28e19e34eeb217ebab794312f 100644 |
--- a/remoting/host/disconnect_window_win.cc |
+++ b/remoting/host/disconnect_window_win.cc |
@@ -10,6 +10,9 @@ |
#include "base/logging.h" |
#include "base/string_util.h" |
#include "base/utf_string_conversions.h" |
+#include "base/win/scoped_gdi_object.h" |
+#include "base/win/scoped_hdc.h" |
+#include "base/win/scoped_select_object.h" |
#include "remoting/host/chromoting_host.h" |
// TODO(wez): The DisconnectWindow isn't plugin-specific, so shouldn't have |
// a dependency on the plugin's resource header. |
@@ -28,6 +31,7 @@ |
extern HMODULE g_hModule; |
const int DISCONNECT_HOTKEY_ID = 1000; |
+const int kWindowBorderRadius = 14; |
namespace remoting { |
@@ -53,6 +57,7 @@ private: |
remoting::ChromotingHost* host_; |
HWND hwnd_; |
bool has_hotkey_; |
+ base::win::ScopedGDIObject<HPEN> border_pen_; |
DISALLOW_COPY_AND_ASSIGN(DisconnectWindowWin); |
}; |
@@ -60,7 +65,9 @@ private: |
DisconnectWindowWin::DisconnectWindowWin() |
: host_(NULL), |
hwnd_(NULL), |
- has_hotkey_(false) { |
+ has_hotkey_(false), |
+ border_pen_(CreatePen(PS_SOLID, 5, |
+ RGB(0.13 * 255, 0.69 * 255, 0.11 * 255))) { |
} |
DisconnectWindowWin::~DisconnectWindowWin() { |
@@ -86,17 +93,11 @@ BOOL CALLBACK DisconnectWindowWin::DialogProc(HWND hwnd, UINT msg, |
BOOL DisconnectWindowWin::OnDialogMessage(HWND hwnd, UINT msg, |
WPARAM wParam, LPARAM lParam) { |
switch (msg) { |
- case WM_HOTKEY: |
- ShutdownHost(); |
- EndDialog(0); |
- return TRUE; |
+ // Ignore close messages. |
case WM_CLOSE: |
- // Ignore close messages. |
- return TRUE; |
- case WM_DESTROY: |
- // Ensure we don't try to use the HWND anymore. |
- hwnd_ = NULL; |
return TRUE; |
+ |
+ // Handle the Disconnect button. |
case WM_COMMAND: |
switch (LOWORD(wParam)) { |
case IDC_DISCONNECT: |
@@ -104,21 +105,77 @@ BOOL DisconnectWindowWin::OnDialogMessage(HWND hwnd, UINT msg, |
EndDialog(LOWORD(wParam)); |
return TRUE; |
} |
+ return FALSE; |
+ |
+ // Ensure we don't try to use the HWND anymore. |
+ case WM_DESTROY: |
+ hwnd_ = NULL; |
+ return TRUE; |
+ |
+ // Handle the disconnect hot-key. |
+ case WM_HOTKEY: |
+ ShutdownHost(); |
+ EndDialog(0); |
+ return TRUE; |
+ |
+ // Let the window be draggable by its client area by responding |
+ // that the entire window is the title bar. |
+ case WM_NCHITTEST: |
+ SetWindowLong(hwnd, DWL_MSGRESULT, HTCAPTION); |
+ return TRUE; |
+ |
+ case WM_PAINT: |
+ { |
+ PAINTSTRUCT ps; |
+ HDC hdc = BeginPaint(hwnd_, &ps); |
+ RECT rect; |
+ GetClientRect(hwnd_, &rect); |
+ { |
+ base::win::ScopedSelectObject border(hdc, border_pen_); |
+ base::win::ScopedSelectObject brush(hdc, GetStockObject(NULL_BRUSH)); |
+ RoundRect(hdc, rect.left, rect.top, rect.right - 1, rect.bottom - 1, |
+ kWindowBorderRadius, kWindowBorderRadius); |
+ } |
+ EndPaint(hwnd_, &ps); |
+ return TRUE; |
+ } |
} |
return FALSE; |
} |
void DisconnectWindowWin::Show(ChromotingHost* host, |
const std::string& username) { |
+ CHECK(!hwnd_); |
host_ = host; |
- CHECK(!hwnd_); |
- hwnd_ = CreateDialogParam(g_hModule, MAKEINTRESOURCE(IDD_DISCONNECT), NULL, |
- (DLGPROC)DialogProc, (LPARAM)this); |
- if (!hwnd_) { |
- LOG(ERROR) << "Unable to create Disconnect dialog for remoting."; |
- return; |
- } |
+ // Load the dialog resource so that we can modify the RTL flags if necessary. |
+ // This is taken from chrome/default_plugin/install_dialog.cc |
+ HRSRC dialog_resource = |
+ FindResource(g_hModule, MAKEINTRESOURCE(IDD_DISCONNECT), RT_DIALOG); |
+ CHECK(dialog_resource); |
+ HGLOBAL dialog_template = LoadResource(g_hModule, dialog_resource); |
+ CHECK(dialog_template); |
+ DLGTEMPLATE* dialog_pointer = |
+ reinterpret_cast<DLGTEMPLATE*>(LockResource(dialog_template)); |
+ CHECK(dialog_pointer); |
+ |
+ // The actual resource type is DLGTEMPLATEEX, but this is not defined in any |
+ // standard headers, so we treat it as a generic pointer and manipulate the |
+ // correct offsets explicitly. |
+ scoped_ptr<unsigned char> rtl_dialog_template; |
+ if (host->ui_strings().direction == UiStrings::RTL) { |
+ unsigned long dialog_template_size = |
+ SizeofResource(g_hModule, dialog_resource); |
+ rtl_dialog_template.reset(new unsigned char[dialog_template_size]); |
+ memcpy(rtl_dialog_template.get(), dialog_pointer, dialog_template_size); |
+ DWORD* rtl_dwords = reinterpret_cast<DWORD*>(rtl_dialog_template.get()); |
+ rtl_dwords[2] |= (WS_EX_LAYOUTRTL | WS_EX_RTLREADING); |
+ dialog_pointer = reinterpret_cast<DLGTEMPLATE*>(rtl_dwords); |
+ } |
+ |
+ hwnd_ = CreateDialogIndirectParam(g_hModule, dialog_pointer, NULL, |
+ (DLGPROC)DialogProc, (LPARAM)this); |
+ CHECK(hwnd_); |
// Set up handler for Ctrl-Alt-Esc shortcut. |
if (!has_hotkey_ && RegisterHotKey(hwnd_, DISCONNECT_HOTKEY_ID, |
@@ -135,8 +192,21 @@ void DisconnectWindowWin::ShutdownHost() { |
host_->Shutdown(NULL); |
} |
+static int GetControlTextWidth(HWND control) { |
+ RECT rect = {0, 0, 0, 0}; |
+ WCHAR text[256]; |
+ int result = GetWindowText(control, text, arraysize(text)); |
+ if (result) { |
+ base::win::ScopedGetDC dc(control); |
+ base::win::ScopedSelectObject font( |
+ dc, (HFONT)SendMessage(control, WM_GETFONT, 0, 0)); |
+ DrawText(dc, text, -1, &rect, DT_CALCRECT|DT_SINGLELINE); |
+ } |
+ return rect.right; |
+} |
+ |
void DisconnectWindowWin::SetStrings(const UiStrings& strings, |
- const std::string& username) { |
+ const std::string& username) { |
SetWindowText(hwnd_, strings.product_name.c_str()); |
HWND hwndButton = GetDlgItem(hwnd_, IDC_DISCONNECT); |
@@ -144,13 +214,49 @@ void DisconnectWindowWin::SetStrings(const UiStrings& strings, |
const WCHAR* label = |
has_hotkey_ ? strings.disconnect_button_text_plus_shortcut.c_str() |
: strings.disconnect_button_text.c_str(); |
+ int button_old_required_width = GetControlTextWidth(hwndButton); |
SetWindowText(hwndButton, label); |
+ int button_new_required_width = GetControlTextWidth(hwndButton); |
HWND hwndSharingWith = GetDlgItem(hwnd_, IDC_DISCONNECT_SHARINGWITH); |
CHECK(hwndSharingWith); |
string16 text = ReplaceStringPlaceholders( |
strings.disconnect_message, UTF8ToUTF16(username), NULL); |
+ int label_old_required_width = GetControlTextWidth(hwndSharingWith); |
SetWindowText(hwndSharingWith, text.c_str()); |
+ int label_new_required_width = GetControlTextWidth(hwndSharingWith); |
+ |
+ int label_width_delta = label_new_required_width - label_old_required_width; |
+ int button_width_delta = |
+ button_new_required_width - button_old_required_width; |
+ |
+ // Reposition the controls such that the label lies to the left of the |
+ // disconnect button (assuming LTR layout). The dialog template determines |
+ // the controls' spacing; update their size to fit the localized content. |
+ RECT label_rect; |
+ GetClientRect(hwndSharingWith, &label_rect); |
+ SetWindowPos(hwndSharingWith, NULL, 0, 0, |
+ label_rect.right + label_width_delta, label_rect.bottom, |
+ SWP_NOMOVE|SWP_NOZORDER); |
+ |
+ RECT button_rect; |
+ GetWindowRect(hwndButton, &button_rect); |
+ int button_width = button_rect.right - button_rect.left; |
+ int button_height = button_rect.bottom - button_rect.top; |
+ MapWindowPoints(NULL, hwnd_, reinterpret_cast<LPPOINT>(&button_rect), 2); |
+ SetWindowPos(hwndButton, NULL, |
+ button_rect.left + label_width_delta, button_rect.top, |
+ button_width + button_width_delta, button_height, SWP_NOZORDER); |
+ |
+ RECT window_rect; |
+ GetWindowRect(hwnd_, &window_rect); |
+ int width = (window_rect.right - window_rect.left) + |
+ button_width_delta + label_width_delta; |
+ int height = window_rect.bottom - window_rect.top; |
+ SetWindowPos(hwnd_, NULL, 0, 0, width, height, SWP_NOMOVE|SWP_NOZORDER); |
+ HRGN rgn = CreateRoundRectRgn(0, 0, width, height, kWindowBorderRadius, |
+ kWindowBorderRadius); |
+ SetWindowRgn(hwnd_, rgn, TRUE); |
} |
void DisconnectWindowWin::Hide() { |