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