1 // Copyright 2019 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 "chrome/updater/win/ui/ui.h"
6 
7 #include <stdint.h>
8 #include <functional>
9 
10 #include "base/logging.h"
11 #include "chrome/updater/win/ui/constants.h"
12 #include "chrome/updater/win/ui/util.h"
13 #include "chrome/updater/win/util.h"
14 
15 namespace updater {
16 namespace ui {
17 
18 const OmahaWnd::ControlAttributes OmahaWnd::kVisibleTextAttributes = {
19     false, true, true, false, false};
20 const OmahaWnd::ControlAttributes OmahaWnd::kDefaultActiveButtonAttributes = {
21     false, true, true, true, true};
22 const OmahaWnd::ControlAttributes OmahaWnd::kDisabledButtonAttributes = {
23     false, false, false, true, false};
24 const OmahaWnd::ControlAttributes OmahaWnd::kNonDefaultActiveButtonAttributes =
25     {false, true, true, true, false};
26 const OmahaWnd::ControlAttributes OmahaWnd::kVisibleImageAttributes = {
27     false, true, false, false, false};
28 const OmahaWnd::ControlAttributes OmahaWnd::kDisabledNonButtonAttributes = {
29     false, false, false, false, false};
30 
EnableFlatButtons(HWND hwnd_parent)31 void EnableFlatButtons(HWND hwnd_parent) {
32   struct Local {
33     static BOOL CALLBACK EnumProc(HWND hwnd, LPARAM) {
34       DCHECK(hwnd);
35       CWindow wnd(hwnd);
36       const DWORD style = wnd.GetStyle();
37       if (style & BS_FLAT)
38         ::SetWindowTheme(wnd, _T(""), _T(""));
39       return true;
40     }
41   };
42 
43   ::EnumChildWindows(hwnd_parent, &Local::EnumProc, 0);
44 }
45 
HideWindowChildren(HWND hwnd_parent)46 void HideWindowChildren(HWND hwnd_parent) {
47   struct Local {
48     static BOOL CALLBACK EnumProc(HWND hwnd, LPARAM) {
49       DCHECK(hwnd);
50       ShowWindow(hwnd, SW_HIDE);
51       return true;
52     }
53   };
54   ::EnumChildWindows(hwnd_parent, &Local::EnumProc, 0);
55 }
56 
OmahaWnd(int dialog_id,WTL::CMessageLoop * message_loop,HWND parent)57 OmahaWnd::OmahaWnd(int dialog_id, WTL::CMessageLoop* message_loop, HWND parent)
58     : IDD(dialog_id),
59       message_loop_(message_loop),
60       parent_(parent),
61       is_complete_(false),
62       is_close_enabled_(true),
63       events_sink_(nullptr),
64       is_machine_(false) {
65   DCHECK(message_loop);
66 }
67 
~OmahaWnd()68 OmahaWnd::~OmahaWnd() {
69   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
70   DCHECK(!IsWindow());
71 }
72 
Initialize()73 HRESULT OmahaWnd::Initialize() {
74   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
75 
76   if (!Create(parent_)) {
77     VLOG(1) << "Failed to create the window";
78     return E_FAIL;
79   }
80   message_loop_->AddMessageFilter(this);
81 
82   return S_OK;
83 }
84 
PreTranslateMessage(MSG * msg)85 BOOL OmahaWnd::PreTranslateMessage(MSG* msg) {
86   return CWindow::IsDialogMessage(msg);
87 }
88 
InitializeDialog()89 void OmahaWnd::InitializeDialog() {
90   SetWindowText(GetInstallerDisplayName(bundle_name_).c_str());
91 
92   CenterWindow(nullptr);
93   ui::SetWindowIcon(m_hWnd, IDI_APP,
94                     base::win::ScopedGDIObject<HICON>::Receiver(hicon_).get());
95 
96   // Disable the Maximize System Menu item.
97   HMENU menu = ::GetSystemMenu(*this, false);
98   DCHECK(menu);
99   ::EnableMenuItem(menu, SC_MAXIMIZE, MF_BYCOMMAND | MF_GRAYED);
100 
101   progress_bar_.SubclassWindow(GetDlgItem(IDC_PROGRESS));
102 
103   default_font_.CreatePointFont(90, kDialogFont);
104   SendMessageToDescendants(
105       WM_SETFONT, reinterpret_cast<WPARAM>(static_cast<HFONT>(default_font_)),
106       0);
107 
108   font_.CreatePointFont(150, kDialogFont);
109   GetDlgItem(IDC_INSTALLER_STATE_TEXT).SetFont(font_);
110   GetDlgItem(IDC_INFO_TEXT).SetFont(font_);
111   GetDlgItem(IDC_COMPLETE_TEXT).SetFont(font_);
112 
113   error_font_.CreatePointFont(110, kDialogFont);
114   GetDlgItem(IDC_ERROR_TEXT).SetFont(error_font_);
115 
116   CreateOwnerDrawTitleBar(m_hWnd, GetDlgItem(IDC_TITLE_BAR_SPACER), kBkColor);
117   SetCustomDlgColors(kTextColor, kBkColor);
118 
119   EnableFlatButtons(m_hWnd);
120 }
121 
OnClose(UINT,WPARAM,LPARAM,BOOL & handled)122 LRESULT OmahaWnd::OnClose(UINT, WPARAM, LPARAM, BOOL& handled) {
123   MaybeCloseWindow();
124   handled = true;
125   return 0;
126 }
127 
CloseWindow()128 HRESULT OmahaWnd::CloseWindow() {
129   HRESULT hr = DestroyWindow() ? S_OK : HRESULTFromLastError();
130   if (events_sink_)
131     events_sink_->DoClose();
132   return hr;
133 }
134 
MaybeRequestExitProcess()135 void OmahaWnd::MaybeRequestExitProcess() {
136   if (!is_complete_)
137     return;
138 
139   RequestExitProcess();
140 }
141 
RequestExitProcess()142 void OmahaWnd::RequestExitProcess() {
143   if (events_sink_)
144     events_sink_->DoExit();
145 }
146 
OnNCDestroy(UINT,WPARAM,LPARAM,BOOL & handled)147 LRESULT OmahaWnd::OnNCDestroy(UINT, WPARAM, LPARAM, BOOL& handled) {
148   message_loop_->RemoveMessageFilter(this);
149   MaybeRequestExitProcess();
150   handled = false;  // Let ATL default processing handle the WM_NCDESTROY.
151   return 0;
152 }
153 
154 // Called when ESC key is pressed.
OnCancel(WORD,WORD id,HWND,BOOL & handled)155 LRESULT OmahaWnd::OnCancel(WORD, WORD id, HWND, BOOL& handled) {
156   DCHECK_EQ(id, IDCANCEL);
157 
158   if (!is_close_enabled_)
159     return 0;
160 
161   MaybeCloseWindow();
162   handled = true;
163   return 0;
164 }
165 
Show()166 void OmahaWnd::Show() {
167   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
168   if (!IsWindow() || IsWindowVisible())
169     return;
170 
171   CenterWindow(nullptr);
172   SetVisible(true);
173 
174   ::SetForegroundWindow(*this);
175 }
176 
OnComplete()177 bool OmahaWnd::OnComplete() {
178   if (!IsWindow()) {
179     RequestExitProcess();
180     return false;
181   }
182 
183   is_complete_ = true;
184 
185   EnableClose(true);
186 
187   return true;
188 }
189 
SetControlAttributes(int control_id,const ControlAttributes & attributes)190 void OmahaWnd::SetControlAttributes(int control_id,
191                                     const ControlAttributes& attributes) {
192   if (attributes.is_ignore_entry)
193     return;
194 
195   HWND hwnd = GetDlgItem(control_id);
196   DCHECK(hwnd);
197   ::ShowWindow(hwnd, attributes.is_visible ? SW_SHOW : SW_HIDE);
198   ::EnableWindow(hwnd, attributes.is_enabled ? true : false);
199   if (attributes.is_button && attributes.is_default) {
200     // We ask the dialog manager to give the default push button the focus, to
201     // have the <Enter> key work as expected.
202     GotoDlgCtrl(hwnd);
203     LONG style = ::GetWindowLong(hwnd, GWL_STYLE);
204     if (style) {
205       style |= BS_DEFPUSHBUTTON;
206       ::SetWindowLong(hwnd, GWL_STYLE, style);
207     }
208   }
209 }
210 
EnableClose(bool enable)211 HRESULT OmahaWnd::EnableClose(bool enable) {
212   is_close_enabled_ = enable;
213   return EnableSystemCloseButton(is_close_enabled_);
214 }
215 
EnableSystemCloseButton(bool enable)216 HRESULT OmahaWnd::EnableSystemCloseButton(bool enable) {
217   HMENU menu = ::GetSystemMenu(*this, false);
218   DCHECK(menu);
219   uint32_t flags = MF_BYCOMMAND;
220   flags |= enable ? MF_ENABLED : MF_GRAYED;
221   ::EnableMenuItem(menu, SC_CLOSE, flags);
222   RecalcLayout();
223   return S_OK;
224 }
225 
InitializeCommonControls(DWORD control_classes)226 HRESULT InitializeCommonControls(DWORD control_classes) {
227   INITCOMMONCONTROLSEX init_ctrls = {sizeof(INITCOMMONCONTROLSEX), 0};
228   DCHECK_EQ(init_ctrls.dwSize, sizeof(init_ctrls));
229   init_ctrls.dwICC = control_classes;
230   if (!::InitCommonControlsEx(&init_ctrls)) {
231     const DWORD error = ::GetLastError();
232     if (error != ERROR_CLASS_ALREADY_EXISTS)
233       return HRESULT_FROM_WIN32(error);
234   }
235 
236   return S_OK;
237 }
238 
239 }  // namespace ui
240 }  // namespace updater
241