OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/status_icons/status_tray_win.h" | 5 #include "chrome/browser/ui/views/status_icons/status_tray_win.h" |
6 | 6 |
7 #include <commctrl.h> | 7 #include <commctrl.h> |
8 | 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/threading/non_thread_safe.h" |
| 11 #include "base/threading/thread.h" |
9 #include "base/win/wrapped_window_proc.h" | 12 #include "base/win/wrapped_window_proc.h" |
10 #include "chrome/browser/ui/views/status_icons/status_icon_win.h" | 13 #include "chrome/browser/ui/views/status_icons/status_icon_win.h" |
| 14 #include "chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h" |
11 #include "chrome/common/chrome_constants.h" | 15 #include "chrome/common/chrome_constants.h" |
12 #include "ui/gfx/screen.h" | 16 #include "ui/gfx/screen.h" |
13 #include "ui/gfx/win/hwnd_util.h" | 17 #include "ui/gfx/win/hwnd_util.h" |
14 | 18 |
15 static const UINT kStatusIconMessage = WM_APP + 1; | 19 static const UINT kStatusIconMessage = WM_APP + 1; |
16 | 20 |
17 namespace { | 21 namespace { |
18 // |kBaseIconId| is 2 to avoid conflicts with plugins that hard-code id 1. | 22 // |kBaseIconId| is 2 to avoid conflicts with plugins that hard-code id 1. |
19 const UINT kBaseIconId = 2; | 23 const UINT kBaseIconId = 2; |
20 | 24 |
21 UINT ReservedIconId(StatusTray::StatusIconType type) { | 25 UINT ReservedIconId(StatusTray::StatusIconType type) { |
22 return kBaseIconId + static_cast<UINT>(type); | 26 return kBaseIconId + static_cast<UINT>(type); |
23 } | 27 } |
24 } // namespace | 28 } // namespace |
25 | 29 |
| 30 // Default implementation for StatusTrayStateChanger that communicates to |
| 31 // Exporer.exe via COM. It spawns a background thread with a fresh COM |
| 32 // apartment and requests that the visibility be increased unless the user |
| 33 // has explicitly set the icon to be hidden. |
| 34 class StatusTrayStateChangerProxyImpl : public StatusTrayStateChangerProxy, |
| 35 public base::NonThreadSafe { |
| 36 public: |
| 37 StatusTrayStateChangerProxyImpl() |
| 38 : pending_requests_(0), |
| 39 worker_thread_("StatusIconCOMWorkerThread"), |
| 40 weak_factory_(this) { |
| 41 worker_thread_.init_com_with_mta(false); |
| 42 } |
| 43 |
| 44 virtual void EnqueueChange(UINT icon_id, HWND window) OVERRIDE { |
| 45 DCHECK(CalledOnValidThread()); |
| 46 if (pending_requests_ == 0) |
| 47 worker_thread_.Start(); |
| 48 |
| 49 ++pending_requests_; |
| 50 worker_thread_.message_loop_proxy()->PostTaskAndReply( |
| 51 FROM_HERE, |
| 52 base::Bind( |
| 53 &StatusTrayStateChangerProxyImpl::EnqueueChangeOnWorkerThread, |
| 54 icon_id, |
| 55 window), |
| 56 base::Bind(&StatusTrayStateChangerProxyImpl::ChangeDone, |
| 57 weak_factory_.GetWeakPtr())); |
| 58 } |
| 59 |
| 60 private: |
| 61 // Must be called only on |worker_thread_|, to ensure the correct COM |
| 62 // apartment. |
| 63 static void EnqueueChangeOnWorkerThread(UINT icon_id, HWND window) { |
| 64 // It appears that IUnknowns are coincidentally compatible with |
| 65 // scoped_refptr. Normally I wouldn't depend on that but it seems that |
| 66 // base::win::IUnknownImpl itself depends on that coincidence so it's |
| 67 // already being assumed elsewhere. |
| 68 scoped_refptr<StatusTrayStateChangerWin> status_tray_state_changer( |
| 69 new StatusTrayStateChangerWin(icon_id, window)); |
| 70 status_tray_state_changer->EnsureTrayIconVisible(); |
| 71 } |
| 72 |
| 73 // Called on UI thread. |
| 74 void ChangeDone() { |
| 75 DCHECK(CalledOnValidThread()); |
| 76 DCHECK_GT(pending_requests_, 0); |
| 77 |
| 78 if (--pending_requests_ == 0) |
| 79 worker_thread_.Stop(); |
| 80 } |
| 81 |
| 82 private: |
| 83 int pending_requests_; |
| 84 base::Thread worker_thread_; |
| 85 base::WeakPtrFactory<StatusTrayStateChangerProxyImpl> weak_factory_; |
| 86 |
| 87 DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerProxyImpl); |
| 88 }; |
| 89 |
26 StatusTrayWin::StatusTrayWin() | 90 StatusTrayWin::StatusTrayWin() |
27 : next_icon_id_(1), | 91 : next_icon_id_(1), |
28 atom_(0), | 92 atom_(0), |
29 instance_(NULL), | 93 instance_(NULL), |
30 window_(NULL) { | 94 window_(NULL) { |
31 // Register our window class | 95 // Register our window class |
32 WNDCLASSEX window_class; | 96 WNDCLASSEX window_class; |
33 base::win::InitializeWindowClass( | 97 base::win::InitializeWindowClass( |
34 chrome::kStatusTrayWindowClass, | 98 chrome::kStatusTrayWindowClass, |
35 &base::win::WrappedWindowProc<StatusTrayWin::WndProcStatic>, | 99 &base::win::WrappedWindowProc<StatusTrayWin::WndProcStatic>, |
(...skipping 10 matching lines...) Expand all Loading... |
46 // Create an offscreen window for handling messages for the status icons. We | 110 // Create an offscreen window for handling messages for the status icons. We |
47 // create a hidden WS_POPUP window instead of an HWND_MESSAGE window, because | 111 // create a hidden WS_POPUP window instead of an HWND_MESSAGE window, because |
48 // only top-level windows such as popups can receive broadcast messages like | 112 // only top-level windows such as popups can receive broadcast messages like |
49 // "TaskbarCreated". | 113 // "TaskbarCreated". |
50 window_ = CreateWindow(MAKEINTATOM(atom_), | 114 window_ = CreateWindow(MAKEINTATOM(atom_), |
51 0, WS_POPUP, 0, 0, 0, 0, 0, 0, instance_, 0); | 115 0, WS_POPUP, 0, 0, 0, 0, 0, 0, instance_, 0); |
52 gfx::CheckWindowCreated(window_); | 116 gfx::CheckWindowCreated(window_); |
53 gfx::SetWindowUserData(window_, this); | 117 gfx::SetWindowUserData(window_, this); |
54 } | 118 } |
55 | 119 |
| 120 StatusTrayWin::~StatusTrayWin() { |
| 121 if (window_) |
| 122 DestroyWindow(window_); |
| 123 |
| 124 if (atom_) |
| 125 UnregisterClass(MAKEINTATOM(atom_), instance_); |
| 126 } |
| 127 |
| 128 void StatusTrayWin::UpdateIconVisibilityInBackground( |
| 129 StatusIconWin* status_icon) { |
| 130 if (!state_changer_proxy_.get()) |
| 131 state_changer_proxy_.reset(new StatusTrayStateChangerProxyImpl); |
| 132 |
| 133 state_changer_proxy_->EnqueueChange(status_icon->icon_id(), |
| 134 status_icon->window()); |
| 135 } |
| 136 |
56 LRESULT CALLBACK StatusTrayWin::WndProcStatic(HWND hwnd, | 137 LRESULT CALLBACK StatusTrayWin::WndProcStatic(HWND hwnd, |
57 UINT message, | 138 UINT message, |
58 WPARAM wparam, | 139 WPARAM wparam, |
59 LPARAM lparam) { | 140 LPARAM lparam) { |
60 StatusTrayWin* msg_wnd = reinterpret_cast<StatusTrayWin*>( | 141 StatusTrayWin* msg_wnd = reinterpret_cast<StatusTrayWin*>( |
61 GetWindowLongPtr(hwnd, GWLP_USERDATA)); | 142 GetWindowLongPtr(hwnd, GWLP_USERDATA)); |
62 if (msg_wnd) | 143 if (msg_wnd) |
63 return msg_wnd->WndProc(hwnd, message, wparam, lparam); | 144 return msg_wnd->WndProc(hwnd, message, wparam, lparam); |
64 else | 145 else |
65 return ::DefWindowProc(hwnd, message, wparam, lparam); | 146 return ::DefWindowProc(hwnd, message, wparam, lparam); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 // HandleClickEvent() method. | 190 // HandleClickEvent() method. |
110 gfx::Point cursor_pos( | 191 gfx::Point cursor_pos( |
111 gfx::Screen::GetNativeScreen()->GetCursorScreenPoint()); | 192 gfx::Screen::GetNativeScreen()->GetCursorScreenPoint()); |
112 win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN); | 193 win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN); |
113 return TRUE; | 194 return TRUE; |
114 } | 195 } |
115 } | 196 } |
116 return ::DefWindowProc(hwnd, message, wparam, lparam); | 197 return ::DefWindowProc(hwnd, message, wparam, lparam); |
117 } | 198 } |
118 | 199 |
119 StatusTrayWin::~StatusTrayWin() { | |
120 if (window_) | |
121 DestroyWindow(window_); | |
122 | |
123 if (atom_) | |
124 UnregisterClass(MAKEINTATOM(atom_), instance_); | |
125 } | |
126 | |
127 StatusIcon* StatusTrayWin::CreatePlatformStatusIcon( | 200 StatusIcon* StatusTrayWin::CreatePlatformStatusIcon( |
128 StatusTray::StatusIconType type, | 201 StatusTray::StatusIconType type, |
129 const gfx::ImageSkia& image, | 202 const gfx::ImageSkia& image, |
130 const base::string16& tool_tip) { | 203 const base::string16& tool_tip) { |
131 UINT next_icon_id; | 204 UINT next_icon_id; |
132 if (type == StatusTray::OTHER_ICON) | 205 if (type == StatusTray::OTHER_ICON) |
133 next_icon_id = NextIconId(); | 206 next_icon_id = NextIconId(); |
134 else | 207 else |
135 next_icon_id = ReservedIconId(type); | 208 next_icon_id = ReservedIconId(type); |
136 | 209 |
137 StatusIcon* icon = | 210 StatusIcon* icon = |
138 new StatusIconWin(next_icon_id, window_, kStatusIconMessage); | 211 new StatusIconWin(this, next_icon_id, window_, kStatusIconMessage); |
139 | 212 |
140 icon->SetImage(image); | 213 icon->SetImage(image); |
141 icon->SetToolTip(tool_tip); | 214 icon->SetToolTip(tool_tip); |
142 return icon; | 215 return icon; |
143 } | 216 } |
144 | 217 |
145 UINT StatusTrayWin::NextIconId() { | 218 UINT StatusTrayWin::NextIconId() { |
146 UINT icon_id = next_icon_id_++; | 219 UINT icon_id = next_icon_id_++; |
147 return kBaseIconId + static_cast<UINT>(NAMED_STATUS_ICON_COUNT) + icon_id; | 220 return kBaseIconId + static_cast<UINT>(NAMED_STATUS_ICON_COUNT) + icon_id; |
148 } | 221 } |
149 | 222 |
| 223 void StatusTrayWin::SetStatusTrayStateChangerProxyForTest( |
| 224 scoped_ptr<StatusTrayStateChangerProxy> proxy) { |
| 225 state_changer_proxy_ = proxy.Pass(); |
| 226 } |
| 227 |
150 StatusTray* StatusTray::Create() { | 228 StatusTray* StatusTray::Create() { |
151 return new StatusTrayWin(); | 229 return new StatusTrayWin(); |
152 } | 230 } |
OLD | NEW |