Revert "Only store leading 13 bits of password hash."
[chromium-blink-merge.git] / chrome / browser / ui / views / status_icons / status_tray_win.cc
blob471a00a4398b4871c7c548bc60b0bb48162bcc32
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.
5 #include "chrome/browser/ui/views/status_icons/status_tray_win.h"
7 #include <commctrl.h>
9 #include "base/bind.h"
10 #include "base/profiler/scoped_tracker.h"
11 #include "base/threading/non_thread_safe.h"
12 #include "base/threading/thread.h"
13 #include "base/win/wrapped_window_proc.h"
14 #include "chrome/browser/lifetime/application_lifetime.h"
15 #include "chrome/browser/ui/views/status_icons/status_icon_win.h"
16 #include "chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h"
17 #include "chrome/common/chrome_constants.h"
18 #include "components/browser_watcher/exit_funnel_win.h"
19 #include "ui/gfx/screen.h"
20 #include "ui/gfx/win/hwnd_util.h"
22 static const UINT kStatusIconMessage = WM_APP + 1;
24 namespace {
25 // |kBaseIconId| is 2 to avoid conflicts with plugins that hard-code id 1.
26 const UINT kBaseIconId = 2;
28 UINT ReservedIconId(StatusTray::StatusIconType type) {
29 return kBaseIconId + static_cast<UINT>(type);
32 // See http://crbug.com/412384.
33 void TraceSessionEnding(LPARAM lparam) {
34 browser_watcher::ExitFunnel funnel;
35 if (!funnel.Init(chrome::kBrowserExitCodesRegistryPath,
36 base::GetCurrentProcessHandle())) {
37 return;
40 // This exit path is the prime suspect for most our unclean shutdowns.
41 // Trace all the possible options to WM_ENDSESSION. This may result in
42 // multiple events for a single shutdown, but that's fine.
43 funnel.RecordEvent(L"TraybarEndSession");
45 if (lparam & ENDSESSION_CLOSEAPP)
46 funnel.RecordEvent(L"ES_CloseApp");
47 if (lparam & ENDSESSION_CRITICAL)
48 funnel.RecordEvent(L"ES_Critical");
49 if (lparam & ENDSESSION_LOGOFF)
50 funnel.RecordEvent(L"ES_Logoff");
51 const LPARAM kKnownBits =
52 ENDSESSION_CLOSEAPP | ENDSESSION_CRITICAL | ENDSESSION_LOGOFF;
53 if (lparam & ~kKnownBits)
54 funnel.RecordEvent(L"ES_Other");
57 } // namespace
59 // Default implementation for StatusTrayStateChanger that communicates to
60 // Exporer.exe via COM. It spawns a background thread with a fresh COM
61 // apartment and requests that the visibility be increased unless the user
62 // has explicitly set the icon to be hidden.
63 class StatusTrayStateChangerProxyImpl : public StatusTrayStateChangerProxy,
64 public base::NonThreadSafe {
65 public:
66 StatusTrayStateChangerProxyImpl()
67 : pending_requests_(0),
68 worker_thread_("StatusIconCOMWorkerThread"),
69 weak_factory_(this) {
70 worker_thread_.init_com_with_mta(false);
73 virtual void EnqueueChange(UINT icon_id, HWND window) override {
74 DCHECK(CalledOnValidThread());
75 if (pending_requests_ == 0)
76 worker_thread_.Start();
78 ++pending_requests_;
79 worker_thread_.message_loop_proxy()->PostTaskAndReply(
80 FROM_HERE,
81 base::Bind(
82 &StatusTrayStateChangerProxyImpl::EnqueueChangeOnWorkerThread,
83 icon_id,
84 window),
85 base::Bind(&StatusTrayStateChangerProxyImpl::ChangeDone,
86 weak_factory_.GetWeakPtr()));
89 private:
90 // Must be called only on |worker_thread_|, to ensure the correct COM
91 // apartment.
92 static void EnqueueChangeOnWorkerThread(UINT icon_id, HWND window) {
93 // It appears that IUnknowns are coincidentally compatible with
94 // scoped_refptr. Normally I wouldn't depend on that but it seems that
95 // base::win::IUnknownImpl itself depends on that coincidence so it's
96 // already being assumed elsewhere.
97 scoped_refptr<StatusTrayStateChangerWin> status_tray_state_changer(
98 new StatusTrayStateChangerWin(icon_id, window));
99 status_tray_state_changer->EnsureTrayIconVisible();
102 // Called on UI thread.
103 void ChangeDone() {
104 DCHECK(CalledOnValidThread());
105 DCHECK_GT(pending_requests_, 0);
107 if (--pending_requests_ == 0)
108 worker_thread_.Stop();
111 private:
112 int pending_requests_;
113 base::Thread worker_thread_;
114 base::WeakPtrFactory<StatusTrayStateChangerProxyImpl> weak_factory_;
116 DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerProxyImpl);
119 StatusTrayWin::StatusTrayWin()
120 : next_icon_id_(1),
121 atom_(0),
122 instance_(NULL),
123 window_(NULL) {
124 // Register our window class
125 WNDCLASSEX window_class;
126 base::win::InitializeWindowClass(
127 chrome::kStatusTrayWindowClass,
128 &base::win::WrappedWindowProc<StatusTrayWin::WndProcStatic>,
129 0, 0, 0, NULL, NULL, NULL, NULL, NULL,
130 &window_class);
131 instance_ = window_class.hInstance;
132 atom_ = RegisterClassEx(&window_class);
133 CHECK(atom_);
135 // If the taskbar is re-created after we start up, we have to rebuild all of
136 // our icons.
137 taskbar_created_message_ = RegisterWindowMessage(TEXT("TaskbarCreated"));
139 // Create an offscreen window for handling messages for the status icons. We
140 // create a hidden WS_POPUP window instead of an HWND_MESSAGE window, because
141 // only top-level windows such as popups can receive broadcast messages like
142 // "TaskbarCreated".
143 window_ = CreateWindow(MAKEINTATOM(atom_),
144 0, WS_POPUP, 0, 0, 0, 0, 0, 0, instance_, 0);
145 gfx::CheckWindowCreated(window_);
146 gfx::SetWindowUserData(window_, this);
149 StatusTrayWin::~StatusTrayWin() {
150 if (window_)
151 DestroyWindow(window_);
153 if (atom_)
154 UnregisterClass(MAKEINTATOM(atom_), instance_);
157 void StatusTrayWin::UpdateIconVisibilityInBackground(
158 StatusIconWin* status_icon) {
159 if (!state_changer_proxy_.get())
160 state_changer_proxy_.reset(new StatusTrayStateChangerProxyImpl);
162 state_changer_proxy_->EnqueueChange(status_icon->icon_id(),
163 status_icon->window());
166 LRESULT CALLBACK StatusTrayWin::WndProcStatic(HWND hwnd,
167 UINT message,
168 WPARAM wparam,
169 LPARAM lparam) {
170 // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
171 tracked_objects::ScopedTracker tracking_profile(
172 FROM_HERE_WITH_EXPLICIT_FUNCTION("440919 StatusTrayWin::WndProcStatic"));
174 StatusTrayWin* msg_wnd = reinterpret_cast<StatusTrayWin*>(
175 GetWindowLongPtr(hwnd, GWLP_USERDATA));
176 if (msg_wnd)
177 return msg_wnd->WndProc(hwnd, message, wparam, lparam);
178 else
179 return ::DefWindowProc(hwnd, message, wparam, lparam);
182 LRESULT CALLBACK StatusTrayWin::WndProc(HWND hwnd,
183 UINT message,
184 WPARAM wparam,
185 LPARAM lparam) {
186 if (message == taskbar_created_message_) {
187 // We need to reset all of our icons because the taskbar went away.
188 for (StatusIcons::const_iterator i(status_icons().begin());
189 i != status_icons().end(); ++i) {
190 StatusIconWin* win_icon = static_cast<StatusIconWin*>(*i);
191 win_icon->ResetIcon();
193 return TRUE;
194 } else if (message == kStatusIconMessage) {
195 StatusIconWin* win_icon = NULL;
197 // Find the selected status icon.
198 for (StatusIcons::const_iterator i(status_icons().begin());
199 i != status_icons().end();
200 ++i) {
201 StatusIconWin* current_win_icon = static_cast<StatusIconWin*>(*i);
202 if (current_win_icon->icon_id() == wparam) {
203 win_icon = current_win_icon;
204 break;
208 // It is possible for this procedure to be called with an obsolete icon
209 // id. In that case we should just return early before handling any
210 // actions.
211 if (!win_icon)
212 return TRUE;
214 switch (lparam) {
215 case TB_INDETERMINATE:
216 win_icon->HandleBalloonClickEvent();
217 return TRUE;
219 case WM_LBUTTONDOWN:
220 case WM_RBUTTONDOWN:
221 case WM_CONTEXTMENU:
222 // Walk our icons, find which one was clicked on, and invoke its
223 // HandleClickEvent() method.
224 gfx::Point cursor_pos(
225 gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
226 win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN);
227 return TRUE;
229 } else if (message == WM_ENDSESSION) {
230 // If Chrome is in background-only mode, this is the only notification
231 // it gets that Windows is exiting. Make sure we shutdown in an orderly
232 // fashion.
233 TraceSessionEnding(lparam);
234 chrome::SessionEnding();
236 return ::DefWindowProc(hwnd, message, wparam, lparam);
239 StatusIcon* StatusTrayWin::CreatePlatformStatusIcon(
240 StatusTray::StatusIconType type,
241 const gfx::ImageSkia& image,
242 const base::string16& tool_tip) {
243 UINT next_icon_id;
244 if (type == StatusTray::OTHER_ICON)
245 next_icon_id = NextIconId();
246 else
247 next_icon_id = ReservedIconId(type);
249 StatusIcon* icon =
250 new StatusIconWin(this, next_icon_id, window_, kStatusIconMessage);
252 icon->SetImage(image);
253 icon->SetToolTip(tool_tip);
254 return icon;
257 UINT StatusTrayWin::NextIconId() {
258 UINT icon_id = next_icon_id_++;
259 return kBaseIconId + static_cast<UINT>(NAMED_STATUS_ICON_COUNT) + icon_id;
262 void StatusTrayWin::SetStatusTrayStateChangerProxyForTest(
263 scoped_ptr<StatusTrayStateChangerProxy> proxy) {
264 state_changer_proxy_ = proxy.Pass();
267 StatusTray* StatusTray::Create() {
268 return new StatusTrayWin();