// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/shell/browser/shell.h" #include <windows.h> #include <commctrl.h> #include <fcntl.h> #include <io.h> #include "base/strings/utf_string_conversions.h" #include "base/win/wrapped_window_proc.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_view.h" #include "content/shell/app/resource.h" #include "ui/gfx/win/hwnd_util.h" namespace { const wchar_t kWindowTitle[] = L"Content Shell"; const wchar_t kWindowClass[] = L"CONTENT_SHELL"; const int kButtonWidth = 72; const int kURLBarHeight = 24; const int kMaxURLLength = 1024; } // namespace namespace content { HINSTANCE Shell::instance_handle_; void Shell::PlatformInitialize(const gfx::Size& default_window_size) { _setmode(_fileno(stdout), _O_BINARY); _setmode(_fileno(stderr), _O_BINARY); INITCOMMONCONTROLSEX InitCtrlEx; InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX); InitCtrlEx.dwICC = ICC_STANDARD_CLASSES; InitCommonControlsEx(&InitCtrlEx); RegisterWindowClass(); } void Shell::PlatformExit() { std::vector<Shell*> windows = windows_; for (std::vector<Shell*>::iterator it = windows.begin(); it != windows.end(); ++it) DestroyWindow((*it)->window_); } void Shell::PlatformCleanUp() { // When the window is destroyed, tell the Edit field to forget about us, // otherwise we will crash. gfx::SetWindowProc(url_edit_view_, default_edit_wnd_proc_); gfx::SetWindowUserData(url_edit_view_, NULL); } void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) { int id; switch (control) { case BACK_BUTTON: id = IDC_NAV_BACK; break; case FORWARD_BUTTON: id = IDC_NAV_FORWARD; break; case STOP_BUTTON: id = IDC_NAV_STOP; break; default: NOTREACHED() << "Unknown UI control"; return; } EnableWindow(GetDlgItem(window_, id), is_enabled); } void Shell::PlatformSetAddressBarURL(const GURL& url) { std::wstring url_string = UTF8ToWide(url.spec()); SendMessage(url_edit_view_, WM_SETTEXT, 0, reinterpret_cast<LPARAM>(url_string.c_str())); } void Shell::PlatformSetIsLoading(bool loading) { } void Shell::PlatformCreateWindow(int width, int height) { window_ = CreateWindow(kWindowClass, kWindowTitle, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, instance_handle_, NULL); gfx::SetWindowUserData(window_, this); HWND hwnd; int x = 0; hwnd = CreateWindow(L"BUTTON", L"Back", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , x, 0, kButtonWidth, kURLBarHeight, window_, (HMENU) IDC_NAV_BACK, instance_handle_, 0); x += kButtonWidth; hwnd = CreateWindow(L"BUTTON", L"Forward", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , x, 0, kButtonWidth, kURLBarHeight, window_, (HMENU) IDC_NAV_FORWARD, instance_handle_, 0); x += kButtonWidth; hwnd = CreateWindow(L"BUTTON", L"Reload", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , x, 0, kButtonWidth, kURLBarHeight, window_, (HMENU) IDC_NAV_RELOAD, instance_handle_, 0); x += kButtonWidth; hwnd = CreateWindow(L"BUTTON", L"Stop", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON , x, 0, kButtonWidth, kURLBarHeight, window_, (HMENU) IDC_NAV_STOP, instance_handle_, 0); x += kButtonWidth; // This control is positioned by PlatformResizeSubViews. url_edit_view_ = CreateWindow(L"EDIT", 0, WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL | ES_AUTOHSCROLL, x, 0, 0, 0, window_, 0, instance_handle_, 0); default_edit_wnd_proc_ = gfx::SetWindowProc(url_edit_view_, Shell::EditWndProc); gfx::SetWindowUserData(url_edit_view_, this); ShowWindow(window_, SW_SHOW); SizeTo(gfx::Size(width, height)); } void Shell::PlatformSetContents() { SetParent(web_contents_->GetView()->GetNativeView(), window_); } void Shell::SizeTo(const gfx::Size& size) { RECT rc, rw; GetClientRect(window_, &rc); GetWindowRect(window_, &rw); int client_width = rc.right - rc.left; int window_width = rw.right - rw.left; window_width = (window_width - client_width) + size.width(); int client_height = rc.bottom - rc.top; int window_height = rw.bottom - rw.top; window_height = (window_height - client_height) + size.height(); // Add space for the url bar. window_height += kURLBarHeight; SetWindowPos(window_, NULL, 0, 0, window_width, window_height, SWP_NOMOVE | SWP_NOZORDER); } void Shell::PlatformResizeSubViews() { RECT rc; GetClientRect(window_, &rc); int x = kButtonWidth * 4; MoveWindow(url_edit_view_, x, 0, rc.right - x, kURLBarHeight, TRUE); MoveWindow(GetContentView(), 0, kURLBarHeight, rc.right, rc.bottom - kURLBarHeight, TRUE); } void Shell::Close() { DestroyWindow(window_); } ATOM Shell::RegisterWindowClass() { WNDCLASSEX window_class; base::win::InitializeWindowClass( kWindowClass, &Shell::WndProc, CS_HREDRAW | CS_VREDRAW, 0, 0, LoadCursor(NULL, IDC_ARROW), NULL, MAKEINTRESOURCE(IDC_CONTENTSHELL), NULL, NULL, &window_class); instance_handle_ = window_class.hInstance; return RegisterClassEx(&window_class); } LRESULT CALLBACK Shell::WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { Shell* shell = static_cast<Shell*>(gfx::GetWindowUserData(hwnd)); switch (message) { case WM_COMMAND: { int id = LOWORD(wParam); switch (id) { case IDM_NEW_WINDOW: CreateNewWindow( shell->web_contents()->GetBrowserContext(), GURL(), NULL, MSG_ROUTING_NONE, gfx::Size()); break; case IDM_CLOSE_WINDOW: DestroyWindow(hwnd); break; case IDM_EXIT: PlatformExit(); break; case IDM_SHOW_DEVELOPER_TOOLS: shell->ShowDevTools(); break; case IDC_NAV_BACK: shell->GoBackOrForward(-1); break; case IDC_NAV_FORWARD: shell->GoBackOrForward(1); break; case IDC_NAV_RELOAD: shell->Reload(); break; case IDC_NAV_STOP: shell->Stop(); break; } break; } case WM_DESTROY: { delete shell; return 0; } case WM_SIZE: { if (shell->GetContentView()) shell->PlatformResizeSubViews(); return 0; } case WM_WINDOWPOSCHANGED: { // Notify the content view that the window position of its parent window // has been changed by sending window message gfx::NativeView native_view = shell->GetContentView(); if (native_view) { SendMessage(native_view, message, wParam, lParam); } break; } } return DefWindowProc(hwnd, message, wParam, lParam); } LRESULT CALLBACK Shell::EditWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { Shell* shell = static_cast<Shell*>(gfx::GetWindowUserData(hwnd)); switch (message) { case WM_CHAR: if (wParam == VK_RETURN) { wchar_t str[kMaxURLLength + 1]; // Leave room for adding a NULL; *(str) = kMaxURLLength; LRESULT str_len = SendMessage(hwnd, EM_GETLINE, 0, (LPARAM)str); if (str_len > 0) { str[str_len] = 0; // EM_GETLINE doesn't NULL terminate. GURL url(str); if (!url.has_scheme()) url = GURL(std::wstring(L"http://") + std::wstring(str)); shell->LoadURL(url); } return 0; } } return CallWindowProc(shell->default_edit_wnd_proc_, hwnd, message, wParam, lParam); } void Shell::PlatformSetTitle(const base::string16& text) { ::SetWindowText(window_, text.c_str()); } } // namespace content