| 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 |