• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include "tests/cefclient/browser/root_window_win.h"
6 
7 #include <shellscalingapi.h>
8 
9 #include "include/base/cef_build.h"
10 #include "include/base/cef_callback.h"
11 #include "include/cef_app.h"
12 #include "tests/cefclient/browser/browser_window_osr_win.h"
13 #include "tests/cefclient/browser/browser_window_std_win.h"
14 #include "tests/cefclient/browser/main_context.h"
15 #include "tests/cefclient/browser/resource.h"
16 #include "tests/cefclient/browser/temp_window.h"
17 #include "tests/cefclient/browser/window_test_runner_win.h"
18 #include "tests/shared/browser/geometry_util.h"
19 #include "tests/shared/browser/main_message_loop.h"
20 #include "tests/shared/browser/util_win.h"
21 #include "tests/shared/common/client_switches.h"
22 
23 #define MAX_URL_LENGTH 255
24 #define BUTTON_WIDTH 72
25 #define URLBAR_HEIGHT 24
26 
27 namespace client {
28 
29 namespace {
30 
31 // Message handler for the About box.
AboutWndProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)32 INT_PTR CALLBACK AboutWndProc(HWND hDlg,
33                               UINT message,
34                               WPARAM wParam,
35                               LPARAM lParam) {
36   UNREFERENCED_PARAMETER(lParam);
37   switch (message) {
38     case WM_INITDIALOG:
39       return TRUE;
40 
41     case WM_COMMAND:
42       if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
43         EndDialog(hDlg, LOWORD(wParam));
44         return TRUE;
45       }
46       break;
47   }
48   return FALSE;
49 }
50 
51 // Returns true if the process is per monitor DPI aware.
IsProcessPerMonitorDpiAware()52 bool IsProcessPerMonitorDpiAware() {
53   enum class PerMonitorDpiAware {
54     UNKNOWN = 0,
55     PER_MONITOR_DPI_UNAWARE,
56     PER_MONITOR_DPI_AWARE,
57   };
58   static PerMonitorDpiAware per_monitor_dpi_aware = PerMonitorDpiAware::UNKNOWN;
59   if (per_monitor_dpi_aware == PerMonitorDpiAware::UNKNOWN) {
60     per_monitor_dpi_aware = PerMonitorDpiAware::PER_MONITOR_DPI_UNAWARE;
61     HMODULE shcore_dll = ::LoadLibrary(L"shcore.dll");
62     if (shcore_dll) {
63       typedef HRESULT(WINAPI * GetProcessDpiAwarenessPtr)(
64           HANDLE, PROCESS_DPI_AWARENESS*);
65       GetProcessDpiAwarenessPtr func_ptr =
66           reinterpret_cast<GetProcessDpiAwarenessPtr>(
67               ::GetProcAddress(shcore_dll, "GetProcessDpiAwareness"));
68       if (func_ptr) {
69         PROCESS_DPI_AWARENESS awareness;
70         if (SUCCEEDED(func_ptr(nullptr, &awareness)) &&
71             awareness == PROCESS_PER_MONITOR_DPI_AWARE)
72           per_monitor_dpi_aware = PerMonitorDpiAware::PER_MONITOR_DPI_AWARE;
73       }
74     }
75   }
76   return per_monitor_dpi_aware == PerMonitorDpiAware::PER_MONITOR_DPI_AWARE;
77 }
78 
79 // DPI value for 1x scale factor.
80 #define DPI_1X 96.0f
81 
GetWindowScaleFactor(HWND hwnd)82 float GetWindowScaleFactor(HWND hwnd) {
83   if (hwnd && IsProcessPerMonitorDpiAware()) {
84     typedef UINT(WINAPI * GetDpiForWindowPtr)(HWND);
85     static GetDpiForWindowPtr func_ptr = reinterpret_cast<GetDpiForWindowPtr>(
86         GetProcAddress(GetModuleHandle(L"user32.dll"), "GetDpiForWindow"));
87     if (func_ptr)
88       return static_cast<float>(func_ptr(hwnd)) / DPI_1X;
89   }
90 
91   return client::GetDeviceScaleFactor();
92 }
93 
GetButtonWidth(HWND hwnd)94 int GetButtonWidth(HWND hwnd) {
95   return LogicalToDevice(BUTTON_WIDTH, GetWindowScaleFactor(hwnd));
96 }
97 
GetURLBarHeight(HWND hwnd)98 int GetURLBarHeight(HWND hwnd) {
99   return LogicalToDevice(URLBAR_HEIGHT, GetWindowScaleFactor(hwnd));
100 }
101 
102 }  // namespace
103 
RootWindowWin()104 RootWindowWin::RootWindowWin()
105     : with_controls_(false),
106       always_on_top_(false),
107       with_osr_(false),
108       with_extension_(false),
109       is_popup_(false),
110       start_rect_(),
111       initialized_(false),
112       hwnd_(nullptr),
113       draggable_region_(nullptr),
114       font_(nullptr),
115       font_height_(0),
116       back_hwnd_(nullptr),
117       forward_hwnd_(nullptr),
118       reload_hwnd_(nullptr),
119       stop_hwnd_(nullptr),
120       edit_hwnd_(nullptr),
121       edit_wndproc_old_(nullptr),
122       find_hwnd_(nullptr),
123       find_message_id_(0),
124       find_wndproc_old_(nullptr),
125       find_state_(),
126       find_next_(false),
127       find_match_case_last_(false),
128       window_destroyed_(false),
129       browser_destroyed_(false),
130       called_enable_non_client_dpi_scaling_(false) {
131   find_buff_[0] = 0;
132 
133   // Create a HRGN representing the draggable window area.
134   draggable_region_ = ::CreateRectRgn(0, 0, 0, 0);
135 }
136 
~RootWindowWin()137 RootWindowWin::~RootWindowWin() {
138   REQUIRE_MAIN_THREAD();
139 
140   ::DeleteObject(draggable_region_);
141   ::DeleteObject(font_);
142 
143   // The window and browser should already have been destroyed.
144   DCHECK(window_destroyed_);
145   DCHECK(browser_destroyed_);
146 }
147 
Init(RootWindow::Delegate * delegate,std::unique_ptr<RootWindowConfig> config,const CefBrowserSettings & settings)148 void RootWindowWin::Init(RootWindow::Delegate* delegate,
149                          std::unique_ptr<RootWindowConfig> config,
150                          const CefBrowserSettings& settings) {
151   DCHECK(delegate);
152   DCHECK(!initialized_);
153 
154   delegate_ = delegate;
155   with_controls_ = config->with_controls;
156   always_on_top_ = config->always_on_top;
157   with_osr_ = config->with_osr;
158   with_extension_ = config->with_extension;
159 
160   start_rect_.left = config->bounds.x;
161   start_rect_.top = config->bounds.y;
162   start_rect_.right = config->bounds.x + config->bounds.width;
163   start_rect_.bottom = config->bounds.y + config->bounds.height;
164 
165   CreateBrowserWindow(config->url);
166 
167   initialized_ = true;
168 
169   // Create the native root window on the main thread.
170   if (CURRENTLY_ON_MAIN_THREAD()) {
171     CreateRootWindow(settings, config->initially_hidden);
172   } else {
173     MAIN_POST_CLOSURE(base::BindOnce(&RootWindowWin::CreateRootWindow, this,
174                                      settings, config->initially_hidden));
175   }
176 }
177 
InitAsPopup(RootWindow::Delegate * delegate,bool with_controls,bool with_osr,const CefPopupFeatures & popupFeatures,CefWindowInfo & windowInfo,CefRefPtr<CefClient> & client,CefBrowserSettings & settings)178 void RootWindowWin::InitAsPopup(RootWindow::Delegate* delegate,
179                                 bool with_controls,
180                                 bool with_osr,
181                                 const CefPopupFeatures& popupFeatures,
182                                 CefWindowInfo& windowInfo,
183                                 CefRefPtr<CefClient>& client,
184                                 CefBrowserSettings& settings) {
185   CEF_REQUIRE_UI_THREAD();
186 
187   DCHECK(delegate);
188   DCHECK(!initialized_);
189 
190   delegate_ = delegate;
191   with_controls_ = with_controls;
192   with_osr_ = with_osr;
193   is_popup_ = true;
194 
195   if (popupFeatures.xSet)
196     start_rect_.left = popupFeatures.x;
197   if (popupFeatures.ySet)
198     start_rect_.top = popupFeatures.y;
199   if (popupFeatures.widthSet)
200     start_rect_.right = start_rect_.left + popupFeatures.width;
201   if (popupFeatures.heightSet)
202     start_rect_.bottom = start_rect_.top + popupFeatures.height;
203 
204   CreateBrowserWindow(std::string());
205 
206   initialized_ = true;
207 
208   // The new popup is initially parented to a temporary window. The native root
209   // window will be created after the browser is created and the popup window
210   // will be re-parented to it at that time.
211   browser_window_->GetPopupConfig(TempWindow::GetWindowHandle(), windowInfo,
212                                   client, settings);
213 }
214 
Show(ShowMode mode)215 void RootWindowWin::Show(ShowMode mode) {
216   REQUIRE_MAIN_THREAD();
217 
218   if (!hwnd_)
219     return;
220 
221   int nCmdShow = SW_SHOWNORMAL;
222   switch (mode) {
223     case ShowMinimized:
224       nCmdShow = SW_SHOWMINIMIZED;
225       break;
226     case ShowMaximized:
227       nCmdShow = SW_SHOWMAXIMIZED;
228       break;
229     case ShowNoActivate:
230       nCmdShow = SW_SHOWNOACTIVATE;
231       break;
232     default:
233       break;
234   }
235 
236   ShowWindow(hwnd_, nCmdShow);
237   UpdateWindow(hwnd_);
238 }
239 
Hide()240 void RootWindowWin::Hide() {
241   REQUIRE_MAIN_THREAD();
242 
243   if (hwnd_)
244     ShowWindow(hwnd_, SW_HIDE);
245 }
246 
SetBounds(int x,int y,size_t width,size_t height)247 void RootWindowWin::SetBounds(int x, int y, size_t width, size_t height) {
248   REQUIRE_MAIN_THREAD();
249 
250   if (hwnd_) {
251     SetWindowPos(hwnd_, nullptr, x, y, static_cast<int>(width),
252                  static_cast<int>(height), SWP_NOZORDER);
253   }
254 }
255 
Close(bool force)256 void RootWindowWin::Close(bool force) {
257   REQUIRE_MAIN_THREAD();
258 
259   if (hwnd_) {
260     if (force)
261       DestroyWindow(hwnd_);
262     else
263       PostMessage(hwnd_, WM_CLOSE, 0, 0);
264   }
265 }
266 
SetDeviceScaleFactor(float device_scale_factor)267 void RootWindowWin::SetDeviceScaleFactor(float device_scale_factor) {
268   REQUIRE_MAIN_THREAD();
269 
270   if (browser_window_ && with_osr_)
271     browser_window_->SetDeviceScaleFactor(device_scale_factor);
272 }
273 
GetDeviceScaleFactor() const274 float RootWindowWin::GetDeviceScaleFactor() const {
275   REQUIRE_MAIN_THREAD();
276 
277   if (browser_window_ && with_osr_)
278     return browser_window_->GetDeviceScaleFactor();
279 
280   NOTREACHED();
281   return 0.0f;
282 }
283 
GetBrowser() const284 CefRefPtr<CefBrowser> RootWindowWin::GetBrowser() const {
285   REQUIRE_MAIN_THREAD();
286 
287   if (browser_window_)
288     return browser_window_->GetBrowser();
289   return nullptr;
290 }
291 
GetWindowHandle() const292 ClientWindowHandle RootWindowWin::GetWindowHandle() const {
293   REQUIRE_MAIN_THREAD();
294   return hwnd_;
295 }
296 
WithWindowlessRendering() const297 bool RootWindowWin::WithWindowlessRendering() const {
298   REQUIRE_MAIN_THREAD();
299   return with_osr_;
300 }
301 
WithExtension() const302 bool RootWindowWin::WithExtension() const {
303   REQUIRE_MAIN_THREAD();
304   return with_extension_;
305 }
306 
CreateBrowserWindow(const std::string & startup_url)307 void RootWindowWin::CreateBrowserWindow(const std::string& startup_url) {
308   if (with_osr_) {
309     OsrRendererSettings settings = {};
310     MainContext::Get()->PopulateOsrSettings(&settings);
311     browser_window_.reset(new BrowserWindowOsrWin(this, startup_url, settings));
312   } else {
313     browser_window_.reset(new BrowserWindowStdWin(this, startup_url));
314   }
315 }
316 
CreateRootWindow(const CefBrowserSettings & settings,bool initially_hidden)317 void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings,
318                                      bool initially_hidden) {
319   REQUIRE_MAIN_THREAD();
320   DCHECK(!hwnd_);
321 
322   HINSTANCE hInstance = GetModuleHandle(nullptr);
323 
324   // Load strings from the resource file.
325   const std::wstring& window_title = GetResourceString(IDS_APP_TITLE);
326   const std::wstring& window_class = GetResourceString(IDC_CEFCLIENT);
327 
328   const cef_color_t background_color = MainContext::Get()->GetBackgroundColor();
329   const HBRUSH background_brush = CreateSolidBrush(
330       RGB(CefColorGetR(background_color), CefColorGetG(background_color),
331           CefColorGetB(background_color)));
332 
333   // Register the window class.
334   RegisterRootClass(hInstance, window_class, background_brush);
335 
336   // Register the message used with the find dialog.
337   find_message_id_ = RegisterWindowMessage(FINDMSGSTRING);
338   CHECK(find_message_id_);
339 
340   CefRefPtr<CefCommandLine> command_line =
341       CefCommandLine::GetGlobalCommandLine();
342   const bool no_activate = command_line->HasSwitch(switches::kNoActivate);
343 
344   const DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
345   DWORD dwExStyle = always_on_top_ ? WS_EX_TOPMOST : 0;
346   if (no_activate) {
347     // Don't activate the browser window on creation.
348     dwExStyle |= WS_EX_NOACTIVATE;
349   }
350 
351   int x, y, width, height;
352   if (::IsRectEmpty(&start_rect_)) {
353     // Use the default window position/size.
354     x = y = width = height = CW_USEDEFAULT;
355   } else {
356     // Adjust the window size to account for window frame and controls.
357     RECT window_rect = start_rect_;
358     ::AdjustWindowRectEx(&window_rect, dwStyle, with_controls_, dwExStyle);
359 
360     x = start_rect_.left;
361     y = start_rect_.top;
362     width = window_rect.right - window_rect.left;
363     height = window_rect.bottom - window_rect.top;
364   }
365 
366   browser_settings_ = settings;
367 
368   // Create the main window initially hidden.
369   CreateWindowEx(dwExStyle, window_class.c_str(), window_title.c_str(), dwStyle,
370                  x, y, width, height, nullptr, nullptr, hInstance, this);
371   CHECK(hwnd_);
372 
373   if (!called_enable_non_client_dpi_scaling_ && IsProcessPerMonitorDpiAware()) {
374     // This call gets Windows to scale the non-client area when WM_DPICHANGED
375     // is fired on Windows versions < 10.0.14393.0.
376     // Derived signature; not available in headers.
377     typedef LRESULT(WINAPI * EnableChildWindowDpiMessagePtr)(HWND, BOOL);
378     static EnableChildWindowDpiMessagePtr func_ptr =
379         reinterpret_cast<EnableChildWindowDpiMessagePtr>(GetProcAddress(
380             GetModuleHandle(L"user32.dll"), "EnableChildWindowDpiMessage"));
381     if (func_ptr)
382       func_ptr(hwnd_, TRUE);
383   }
384 
385   if (!initially_hidden) {
386     // Show this window.
387     Show(no_activate ? ShowNoActivate : ShowNormal);
388   }
389 }
390 
391 // static
RegisterRootClass(HINSTANCE hInstance,const std::wstring & window_class,HBRUSH background_brush)392 void RootWindowWin::RegisterRootClass(HINSTANCE hInstance,
393                                       const std::wstring& window_class,
394                                       HBRUSH background_brush) {
395   // Only register the class one time.
396   static bool class_registered = false;
397   if (class_registered)
398     return;
399   class_registered = true;
400 
401   WNDCLASSEX wcex;
402 
403   wcex.cbSize = sizeof(WNDCLASSEX);
404 
405   wcex.style = CS_HREDRAW | CS_VREDRAW;
406   wcex.lpfnWndProc = RootWndProc;
407   wcex.cbClsExtra = 0;
408   wcex.cbWndExtra = 0;
409   wcex.hInstance = hInstance;
410   wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CEFCLIENT));
411   wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
412   wcex.hbrBackground = background_brush;
413   wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CEFCLIENT);
414   wcex.lpszClassName = window_class.c_str();
415   wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
416 
417   RegisterClassEx(&wcex);
418 }
419 
420 // static
EditWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)421 LRESULT CALLBACK RootWindowWin::EditWndProc(HWND hWnd,
422                                             UINT message,
423                                             WPARAM wParam,
424                                             LPARAM lParam) {
425   REQUIRE_MAIN_THREAD();
426 
427   RootWindowWin* self = GetUserDataPtr<RootWindowWin*>(hWnd);
428   DCHECK(self);
429   DCHECK(hWnd == self->edit_hwnd_);
430 
431   switch (message) {
432     case WM_CHAR:
433       if (wParam == VK_RETURN) {
434         // When the user hits the enter key load the URL.
435         CefRefPtr<CefBrowser> browser = self->GetBrowser();
436         if (browser) {
437           wchar_t strPtr[MAX_URL_LENGTH + 1] = {0};
438           *((LPWORD)strPtr) = MAX_URL_LENGTH;
439           LRESULT strLen = SendMessage(hWnd, EM_GETLINE, 0, (LPARAM)strPtr);
440           if (strLen > 0) {
441             strPtr[strLen] = 0;
442             browser->GetMainFrame()->LoadURL(strPtr);
443           }
444         }
445         return 0;
446       }
447       break;
448     case WM_NCDESTROY:
449       // Clear the reference to |self|.
450       SetUserDataPtr(hWnd, nullptr);
451       self->edit_hwnd_ = nullptr;
452       break;
453   }
454 
455   return CallWindowProc(self->edit_wndproc_old_, hWnd, message, wParam, lParam);
456 }
457 
458 // static
FindWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)459 LRESULT CALLBACK RootWindowWin::FindWndProc(HWND hWnd,
460                                             UINT message,
461                                             WPARAM wParam,
462                                             LPARAM lParam) {
463   REQUIRE_MAIN_THREAD();
464 
465   RootWindowWin* self = GetUserDataPtr<RootWindowWin*>(hWnd);
466   DCHECK(self);
467   DCHECK(hWnd == self->find_hwnd_);
468 
469   switch (message) {
470     case WM_ACTIVATE:
471       // Set this dialog as current when activated.
472       MainMessageLoop::Get()->SetCurrentModelessDialog(wParam == 0 ? nullptr
473                                                                    : hWnd);
474       return FALSE;
475     case WM_NCDESTROY:
476       // Clear the reference to |self|.
477       SetUserDataPtr(hWnd, nullptr);
478       self->find_hwnd_ = nullptr;
479       break;
480   }
481 
482   return CallWindowProc(self->find_wndproc_old_, hWnd, message, wParam, lParam);
483 }
484 
485 // static
RootWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)486 LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd,
487                                             UINT message,
488                                             WPARAM wParam,
489                                             LPARAM lParam) {
490   REQUIRE_MAIN_THREAD();
491 
492   RootWindowWin* self = nullptr;
493   if (message != WM_NCCREATE) {
494     self = GetUserDataPtr<RootWindowWin*>(hWnd);
495     if (!self)
496       return DefWindowProc(hWnd, message, wParam, lParam);
497     DCHECK_EQ(hWnd, self->hwnd_);
498   }
499 
500   if (self && message == self->find_message_id_) {
501     // Message targeting the find dialog.
502     LPFINDREPLACE lpfr = reinterpret_cast<LPFINDREPLACE>(lParam);
503     CHECK(lpfr == &self->find_state_);
504     self->OnFindEvent();
505     return 0;
506   }
507 
508   // Callback for the main window
509   switch (message) {
510     case WM_COMMAND:
511       if (self->OnCommand(LOWORD(wParam)))
512         return 0;
513       break;
514 
515     case WM_GETOBJECT: {
516       // Only the lower 32 bits of lParam are valid when checking the object id
517       // because it sometimes gets sign-extended incorrectly (but not always).
518       DWORD obj_id = static_cast<DWORD>(static_cast<DWORD_PTR>(lParam));
519 
520       // Accessibility readers will send an OBJID_CLIENT message.
521       if (static_cast<DWORD>(OBJID_CLIENT) == obj_id) {
522         if (self->GetBrowser() && self->GetBrowser()->GetHost())
523           self->GetBrowser()->GetHost()->SetAccessibilityState(STATE_ENABLED);
524       }
525     } break;
526 
527     case WM_PAINT:
528       self->OnPaint();
529       return 0;
530 
531     case WM_ACTIVATE:
532       self->OnActivate(LOWORD(wParam) != WA_INACTIVE);
533       // Allow DefWindowProc to set keyboard focus.
534       break;
535 
536     case WM_SETFOCUS:
537       self->OnFocus();
538       return 0;
539 
540     case WM_SIZE:
541       self->OnSize(wParam == SIZE_MINIMIZED);
542       break;
543 
544     case WM_MOVING:
545     case WM_MOVE:
546       self->OnMove();
547       return 0;
548 
549     case WM_DPICHANGED:
550       self->OnDpiChanged(wParam, lParam);
551       break;
552 
553     case WM_ERASEBKGND:
554       if (self->OnEraseBkgnd())
555         break;
556       // Don't erase the background.
557       return 0;
558 
559     case WM_ENTERMENULOOP:
560       if (!wParam) {
561         // Entering the menu loop for the application menu.
562         CefSetOSModalLoop(true);
563       }
564       break;
565 
566     case WM_EXITMENULOOP:
567       if (!wParam) {
568         // Exiting the menu loop for the application menu.
569         CefSetOSModalLoop(false);
570       }
571       break;
572 
573     case WM_CLOSE:
574       if (self->OnClose())
575         return 0;  // Cancel the close.
576       break;
577 
578     case WM_NCHITTEST: {
579       LRESULT hit = DefWindowProc(hWnd, message, wParam, lParam);
580       if (hit == HTCLIENT) {
581         POINTS points = MAKEPOINTS(lParam);
582         POINT point = {points.x, points.y};
583         ::ScreenToClient(hWnd, &point);
584         if (::PtInRegion(self->draggable_region_, point.x, point.y)) {
585           // If cursor is inside a draggable region return HTCAPTION to allow
586           // dragging.
587           return HTCAPTION;
588         }
589       }
590       return hit;
591     }
592 
593     case WM_NCCREATE: {
594       CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
595       self = reinterpret_cast<RootWindowWin*>(cs->lpCreateParams);
596       DCHECK(self);
597       // Associate |self| with the main window.
598       SetUserDataPtr(hWnd, self);
599       self->hwnd_ = hWnd;
600 
601       self->OnNCCreate(cs);
602     } break;
603 
604     case WM_CREATE:
605       self->OnCreate(reinterpret_cast<CREATESTRUCT*>(lParam));
606       break;
607 
608     case WM_NCDESTROY:
609       // Clear the reference to |self|.
610       SetUserDataPtr(hWnd, nullptr);
611       self->hwnd_ = nullptr;
612       self->OnDestroyed();
613       break;
614   }
615 
616   return DefWindowProc(hWnd, message, wParam, lParam);
617 }
618 
OnPaint()619 void RootWindowWin::OnPaint() {
620   PAINTSTRUCT ps;
621   BeginPaint(hwnd_, &ps);
622   EndPaint(hwnd_, &ps);
623 }
624 
OnFocus()625 void RootWindowWin::OnFocus() {
626   // Selecting "Close window" from the task bar menu may send a focus
627   // notification even though the window is currently disabled (e.g. while a
628   // modal JS dialog is displayed).
629   if (browser_window_ && ::IsWindowEnabled(hwnd_))
630     browser_window_->SetFocus(true);
631 }
632 
OnActivate(bool active)633 void RootWindowWin::OnActivate(bool active) {
634   if (active)
635     delegate_->OnRootWindowActivated(this);
636 }
637 
OnSize(bool minimized)638 void RootWindowWin::OnSize(bool minimized) {
639   if (minimized) {
640     // Notify the browser window that it was hidden and do nothing further.
641     if (browser_window_)
642       browser_window_->Hide();
643     return;
644   }
645 
646   if (browser_window_)
647     browser_window_->Show();
648 
649   RECT rect;
650   GetClientRect(hwnd_, &rect);
651 
652   if (with_controls_ && edit_hwnd_) {
653     const int button_width = GetButtonWidth(hwnd_);
654     const int urlbar_height = GetURLBarHeight(hwnd_);
655     const int font_height = LogicalToDevice(14, GetWindowScaleFactor(hwnd_));
656 
657     if (font_height != font_height_) {
658       font_height_ = font_height;
659       if (font_) {
660         DeleteObject(font_);
661       }
662 
663       // Create a scaled font.
664       font_ =
665           ::CreateFont(-font_height, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE,
666                        DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
667                        DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial");
668 
669       SendMessage(back_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_),
670                   TRUE);
671       SendMessage(forward_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_),
672                   TRUE);
673       SendMessage(reload_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_),
674                   TRUE);
675       SendMessage(stop_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_),
676                   TRUE);
677       SendMessage(edit_hwnd_, WM_SETFONT, reinterpret_cast<WPARAM>(font_),
678                   TRUE);
679     }
680 
681     // Resize the window and address bar to match the new frame size.
682     rect.top += urlbar_height;
683 
684     int x_offset = rect.left;
685 
686     // |browser_hwnd| may be nullptr if the browser has not yet been created.
687     HWND browser_hwnd = nullptr;
688     if (browser_window_)
689       browser_hwnd = browser_window_->GetWindowHandle();
690 
691     // Resize all controls.
692     HDWP hdwp = BeginDeferWindowPos(browser_hwnd ? 6 : 5);
693     hdwp = DeferWindowPos(hdwp, back_hwnd_, nullptr, x_offset, 0, button_width,
694                           urlbar_height, SWP_NOZORDER);
695     x_offset += button_width;
696     hdwp = DeferWindowPos(hdwp, forward_hwnd_, nullptr, x_offset, 0,
697                           button_width, urlbar_height, SWP_NOZORDER);
698     x_offset += button_width;
699     hdwp = DeferWindowPos(hdwp, reload_hwnd_, nullptr, x_offset, 0,
700                           button_width, urlbar_height, SWP_NOZORDER);
701     x_offset += button_width;
702     hdwp = DeferWindowPos(hdwp, stop_hwnd_, nullptr, x_offset, 0, button_width,
703                           urlbar_height, SWP_NOZORDER);
704     x_offset += button_width;
705     hdwp = DeferWindowPos(hdwp, edit_hwnd_, nullptr, x_offset, 0,
706                           rect.right - x_offset, urlbar_height, SWP_NOZORDER);
707 
708     if (browser_hwnd) {
709       hdwp = DeferWindowPos(hdwp, browser_hwnd, nullptr, rect.left, rect.top,
710                             rect.right - rect.left, rect.bottom - rect.top,
711                             SWP_NOZORDER);
712     }
713 
714     BOOL result = EndDeferWindowPos(hdwp);
715     ALLOW_UNUSED_LOCAL(result);
716     DCHECK(result);
717   } else if (browser_window_) {
718     // Size the browser window to the whole client area.
719     browser_window_->SetBounds(0, 0, rect.right, rect.bottom);
720   }
721 }
722 
OnMove()723 void RootWindowWin::OnMove() {
724   // Notify the browser of move events so that popup windows are displayed
725   // in the correct location and dismissed when the window moves.
726   CefRefPtr<CefBrowser> browser = GetBrowser();
727   if (browser)
728     browser->GetHost()->NotifyMoveOrResizeStarted();
729 }
730 
OnDpiChanged(WPARAM wParam,LPARAM lParam)731 void RootWindowWin::OnDpiChanged(WPARAM wParam, LPARAM lParam) {
732   if (LOWORD(wParam) != HIWORD(wParam)) {
733     NOTIMPLEMENTED() << "Received non-square scaling factors";
734     return;
735   }
736 
737   if (browser_window_ && with_osr_) {
738     // Scale factor for the new display.
739     const float display_scale_factor =
740         static_cast<float>(LOWORD(wParam)) / DPI_1X;
741     browser_window_->SetDeviceScaleFactor(display_scale_factor);
742   }
743 
744   // Suggested size and position of the current window scaled for the new DPI.
745   const RECT* rect = reinterpret_cast<RECT*>(lParam);
746   SetBounds(rect->left, rect->top, rect->right - rect->left,
747             rect->bottom - rect->top);
748 }
749 
OnEraseBkgnd()750 bool RootWindowWin::OnEraseBkgnd() {
751   // Erase the background when the browser does not exist.
752   return (GetBrowser() == nullptr);
753 }
754 
OnCommand(UINT id)755 bool RootWindowWin::OnCommand(UINT id) {
756   if (id >= ID_TESTS_FIRST && id <= ID_TESTS_LAST) {
757     delegate_->OnTest(this, id);
758     return true;
759   }
760 
761   switch (id) {
762     case IDM_ABOUT:
763       OnAbout();
764       return true;
765     case IDM_EXIT:
766       delegate_->OnExit(this);
767       return true;
768     case ID_FIND:
769       OnFind();
770       return true;
771     case IDC_NAV_BACK:  // Back button
772       if (CefRefPtr<CefBrowser> browser = GetBrowser())
773         browser->GoBack();
774       return true;
775     case IDC_NAV_FORWARD:  // Forward button
776       if (CefRefPtr<CefBrowser> browser = GetBrowser())
777         browser->GoForward();
778       return true;
779     case IDC_NAV_RELOAD:  // Reload button
780       if (CefRefPtr<CefBrowser> browser = GetBrowser())
781         browser->Reload();
782       return true;
783     case IDC_NAV_STOP:  // Stop button
784       if (CefRefPtr<CefBrowser> browser = GetBrowser())
785         browser->StopLoad();
786       return true;
787   }
788 
789   return false;
790 }
791 
OnFind()792 void RootWindowWin::OnFind() {
793   if (find_hwnd_) {
794     // Give focus to the existing find dialog.
795     ::SetFocus(find_hwnd_);
796     return;
797   }
798 
799   // Configure dialog state.
800   ZeroMemory(&find_state_, sizeof(find_state_));
801   find_state_.lStructSize = sizeof(find_state_);
802   find_state_.hwndOwner = hwnd_;
803   find_state_.lpstrFindWhat = find_buff_;
804   find_state_.wFindWhatLen = sizeof(find_buff_);
805   find_state_.Flags = FR_HIDEWHOLEWORD | FR_DOWN;
806 
807   // Create the dialog.
808   find_hwnd_ = FindText(&find_state_);
809 
810   // Override the dialog's window procedure.
811   find_wndproc_old_ = SetWndProcPtr(find_hwnd_, FindWndProc);
812 
813   // Associate |self| with the dialog.
814   SetUserDataPtr(find_hwnd_, this);
815 }
816 
OnFindEvent()817 void RootWindowWin::OnFindEvent() {
818   CefRefPtr<CefBrowser> browser = GetBrowser();
819 
820   if (find_state_.Flags & FR_DIALOGTERM) {
821     // The find dialog box has been dismissed so invalidate the handle and
822     // reset the search results.
823     if (browser) {
824       browser->GetHost()->StopFinding(true);
825       find_what_last_.clear();
826       find_next_ = false;
827     }
828   } else if ((find_state_.Flags & FR_FINDNEXT) && browser) {
829     // Search for the requested string.
830     bool match_case = ((find_state_.Flags & FR_MATCHCASE) ? true : false);
831     const std::wstring& find_what = find_buff_;
832     if (match_case != find_match_case_last_ || find_what != find_what_last_) {
833       // The search string has changed, so reset the search results.
834       if (!find_what.empty()) {
835         browser->GetHost()->StopFinding(true);
836         find_next_ = false;
837       }
838       find_match_case_last_ = match_case;
839       find_what_last_ = find_buff_;
840     }
841 
842     browser->GetHost()->Find(find_what,
843                              (find_state_.Flags & FR_DOWN) ? true : false,
844                              match_case, find_next_);
845     if (!find_next_)
846       find_next_ = true;
847   }
848 }
849 
OnAbout()850 void RootWindowWin::OnAbout() {
851   // Show the about box.
852   DialogBox(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd_,
853             AboutWndProc);
854 }
855 
OnNCCreate(LPCREATESTRUCT lpCreateStruct)856 void RootWindowWin::OnNCCreate(LPCREATESTRUCT lpCreateStruct) {
857   if (IsProcessPerMonitorDpiAware()) {
858     // This call gets Windows to scale the non-client area when WM_DPICHANGED
859     // is fired on Windows versions >= 10.0.14393.0.
860     typedef BOOL(WINAPI * EnableNonClientDpiScalingPtr)(HWND);
861     static EnableNonClientDpiScalingPtr func_ptr =
862         reinterpret_cast<EnableNonClientDpiScalingPtr>(GetProcAddress(
863             GetModuleHandle(L"user32.dll"), "EnableNonClientDpiScaling"));
864     called_enable_non_client_dpi_scaling_ = !!(func_ptr && func_ptr(hwnd_));
865   }
866 }
867 
OnCreate(LPCREATESTRUCT lpCreateStruct)868 void RootWindowWin::OnCreate(LPCREATESTRUCT lpCreateStruct) {
869   const HINSTANCE hInstance = lpCreateStruct->hInstance;
870 
871   RECT rect;
872   GetClientRect(hwnd_, &rect);
873 
874   if (with_controls_) {
875     // Create the child controls.
876     int x_offset = 0;
877 
878     const int button_width = GetButtonWidth(hwnd_);
879     const int urlbar_height = GetURLBarHeight(hwnd_);
880 
881     back_hwnd_ = CreateWindow(
882         L"BUTTON", L"Back", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
883         x_offset, 0, button_width, urlbar_height, hwnd_,
884         reinterpret_cast<HMENU>(IDC_NAV_BACK), hInstance, 0);
885     CHECK(back_hwnd_);
886     x_offset += button_width;
887 
888     forward_hwnd_ =
889         CreateWindow(L"BUTTON", L"Forward",
890                      WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
891                      x_offset, 0, button_width, urlbar_height, hwnd_,
892                      reinterpret_cast<HMENU>(IDC_NAV_FORWARD), hInstance, 0);
893     CHECK(forward_hwnd_);
894     x_offset += button_width;
895 
896     reload_hwnd_ =
897         CreateWindow(L"BUTTON", L"Reload",
898                      WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
899                      x_offset, 0, button_width, urlbar_height, hwnd_,
900                      reinterpret_cast<HMENU>(IDC_NAV_RELOAD), hInstance, 0);
901     CHECK(reload_hwnd_);
902     x_offset += button_width;
903 
904     stop_hwnd_ = CreateWindow(
905         L"BUTTON", L"Stop", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
906         x_offset, 0, button_width, urlbar_height, hwnd_,
907         reinterpret_cast<HMENU>(IDC_NAV_STOP), hInstance, 0);
908     CHECK(stop_hwnd_);
909     x_offset += button_width;
910 
911     edit_hwnd_ = CreateWindow(L"EDIT", 0,
912                               WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT |
913                                   ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_DISABLED,
914                               x_offset, 0, rect.right - button_width * 4,
915                               urlbar_height, hwnd_, 0, hInstance, 0);
916     CHECK(edit_hwnd_);
917 
918     // Override the edit control's window procedure.
919     edit_wndproc_old_ = SetWndProcPtr(edit_hwnd_, EditWndProc);
920 
921     // Associate |this| with the edit window.
922     SetUserDataPtr(edit_hwnd_, this);
923 
924     rect.top += urlbar_height;
925 
926     if (!with_osr_) {
927       // Remove the menu items that are only used with OSR.
928       HMENU hMenu = ::GetMenu(hwnd_);
929       if (hMenu) {
930         HMENU hTestMenu = ::GetSubMenu(hMenu, 2);
931         if (hTestMenu) {
932           ::RemoveMenu(hTestMenu, ID_TESTS_OSR_FPS, MF_BYCOMMAND);
933           ::RemoveMenu(hTestMenu, ID_TESTS_OSR_DSF, MF_BYCOMMAND);
934         }
935       }
936     }
937   } else {
938     // No controls so also remove the default menu.
939     ::SetMenu(hwnd_, nullptr);
940   }
941 
942   const float device_scale_factor = GetWindowScaleFactor(hwnd_);
943 
944   if (with_osr_) {
945     browser_window_->SetDeviceScaleFactor(device_scale_factor);
946   }
947 
948   if (!is_popup_) {
949     // Create the browser window.
950     CefRect cef_rect(rect.left, rect.top, rect.right - rect.left,
951                      rect.bottom - rect.top);
952     browser_window_->CreateBrowser(hwnd_, cef_rect, browser_settings_, nullptr,
953                                    delegate_->GetRequestContext(this));
954   } else {
955     // With popups we already have a browser window. Parent the browser window
956     // to the root window and show it in the correct location.
957     browser_window_->ShowPopup(hwnd_, rect.left, rect.top,
958                                rect.right - rect.left, rect.bottom - rect.top);
959   }
960 }
961 
OnClose()962 bool RootWindowWin::OnClose() {
963   if (browser_window_ && !browser_window_->IsClosing()) {
964     CefRefPtr<CefBrowser> browser = GetBrowser();
965     if (browser) {
966       // Notify the browser window that we would like to close it. This
967       // will result in a call to ClientHandler::DoClose() if the
968       // JavaScript 'onbeforeunload' event handler allows it.
969       browser->GetHost()->CloseBrowser(false);
970 
971       // Cancel the close.
972       return true;
973     }
974   }
975 
976   // Allow the close.
977   return false;
978 }
979 
OnDestroyed()980 void RootWindowWin::OnDestroyed() {
981   window_destroyed_ = true;
982   NotifyDestroyedIfDone();
983 }
984 
OnBrowserCreated(CefRefPtr<CefBrowser> browser)985 void RootWindowWin::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
986   REQUIRE_MAIN_THREAD();
987 
988   if (is_popup_) {
989     // For popup browsers create the root window once the browser has been
990     // created.
991     CreateRootWindow(CefBrowserSettings(), false);
992   } else {
993     // Make sure the browser is sized correctly.
994     OnSize(false);
995   }
996 
997   delegate_->OnBrowserCreated(this, browser);
998 }
999 
OnBrowserWindowDestroyed()1000 void RootWindowWin::OnBrowserWindowDestroyed() {
1001   REQUIRE_MAIN_THREAD();
1002 
1003   browser_window_.reset();
1004 
1005   if (!window_destroyed_) {
1006     // The browser was destroyed first. This could be due to the use of
1007     // off-screen rendering or execution of JavaScript window.close().
1008     // Close the RootWindow.
1009     Close(true);
1010   }
1011 
1012   browser_destroyed_ = true;
1013   NotifyDestroyedIfDone();
1014 }
1015 
OnSetAddress(const std::string & url)1016 void RootWindowWin::OnSetAddress(const std::string& url) {
1017   REQUIRE_MAIN_THREAD();
1018 
1019   if (edit_hwnd_)
1020     SetWindowText(edit_hwnd_, CefString(url).ToWString().c_str());
1021 }
1022 
OnSetTitle(const std::string & title)1023 void RootWindowWin::OnSetTitle(const std::string& title) {
1024   REQUIRE_MAIN_THREAD();
1025 
1026   if (hwnd_)
1027     SetWindowText(hwnd_, CefString(title).ToWString().c_str());
1028 }
1029 
OnSetFullscreen(bool fullscreen)1030 void RootWindowWin::OnSetFullscreen(bool fullscreen) {
1031   REQUIRE_MAIN_THREAD();
1032 
1033   CefRefPtr<CefBrowser> browser = GetBrowser();
1034   if (browser) {
1035     std::unique_ptr<window_test::WindowTestRunnerWin> test_runner(
1036         new window_test::WindowTestRunnerWin());
1037     if (fullscreen)
1038       test_runner->Maximize(browser);
1039     else
1040       test_runner->Restore(browser);
1041   }
1042 }
1043 
OnAutoResize(const CefSize & new_size)1044 void RootWindowWin::OnAutoResize(const CefSize& new_size) {
1045   REQUIRE_MAIN_THREAD();
1046 
1047   if (!hwnd_)
1048     return;
1049 
1050   int new_width = new_size.width;
1051 
1052   // Make the window wide enough to drag by the top menu bar.
1053   if (new_width < 200)
1054     new_width = 200;
1055 
1056   const float device_scale_factor = GetWindowScaleFactor(hwnd_);
1057   RECT rect = {0, 0, LogicalToDevice(new_width, device_scale_factor),
1058                LogicalToDevice(new_size.height, device_scale_factor)};
1059   DWORD style = GetWindowLong(hwnd_, GWL_STYLE);
1060   DWORD ex_style = GetWindowLong(hwnd_, GWL_EXSTYLE);
1061   bool has_menu = !(style & WS_CHILD) && (GetMenu(hwnd_) != nullptr);
1062 
1063   // The size value is for the client area. Calculate the whole window size
1064   // based on the current style.
1065   AdjustWindowRectEx(&rect, style, has_menu, ex_style);
1066 
1067   // Size the window. The left/top values may be negative.
1068   // Also show the window if it's not currently visible.
1069   SetWindowPos(hwnd_, nullptr, 0, 0, rect.right - rect.left,
1070                rect.bottom - rect.top,
1071                SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
1072 }
1073 
OnSetLoadingState(bool isLoading,bool canGoBack,bool canGoForward)1074 void RootWindowWin::OnSetLoadingState(bool isLoading,
1075                                       bool canGoBack,
1076                                       bool canGoForward) {
1077   REQUIRE_MAIN_THREAD();
1078 
1079   if (with_controls_) {
1080     EnableWindow(back_hwnd_, canGoBack);
1081     EnableWindow(forward_hwnd_, canGoForward);
1082     EnableWindow(reload_hwnd_, !isLoading);
1083     EnableWindow(stop_hwnd_, isLoading);
1084     EnableWindow(edit_hwnd_, TRUE);
1085   }
1086 
1087   if (!isLoading && GetWindowLongPtr(hwnd_, GWL_EXSTYLE) & WS_EX_NOACTIVATE) {
1088     // Done with the initial navigation. Remove the WS_EX_NOACTIVATE style so
1089     // that future mouse clicks inside the browser correctly activate and focus
1090     // the window. For the top-level window removing this style causes Windows
1091     // to display the task bar button.
1092     SetWindowLongPtr(hwnd_, GWL_EXSTYLE,
1093                      GetWindowLongPtr(hwnd_, GWL_EXSTYLE) & ~WS_EX_NOACTIVATE);
1094 
1095     if (browser_window_) {
1096       HWND browser_hwnd = browser_window_->GetWindowHandle();
1097       SetWindowLongPtr(
1098           browser_hwnd, GWL_EXSTYLE,
1099           GetWindowLongPtr(browser_hwnd, GWL_EXSTYLE) & ~WS_EX_NOACTIVATE);
1100     }
1101   }
1102 }
1103 
1104 namespace {
1105 
1106 LPCWSTR kParentWndProc = L"CefParentWndProc";
1107 LPCWSTR kDraggableRegion = L"CefDraggableRegion";
1108 
SubclassedWindowProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)1109 LRESULT CALLBACK SubclassedWindowProc(HWND hWnd,
1110                                       UINT message,
1111                                       WPARAM wParam,
1112                                       LPARAM lParam) {
1113   WNDPROC hParentWndProc =
1114       reinterpret_cast<WNDPROC>(::GetPropW(hWnd, kParentWndProc));
1115   HRGN hRegion = reinterpret_cast<HRGN>(::GetPropW(hWnd, kDraggableRegion));
1116 
1117   if (message == WM_NCHITTEST) {
1118     LRESULT hit = CallWindowProc(hParentWndProc, hWnd, message, wParam, lParam);
1119     if (hit == HTCLIENT) {
1120       POINTS points = MAKEPOINTS(lParam);
1121       POINT point = {points.x, points.y};
1122       ::ScreenToClient(hWnd, &point);
1123       if (::PtInRegion(hRegion, point.x, point.y)) {
1124         // Let the parent window handle WM_NCHITTEST by returning HTTRANSPARENT
1125         // in child windows.
1126         return HTTRANSPARENT;
1127       }
1128     }
1129     return hit;
1130   }
1131 
1132   return CallWindowProc(hParentWndProc, hWnd, message, wParam, lParam);
1133 }
1134 
SubclassWindow(HWND hWnd,HRGN hRegion)1135 void SubclassWindow(HWND hWnd, HRGN hRegion) {
1136   HANDLE hParentWndProc = ::GetPropW(hWnd, kParentWndProc);
1137   if (hParentWndProc) {
1138     return;
1139   }
1140 
1141   SetLastError(0);
1142   LONG_PTR hOldWndProc = SetWindowLongPtr(
1143       hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SubclassedWindowProc));
1144   if (hOldWndProc == 0 && GetLastError() != ERROR_SUCCESS) {
1145     return;
1146   }
1147 
1148   ::SetPropW(hWnd, kParentWndProc, reinterpret_cast<HANDLE>(hOldWndProc));
1149   ::SetPropW(hWnd, kDraggableRegion, reinterpret_cast<HANDLE>(hRegion));
1150 }
1151 
UnSubclassWindow(HWND hWnd)1152 void UnSubclassWindow(HWND hWnd) {
1153   LONG_PTR hParentWndProc =
1154       reinterpret_cast<LONG_PTR>(::GetPropW(hWnd, kParentWndProc));
1155   if (hParentWndProc) {
1156     LONG_PTR hPreviousWndProc =
1157         SetWindowLongPtr(hWnd, GWLP_WNDPROC, hParentWndProc);
1158     ALLOW_UNUSED_LOCAL(hPreviousWndProc);
1159     DCHECK_EQ(hPreviousWndProc,
1160               reinterpret_cast<LONG_PTR>(SubclassedWindowProc));
1161   }
1162 
1163   ::RemovePropW(hWnd, kParentWndProc);
1164   ::RemovePropW(hWnd, kDraggableRegion);
1165 }
1166 
SubclassWindowsProc(HWND hwnd,LPARAM lParam)1167 BOOL CALLBACK SubclassWindowsProc(HWND hwnd, LPARAM lParam) {
1168   SubclassWindow(hwnd, reinterpret_cast<HRGN>(lParam));
1169   return TRUE;
1170 }
1171 
UnSubclassWindowsProc(HWND hwnd,LPARAM lParam)1172 BOOL CALLBACK UnSubclassWindowsProc(HWND hwnd, LPARAM lParam) {
1173   UnSubclassWindow(hwnd);
1174   return TRUE;
1175 }
1176 
1177 }  // namespace
1178 
OnSetDraggableRegions(const std::vector<CefDraggableRegion> & regions)1179 void RootWindowWin::OnSetDraggableRegions(
1180     const std::vector<CefDraggableRegion>& regions) {
1181   REQUIRE_MAIN_THREAD();
1182 
1183   // Reset draggable region.
1184   ::SetRectRgn(draggable_region_, 0, 0, 0, 0);
1185 
1186   // Determine new draggable region.
1187   std::vector<CefDraggableRegion>::const_iterator it = regions.begin();
1188   for (; it != regions.end(); ++it) {
1189     HRGN region = ::CreateRectRgn(it->bounds.x, it->bounds.y,
1190                                   it->bounds.x + it->bounds.width,
1191                                   it->bounds.y + it->bounds.height);
1192     ::CombineRgn(draggable_region_, draggable_region_, region,
1193                  it->draggable ? RGN_OR : RGN_DIFF);
1194     ::DeleteObject(region);
1195   }
1196 
1197   // Subclass child window procedures in order to do hit-testing.
1198   // This will be a no-op, if it is already subclassed.
1199   if (hwnd_) {
1200     WNDENUMPROC proc =
1201         !regions.empty() ? SubclassWindowsProc : UnSubclassWindowsProc;
1202     ::EnumChildWindows(hwnd_, proc,
1203                        reinterpret_cast<LPARAM>(draggable_region_));
1204   }
1205 }
1206 
NotifyDestroyedIfDone()1207 void RootWindowWin::NotifyDestroyedIfDone() {
1208   // Notify once both the window and the browser have been destroyed.
1209   if (window_destroyed_ && browser_destroyed_)
1210     delegate_->OnRootWindowDestroyed(this);
1211 }
1212 
1213 }  // namespace client
1214