Home | History | Annotate | Download | only in shell
      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 "content/shell/shell.h"
      6 
      7 #include <commctrl.h>
      8 #include <fcntl.h>
      9 #include <io.h>
     10 #include <windows.h>
     11 
     12 #include "base/strings/utf_string_conversions.h"
     13 #include "base/win/wrapped_window_proc.h"
     14 #include "content/public/browser/web_contents.h"
     15 #include "content/public/browser/web_contents_view.h"
     16 #include "content/shell/app/resource.h"
     17 #include "ui/base/win/hwnd_util.h"
     18 
     19 namespace {
     20 
     21 const wchar_t kWindowTitle[] = L"Content Shell";
     22 const wchar_t kWindowClass[] = L"CONTENT_SHELL";
     23 
     24 const int kButtonWidth = 72;
     25 const int kURLBarHeight = 24;
     26 
     27 const int kMaxURLLength = 1024;
     28 
     29 }  // namespace
     30 
     31 namespace content {
     32 
     33 HINSTANCE Shell::instance_handle_;
     34 
     35 void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
     36   _setmode(_fileno(stdout), _O_BINARY);
     37   _setmode(_fileno(stderr), _O_BINARY);
     38   INITCOMMONCONTROLSEX InitCtrlEx;
     39   InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
     40   InitCtrlEx.dwICC  = ICC_STANDARD_CLASSES;
     41   InitCommonControlsEx(&InitCtrlEx);
     42   RegisterWindowClass();
     43 }
     44 
     45 void Shell::PlatformExit() {
     46   std::vector<Shell*> windows = windows_;
     47   for (std::vector<Shell*>::iterator it = windows.begin();
     48        it != windows.end(); ++it)
     49     DestroyWindow((*it)->window_);
     50 }
     51 
     52 void Shell::PlatformCleanUp() {
     53   // When the window is destroyed, tell the Edit field to forget about us,
     54   // otherwise we will crash.
     55   ui::SetWindowProc(url_edit_view_, default_edit_wnd_proc_);
     56   ui::SetWindowUserData(url_edit_view_, NULL);
     57 }
     58 
     59 void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
     60   int id;
     61   switch (control) {
     62     case BACK_BUTTON:
     63       id = IDC_NAV_BACK;
     64       break;
     65     case FORWARD_BUTTON:
     66       id = IDC_NAV_FORWARD;
     67       break;
     68     case STOP_BUTTON:
     69       id = IDC_NAV_STOP;
     70       break;
     71     default:
     72       NOTREACHED() << "Unknown UI control";
     73       return;
     74   }
     75   EnableWindow(GetDlgItem(window_, id), is_enabled);
     76 }
     77 
     78 void Shell::PlatformSetAddressBarURL(const GURL& url) {
     79   std::wstring url_string = UTF8ToWide(url.spec());
     80   SendMessage(url_edit_view_, WM_SETTEXT, 0,
     81               reinterpret_cast<LPARAM>(url_string.c_str()));
     82 }
     83 
     84 void Shell::PlatformSetIsLoading(bool loading) {
     85 }
     86 
     87 void Shell::PlatformCreateWindow(int width, int height) {
     88   window_ = CreateWindow(kWindowClass, kWindowTitle,
     89                          WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
     90                          CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
     91                          NULL, NULL, instance_handle_, NULL);
     92   ui::SetWindowUserData(window_, this);
     93 
     94   HWND hwnd;
     95   int x = 0;
     96 
     97   hwnd = CreateWindow(L"BUTTON", L"Back",
     98                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
     99                       x, 0, kButtonWidth, kURLBarHeight,
    100                       window_, (HMENU) IDC_NAV_BACK, instance_handle_, 0);
    101   x += kButtonWidth;
    102 
    103   hwnd = CreateWindow(L"BUTTON", L"Forward",
    104                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
    105                       x, 0, kButtonWidth, kURLBarHeight,
    106                       window_, (HMENU) IDC_NAV_FORWARD, instance_handle_, 0);
    107   x += kButtonWidth;
    108 
    109   hwnd = CreateWindow(L"BUTTON", L"Reload",
    110                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
    111                       x, 0, kButtonWidth, kURLBarHeight,
    112                       window_, (HMENU) IDC_NAV_RELOAD, instance_handle_, 0);
    113   x += kButtonWidth;
    114 
    115   hwnd = CreateWindow(L"BUTTON", L"Stop",
    116                       WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
    117                       x, 0, kButtonWidth, kURLBarHeight,
    118                       window_, (HMENU) IDC_NAV_STOP, instance_handle_, 0);
    119   x += kButtonWidth;
    120 
    121   // This control is positioned by PlatformResizeSubViews.
    122   url_edit_view_ = CreateWindow(L"EDIT", 0,
    123                                 WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT |
    124                                 ES_AUTOVSCROLL | ES_AUTOHSCROLL,
    125                                 x, 0, 0, 0, window_, 0, instance_handle_, 0);
    126 
    127   default_edit_wnd_proc_ = ui::SetWindowProc(url_edit_view_,
    128                                              Shell::EditWndProc);
    129   ui::SetWindowUserData(url_edit_view_, this);
    130 
    131   ShowWindow(window_, SW_SHOW);
    132 
    133   SizeTo(width, height);
    134 }
    135 
    136 void Shell::PlatformSetContents() {
    137   SetParent(web_contents_->GetView()->GetNativeView(), window_);
    138 }
    139 
    140 void Shell::SizeTo(int width, int height) {
    141   RECT rc, rw;
    142   GetClientRect(window_, &rc);
    143   GetWindowRect(window_, &rw);
    144 
    145   int client_width = rc.right - rc.left;
    146   int window_width = rw.right - rw.left;
    147   window_width = (window_width - client_width) + width;
    148 
    149   int client_height = rc.bottom - rc.top;
    150   int window_height = rw.bottom - rw.top;
    151   window_height = (window_height - client_height) + height;
    152 
    153   // Add space for the url bar.
    154   window_height += kURLBarHeight;
    155 
    156   SetWindowPos(window_, NULL, 0, 0, window_width, window_height,
    157                SWP_NOMOVE | SWP_NOZORDER);
    158 }
    159 
    160 void Shell::PlatformResizeSubViews() {
    161   RECT rc;
    162   GetClientRect(window_, &rc);
    163 
    164   int x = kButtonWidth * 4;
    165   MoveWindow(url_edit_view_, x, 0, rc.right - x, kURLBarHeight, TRUE);
    166 
    167   MoveWindow(GetContentView(), 0, kURLBarHeight, rc.right,
    168              rc.bottom - kURLBarHeight, TRUE);
    169 }
    170 
    171 void Shell::Close() {
    172   DestroyWindow(window_);
    173 }
    174 
    175 ATOM Shell::RegisterWindowClass() {
    176   WNDCLASSEX window_class;
    177   base::win::InitializeWindowClass(
    178       kWindowClass,
    179       &Shell::WndProc,
    180       CS_HREDRAW | CS_VREDRAW,
    181       0,
    182       0,
    183       LoadCursor(NULL, IDC_ARROW),
    184       NULL,
    185       MAKEINTRESOURCE(IDC_CONTENTSHELL),
    186       NULL,
    187       NULL,
    188       &window_class);
    189   instance_handle_ = window_class.hInstance;
    190   return RegisterClassEx(&window_class);
    191 }
    192 
    193 LRESULT CALLBACK Shell::WndProc(HWND hwnd, UINT message, WPARAM wParam,
    194                                 LPARAM lParam) {
    195   Shell* shell = static_cast<Shell*>(ui::GetWindowUserData(hwnd));
    196 
    197   switch (message) {
    198     case WM_COMMAND: {
    199       int id = LOWORD(wParam);
    200       switch (id) {
    201         case IDM_NEW_WINDOW:
    202           CreateNewWindow(
    203               shell->web_contents()->GetBrowserContext(),
    204               GURL(), NULL, MSG_ROUTING_NONE, gfx::Size());
    205           break;
    206         case IDM_CLOSE_WINDOW:
    207           DestroyWindow(hwnd);
    208           break;
    209         case IDM_EXIT:
    210           PlatformExit();
    211           break;
    212         case IDM_SHOW_DEVELOPER_TOOLS:
    213           shell->ShowDevTools();
    214           break;
    215         case IDC_NAV_BACK:
    216           shell->GoBackOrForward(-1);
    217           break;
    218         case IDC_NAV_FORWARD:
    219           shell->GoBackOrForward(1);
    220           break;
    221         case IDC_NAV_RELOAD:
    222           shell->Reload();
    223           break;
    224         case IDC_NAV_STOP:
    225           shell->Stop();
    226           break;
    227       }
    228       break;
    229     }
    230     case WM_DESTROY: {
    231       delete shell;
    232       return 0;
    233     }
    234 
    235     case WM_SIZE: {
    236       if (shell->GetContentView())
    237         shell->PlatformResizeSubViews();
    238       return 0;
    239     }
    240 
    241     case WM_WINDOWPOSCHANGED: {
    242       // Notify the content view that the window position of its parent window
    243       // has been changed by sending window message
    244       gfx::NativeView native_view = shell->GetContentView();
    245       if (native_view) {
    246         SendMessage(native_view, message, wParam, lParam);
    247       }
    248       break;
    249    }
    250   }
    251 
    252   return DefWindowProc(hwnd, message, wParam, lParam);
    253 }
    254 
    255 LRESULT CALLBACK Shell::EditWndProc(HWND hwnd, UINT message,
    256                                     WPARAM wParam, LPARAM lParam) {
    257   Shell* shell = static_cast<Shell*>(ui::GetWindowUserData(hwnd));
    258 
    259   switch (message) {
    260     case WM_CHAR:
    261       if (wParam == VK_RETURN) {
    262         wchar_t str[kMaxURLLength + 1];  // Leave room for adding a NULL;
    263         *(str) = kMaxURLLength;
    264         LRESULT str_len = SendMessage(hwnd, EM_GETLINE, 0, (LPARAM)str);
    265         if (str_len > 0) {
    266           str[str_len] = 0;  // EM_GETLINE doesn't NULL terminate.
    267           GURL url(str);
    268           if (!url.has_scheme())
    269             url = GURL(std::wstring(L"http://") + std::wstring(str));
    270           shell->LoadURL(url);
    271         }
    272 
    273         return 0;
    274       }
    275   }
    276 
    277   return CallWindowProc(shell->default_edit_wnd_proc_, hwnd, message, wParam,
    278                         lParam);
    279 }
    280 
    281 void Shell::PlatformSetTitle(const string16& text) {
    282   ::SetWindowText(window_, text.c_str());
    283 }
    284 
    285 }  // namespace content
    286