| Index: chrome/browser/ui/views/status_icons/status_tray_win.cc
|
| diff --git a/chrome/browser/ui/views/status_icons/status_tray_win.cc b/chrome/browser/ui/views/status_icons/status_tray_win.cc
|
| index bcbe8e623b1d01aa835f1274565f05b6f3f67037..18830d360830dafd33eaf7d948d47b9d30ed42f6 100644
|
| --- a/chrome/browser/ui/views/status_icons/status_tray_win.cc
|
| +++ b/chrome/browser/ui/views/status_icons/status_tray_win.cc
|
| @@ -6,8 +6,12 @@
|
|
|
| #include <commctrl.h>
|
|
|
| +#include "base/bind.h"
|
| +#include "base/threading/non_thread_safe.h"
|
| +#include "base/threading/thread.h"
|
| #include "base/win/wrapped_window_proc.h"
|
| #include "chrome/browser/ui/views/status_icons/status_icon_win.h"
|
| +#include "chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h"
|
| #include "chrome/common/chrome_constants.h"
|
| #include "ui/gfx/screen.h"
|
| #include "ui/gfx/win/hwnd_util.h"
|
| @@ -23,6 +27,66 @@ UINT ReservedIconId(StatusTray::StatusIconType type) {
|
| }
|
| } // namespace
|
|
|
| +// Default implementation for StatusTrayStateChanger that communicates to
|
| +// Exporer.exe via COM. It spawns a background thread with a fresh COM
|
| +// apartment and requests that the visibility be increased unless the user
|
| +// has explicitly set the icon to be hidden.
|
| +class StatusTrayStateChangerProxyImpl : public StatusTrayStateChangerProxy,
|
| + public base::NonThreadSafe {
|
| + public:
|
| + StatusTrayStateChangerProxyImpl()
|
| + : pending_requests_(0),
|
| + worker_thread_("StatusIconCOMWorkerThread"),
|
| + weak_factory_(this) {
|
| + worker_thread_.init_com_with_mta(false);
|
| + }
|
| +
|
| + virtual void EnqueueChange(UINT icon_id, HWND window) OVERRIDE {
|
| + DCHECK(CalledOnValidThread());
|
| + if (pending_requests_ == 0)
|
| + worker_thread_.Start();
|
| +
|
| + ++pending_requests_;
|
| + worker_thread_.message_loop_proxy()->PostTaskAndReply(
|
| + FROM_HERE,
|
| + base::Bind(
|
| + &StatusTrayStateChangerProxyImpl::EnqueueChangeOnWorkerThread,
|
| + icon_id,
|
| + window),
|
| + base::Bind(&StatusTrayStateChangerProxyImpl::ChangeDone,
|
| + weak_factory_.GetWeakPtr()));
|
| + }
|
| +
|
| + private:
|
| + // Must be called only on |worker_thread_|, to ensure the correct COM
|
| + // apartment.
|
| + static void EnqueueChangeOnWorkerThread(UINT icon_id, HWND window) {
|
| + // It appears that IUnknowns are coincidentally compatible with
|
| + // scoped_refptr. Normally I wouldn't depend on that but it seems that
|
| + // base::win::IUnknownImpl itself depends on that coincidence so it's
|
| + // already being assumed elsewhere.
|
| + scoped_refptr<StatusTrayStateChangerWin> status_tray_state_changer(
|
| + new StatusTrayStateChangerWin(icon_id, window));
|
| + status_tray_state_changer->EnsureTrayIconVisible();
|
| + }
|
| +
|
| + // Called on UI thread.
|
| + void ChangeDone() {
|
| + DCHECK(CalledOnValidThread());
|
| + DCHECK_GT(pending_requests_, 0);
|
| +
|
| + if (--pending_requests_ == 0)
|
| + worker_thread_.Stop();
|
| + }
|
| +
|
| + private:
|
| + int pending_requests_;
|
| + base::Thread worker_thread_;
|
| + base::WeakPtrFactory<StatusTrayStateChangerProxyImpl> weak_factory_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerProxyImpl);
|
| +};
|
| +
|
| StatusTrayWin::StatusTrayWin()
|
| : next_icon_id_(1),
|
| atom_(0),
|
| @@ -53,6 +117,23 @@ StatusTrayWin::StatusTrayWin()
|
| gfx::SetWindowUserData(window_, this);
|
| }
|
|
|
| +StatusTrayWin::~StatusTrayWin() {
|
| + if (window_)
|
| + DestroyWindow(window_);
|
| +
|
| + if (atom_)
|
| + UnregisterClass(MAKEINTATOM(atom_), instance_);
|
| +}
|
| +
|
| +void StatusTrayWin::UpdateIconVisibilityInBackground(
|
| + StatusIconWin* status_icon) {
|
| + if (!state_changer_proxy_.get())
|
| + state_changer_proxy_.reset(new StatusTrayStateChangerProxyImpl);
|
| +
|
| + state_changer_proxy_->EnqueueChange(status_icon->icon_id(),
|
| + status_icon->window());
|
| +}
|
| +
|
| LRESULT CALLBACK StatusTrayWin::WndProcStatic(HWND hwnd,
|
| UINT message,
|
| WPARAM wparam,
|
| @@ -116,14 +197,6 @@ LRESULT CALLBACK StatusTrayWin::WndProc(HWND hwnd,
|
| return ::DefWindowProc(hwnd, message, wparam, lparam);
|
| }
|
|
|
| -StatusTrayWin::~StatusTrayWin() {
|
| - if (window_)
|
| - DestroyWindow(window_);
|
| -
|
| - if (atom_)
|
| - UnregisterClass(MAKEINTATOM(atom_), instance_);
|
| -}
|
| -
|
| StatusIcon* StatusTrayWin::CreatePlatformStatusIcon(
|
| StatusTray::StatusIconType type,
|
| const gfx::ImageSkia& image,
|
| @@ -135,7 +208,7 @@ StatusIcon* StatusTrayWin::CreatePlatformStatusIcon(
|
| next_icon_id = ReservedIconId(type);
|
|
|
| StatusIcon* icon =
|
| - new StatusIconWin(next_icon_id, window_, kStatusIconMessage);
|
| + new StatusIconWin(this, next_icon_id, window_, kStatusIconMessage);
|
|
|
| icon->SetImage(image);
|
| icon->SetToolTip(tool_tip);
|
| @@ -147,6 +220,11 @@ UINT StatusTrayWin::NextIconId() {
|
| return kBaseIconId + static_cast<UINT>(NAMED_STATUS_ICON_COUNT) + icon_id;
|
| }
|
|
|
| +void StatusTrayWin::SetStatusTrayStateChangerProxyForTest(
|
| + scoped_ptr<StatusTrayStateChangerProxy> proxy) {
|
| + state_changer_proxy_ = proxy.Pass();
|
| +}
|
| +
|
| StatusTray* StatusTray::Create() {
|
| return new StatusTrayWin();
|
| }
|
|
|