Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(375)

Side by Side Diff: chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc

Issue 110693004: Moves the notification icon out of the status area overflow. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebase. Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 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/browser/ui/views/status_icons/status_tray_state_changer_win.h"
6
7 namespace {
8
9 ////////////////////////////////////////////////////////////////////////////////
10 // Status Tray API
11
12 // The folowing describes the interface to the undocumented Windows Exporer APIs
13 // for manipulating with the status tray area. This code should be used with
14 // care as it can change with versions (even minor versions) of Windows.
15
16 // ITrayNotify is an interface describing the API for manipulating the state of
17 // the Windows notification area, as well as for registering for change
18 // notifications.
19 class __declspec(uuid("FB852B2C-6BAD-4605-9551-F15F87830935")) ITrayNotify
20 : public IUnknown {
21 public:
22 virtual HRESULT STDMETHODCALLTYPE
23 RegisterCallback(INotificationCB* callback) = 0;
24 virtual HRESULT STDMETHODCALLTYPE
25 SetPreference(const NOTIFYITEM* notify_item) = 0;
26 virtual HRESULT STDMETHODCALLTYPE EnableAutoTray(BOOL enabled) = 0;
27 };
28
29 // ITrayNotifyWin8 is the interface that replaces ITrayNotify for newer versions
30 // of Windows.
31 class __declspec(uuid("D133CE13-3537-48BA-93A7-AFCD5D2053B4")) ITrayNotifyWin8
32 : public IUnknown {
33 public:
34 virtual HRESULT STDMETHODCALLTYPE
35 RegisterCallback(INotificationCB* callback, unsigned long*) = 0;
36 virtual HRESULT STDMETHODCALLTYPE UnregisterCallback(unsigned long*) = 0;
37 virtual HRESULT STDMETHODCALLTYPE SetPreference(NOTIFYITEM const*) = 0;
38 virtual HRESULT STDMETHODCALLTYPE EnableAutoTray(BOOL) = 0;
39 virtual HRESULT STDMETHODCALLTYPE DoAction(BOOL) = 0;
40 };
41
42 const CLSID CLSID_TrayNotify = {
43 0x25DEAD04,
44 0x1EAC,
45 0x4911,
46 {0x9E, 0x3A, 0xAD, 0x0A, 0x4A, 0xB5, 0x60, 0xFD}};
47
48 } // namespace
49
50 StatusTrayStateChangerWin::StatusTrayStateChangerWin(UINT icon_id, HWND window)
51 : interface_version_(INTERFACE_VERSION_UNKNOWN),
52 icon_id_(icon_id),
53 window_(window) {
54 wchar_t module_name[MAX_PATH];
55 ::GetModuleFileName(NULL, module_name, MAX_PATH);
56
57 file_name_ = module_name;
58 }
59
60 void StatusTrayStateChangerWin::EnsureTrayIconVisible() {
61 DCHECK(CalledOnValidThread());
62
63 if (!CreateTrayNotify()) {
64 VLOG(1) << "Unable to create COM object for ITrayNotify.";
65 return;
66 }
67
68 scoped_ptr<NOTIFYITEM> notify_item = RegisterCallback();
69
70 // If the user has already hidden us explicitly, try to honor their choice by
71 // not changing anything.
72 if (notify_item->dwPreference == PREFERENCE_SHOW_NEVER)
73 return;
74
75 // If we are already on the taskbar, return since nothing needs to be done.
76 if (notify_item->dwPreference == PREFERENCE_SHOW_ALWAYS)
77 return;
78
79 notify_item->dwPreference = PREFERENCE_SHOW_ALWAYS;
80
81 SendNotifyItemUpdate(notify_item.Pass());
82 }
83
84 STDMETHODIMP_(ULONG) StatusTrayStateChangerWin::AddRef() {
85 DCHECK(CalledOnValidThread());
86 return base::win::IUnknownImpl::AddRef();
87 }
88
89 STDMETHODIMP_(ULONG) StatusTrayStateChangerWin::Release() {
90 DCHECK(CalledOnValidThread());
91 return base::win::IUnknownImpl::Release();
92 }
93
94 STDMETHODIMP StatusTrayStateChangerWin::QueryInterface(REFIID riid,
95 PVOID* ptr_void) {
96 DCHECK(CalledOnValidThread());
97 if (riid == __uuidof(INotificationCB)) {
98 *ptr_void = static_cast<INotificationCB*>(this);
99 AddRef();
100 return S_OK;
101 }
102
103 return base::win::IUnknownImpl::QueryInterface(riid, ptr_void);
104 }
105
106 STDMETHODIMP StatusTrayStateChangerWin::Notify(ULONG event,
107 NOTIFYITEM* notify_item) {
108 DCHECK(CalledOnValidThread());
109 DCHECK(notify_item);
110 if (notify_item->hWnd != window_ || notify_item->uID != icon_id_ ||
111 base::string16(notify_item->pszExeName) != file_name_) {
112 return S_OK;
113 }
114
115 notify_item_.reset(new NOTIFYITEM(*notify_item));
116 return S_OK;
117 }
118
119 StatusTrayStateChangerWin::~StatusTrayStateChangerWin() {
120 DCHECK(CalledOnValidThread());
121 }
122
123 bool StatusTrayStateChangerWin::CreateTrayNotify() {
124 DCHECK(CalledOnValidThread());
125 HRESULT hr = tray_notify_.CreateInstance(CLSID_TrayNotify);
126 if (FAILED(hr))
127 return false;
128
129 base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify_win8;
130 hr = tray_notify_win8.QueryFrom(tray_notify_);
131 if (SUCCEEDED(hr)) {
132 interface_version_ = INTERFACE_VERSION_WIN8;
133 return true;
134 }
135
136 base::win::ScopedComPtr<ITrayNotify> tray_notify_legacy;
137 hr = tray_notify_legacy.QueryFrom(tray_notify_);
138 if (SUCCEEDED(hr)) {
139 interface_version_ = INTERFACE_VERSION_LEGACY;
140 return true;
141 }
142
143 return false;
144 }
145
146 scoped_ptr<NOTIFYITEM> StatusTrayStateChangerWin::RegisterCallback() {
147 // |notify_item_| is used to store the result of the callback from
148 // Explorer.exe, which happens synchronously during
149 // RegisterCallbackWin8 or RegisterCallbackLegacy.
150 DCHECK(notify_item_.get() == NULL);
151
152 // TODO(dewittj): Add UMA logging here to report if either of our strategies
153 // has a tendency to fail on particular versions of Windows.
154 switch (interface_version_) {
155 case INTERFACE_VERSION_WIN8:
156 if (!RegisterCallbackWin8())
157 VLOG(1) << "Unable to successfully run RegisterCallbackWin8.";
158 break;
159 case INTERFACE_VERSION_LEGACY:
160 if (!RegisterCallbackLegacy())
161 VLOG(1) << "Unable to successfully run RegisterCallbackLegacy.";
162 break;
163 default:
164 NOTREACHED();
165 }
166
167 return notify_item_.Pass();
168 }
169
170 bool StatusTrayStateChangerWin::RegisterCallbackWin8() {
171 base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify_win8;
172 HRESULT hr = tray_notify_win8.QueryFrom(tray_notify_);
173 if (FAILED(hr))
174 return false;
175
176 // The following two lines cause Windows Explorer to call us back with all the
177 // existing tray icons and their preference. It would also presumably notify
178 // us if changes were made in realtime while we registered as a callback, but
179 // we just want to modify our own entry so we immediately unregister.
180 unsigned long callback_id = 0;
181 tray_notify_win8->RegisterCallback(this, &callback_id);
182 tray_notify_win8->UnregisterCallback(&callback_id);
183
184 return true;
185 }
186
187 bool StatusTrayStateChangerWin::RegisterCallbackLegacy() {
188 base::win::ScopedComPtr<ITrayNotify> tray_notify;
189 HRESULT hr = tray_notify.QueryFrom(tray_notify_);
190 if (FAILED(hr))
191 return false;
192
193 // The following two lines cause Windows Explorer to call us back with all the
194 // existing tray icons and their preference. It would also presumably notify
195 // us if changes were made in realtime while we registered as a callback. In
196 // this version of the API, there can be only one registered callback so it is
197 // better to unregister as soon as possible.
198 // TODO(dewittj): Try to notice if the notification area icon customization
199 // window is open and postpone this call until the user closes it;
200 // registering the callback while the window is open can cause stale data to
201 // be displayed to the user.
202 tray_notify->RegisterCallback(this);
203 tray_notify->RegisterCallback(NULL);
204
205 return true;
206 }
207
208 void StatusTrayStateChangerWin::SendNotifyItemUpdate(
209 scoped_ptr<NOTIFYITEM> notify_item) {
210 if (interface_version_ == INTERFACE_VERSION_LEGACY) {
211 base::win::ScopedComPtr<ITrayNotify> tray_notify;
212 HRESULT hr = tray_notify.QueryFrom(tray_notify_);
213 if (SUCCEEDED(hr))
214 tray_notify->SetPreference(notify_item.get());
215 } else if (interface_version_ == INTERFACE_VERSION_WIN8) {
216 base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify;
217 HRESULT hr = tray_notify.QueryFrom(tray_notify_);
218 if (SUCCEEDED(hr))
219 tray_notify->SetPreference(notify_item.get());
220 }
221 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698