'chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.h',
'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.cc',
'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h',
- 'chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc',
- 'chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h',
'chromium_src/chrome/common/print_messages.cc',
'chromium_src/chrome/common/print_messages.h',
'chromium_src/chrome/common/tts_messages.h',
BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data);
if (!result)
LOG(WARNING) << "Error setting status tray icon image";
- else
- host_->UpdateIconVisibilityInBackground(this);
}
void NotifyIcon::SetPressedImage(const gfx::ImageSkia& image) {
#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_tray_state_changer_win.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/win/hwnd_util.h"
} // namespace
-// Default implementation for NotifyIconHostStateChangerProxy 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 NotifyIconHostStateChangerProxyImpl
- : public NotifyIconHostStateChangerProxy,
- public base::NonThreadSafe {
- public:
- NotifyIconHostStateChangerProxyImpl()
- : pending_requests_(0),
- worker_thread_("NotifyIconCOMWorkerThread"),
- 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(
- &NotifyIconHostStateChangerProxyImpl::EnqueueChangeOnWorkerThread,
- icon_id,
- window),
- base::Bind(&NotifyIconHostStateChangerProxyImpl::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<NotifyIconHostStateChangerProxyImpl> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(NotifyIconHostStateChangerProxyImpl);
-};
-
-
NotifyIconHost::NotifyIconHost()
: next_icon_id_(1),
atom_(0),
notify_icons_.erase(i);
}
-void NotifyIconHost::UpdateIconVisibilityInBackground(
- NotifyIcon* notify_icon) {
- if (!state_changer_proxy_.get())
- state_changer_proxy_.reset(new NotifyIconHostStateChangerProxyImpl);
-
- state_changer_proxy_->EnqueueChange(notify_icon->icon_id(),
- notify_icon->window());
-}
-
LRESULT CALLBACK NotifyIconHost::WndProcStatic(HWND hwnd,
UINT message,
WPARAM wparam,
class NotifyIcon;
-// A class that's responsible for increasing, if possible, the visibility
-// of a status tray icon on the taskbar. The default implementation sends
-// a task to a worker thread each time EnqueueChange is called.
-class NotifyIconHostStateChangerProxy {
- public:
- // Called by NotifyIconHost to request upgraded visibility on the icon
- // represented by the |icon_id|, |window| pair.
- virtual void EnqueueChange(UINT icon_id, HWND window) = 0;
-};
-
class NotifyIconHost {
public:
NotifyIconHost();
NotifyIcon* CreateNotifyIcon();
void Remove(NotifyIcon* notify_icon);
- void UpdateIconVisibilityInBackground(NotifyIcon* notify_icon);
-
private:
typedef std::vector<NotifyIcon*> NotifyIcons;
// reset our status icons.
UINT taskbar_created_message_;
- // Manages changes performed on a background thread to manipulate visibility
- // of notification icons.
- scoped_ptr<NotifyIconHostStateChangerProxy> state_changer_proxy_;
-
DISALLOW_COPY_AND_ASSIGN(NotifyIconHost);
};
+++ /dev/null
-// Copyright 2014 The Chromium Authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
-\r
-#include "chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h"\r
-\r
-namespace {\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Status Tray API\r
-\r
-// The folowing describes the interface to the undocumented Windows Exporer APIs\r
-// for manipulating with the status tray area. This code should be used with\r
-// care as it can change with versions (even minor versions) of Windows.\r
-\r
-// ITrayNotify is an interface describing the API for manipulating the state of\r
-// the Windows notification area, as well as for registering for change\r
-// notifications.\r
-class __declspec(uuid("FB852B2C-6BAD-4605-9551-F15F87830935")) ITrayNotify\r
- : public IUnknown {\r
- public:\r
- virtual HRESULT STDMETHODCALLTYPE\r
- RegisterCallback(INotificationCB* callback) = 0;\r
- virtual HRESULT STDMETHODCALLTYPE\r
- SetPreference(const NOTIFYITEM* notify_item) = 0;\r
- virtual HRESULT STDMETHODCALLTYPE EnableAutoTray(BOOL enabled) = 0;\r
-};\r
-\r
-// ITrayNotifyWin8 is the interface that replaces ITrayNotify for newer versions\r
-// of Windows.\r
-class __declspec(uuid("D133CE13-3537-48BA-93A7-AFCD5D2053B4")) ITrayNotifyWin8\r
- : public IUnknown {\r
- public:\r
- virtual HRESULT STDMETHODCALLTYPE\r
- RegisterCallback(INotificationCB* callback, unsigned long*) = 0;\r
- virtual HRESULT STDMETHODCALLTYPE UnregisterCallback(unsigned long*) = 0;\r
- virtual HRESULT STDMETHODCALLTYPE SetPreference(NOTIFYITEM const*) = 0;\r
- virtual HRESULT STDMETHODCALLTYPE EnableAutoTray(BOOL) = 0;\r
- virtual HRESULT STDMETHODCALLTYPE DoAction(BOOL) = 0;\r
-};\r
-\r
-const CLSID CLSID_TrayNotify = {\r
- 0x25DEAD04,\r
- 0x1EAC,\r
- 0x4911,\r
- {0x9E, 0x3A, 0xAD, 0x0A, 0x4A, 0xB5, 0x60, 0xFD}};\r
-\r
-} // namespace\r
-\r
-StatusTrayStateChangerWin::StatusTrayStateChangerWin(UINT icon_id, HWND window)\r
- : interface_version_(INTERFACE_VERSION_UNKNOWN),\r
- icon_id_(icon_id),\r
- window_(window) {\r
- wchar_t module_name[MAX_PATH];\r
- ::GetModuleFileName(NULL, module_name, MAX_PATH);\r
-\r
- file_name_ = module_name;\r
-}\r
-\r
-void StatusTrayStateChangerWin::EnsureTrayIconVisible() {\r
- DCHECK(CalledOnValidThread());\r
-\r
- if (!CreateTrayNotify()) {\r
- VLOG(1) << "Unable to create COM object for ITrayNotify.";\r
- return;\r
- }\r
-\r
- scoped_ptr<NOTIFYITEM> notify_item = RegisterCallback();\r
-\r
- // If the user has already hidden us explicitly, try to honor their choice by\r
- // not changing anything.\r
- if (notify_item->preference == PREFERENCE_SHOW_NEVER)\r
- return;\r
-\r
- // If we are already on the taskbar, return since nothing needs to be done.\r
- if (notify_item->preference == PREFERENCE_SHOW_ALWAYS)\r
- return;\r
-\r
- notify_item->preference = PREFERENCE_SHOW_ALWAYS;\r
-\r
- SendNotifyItemUpdate(notify_item.Pass());\r
-}\r
-\r
-STDMETHODIMP_(ULONG) StatusTrayStateChangerWin::AddRef() {\r
- DCHECK(CalledOnValidThread());\r
- return base::win::IUnknownImpl::AddRef();\r
-}\r
-\r
-STDMETHODIMP_(ULONG) StatusTrayStateChangerWin::Release() {\r
- DCHECK(CalledOnValidThread());\r
- return base::win::IUnknownImpl::Release();\r
-}\r
-\r
-STDMETHODIMP StatusTrayStateChangerWin::QueryInterface(REFIID riid,\r
- PVOID* ptr_void) {\r
- DCHECK(CalledOnValidThread());\r
- if (riid == __uuidof(INotificationCB)) {\r
- *ptr_void = static_cast<INotificationCB*>(this);\r
- AddRef();\r
- return S_OK;\r
- }\r
-\r
- return base::win::IUnknownImpl::QueryInterface(riid, ptr_void);\r
-}\r
-\r
-STDMETHODIMP StatusTrayStateChangerWin::Notify(ULONG event,\r
- NOTIFYITEM* notify_item) {\r
- DCHECK(CalledOnValidThread());\r
- DCHECK(notify_item);\r
- if (notify_item->hwnd != window_ || notify_item->id != icon_id_ ||\r
- base::string16(notify_item->exe_name) != file_name_) {\r
- return S_OK;\r
- }\r
-\r
- notify_item_.reset(new NOTIFYITEM(*notify_item));\r
- return S_OK;\r
-}\r
-\r
-StatusTrayStateChangerWin::~StatusTrayStateChangerWin() {\r
- DCHECK(CalledOnValidThread());\r
-}\r
-\r
-bool StatusTrayStateChangerWin::CreateTrayNotify() {\r
- DCHECK(CalledOnValidThread());\r
-\r
- tray_notify_.Release(); // Release so this method can be called more than\r
- // once.\r
-\r
- HRESULT hr = tray_notify_.CreateInstance(CLSID_TrayNotify);\r
- if (FAILED(hr))\r
- return false;\r
-\r
- base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify_win8;\r
- hr = tray_notify_win8.QueryFrom(tray_notify_);\r
- if (SUCCEEDED(hr)) {\r
- interface_version_ = INTERFACE_VERSION_WIN8;\r
- return true;\r
- }\r
-\r
- base::win::ScopedComPtr<ITrayNotify> tray_notify_legacy;\r
- hr = tray_notify_legacy.QueryFrom(tray_notify_);\r
- if (SUCCEEDED(hr)) {\r
- interface_version_ = INTERFACE_VERSION_LEGACY;\r
- return true;\r
- }\r
-\r
- return false;\r
-}\r
-\r
-scoped_ptr<NOTIFYITEM> StatusTrayStateChangerWin::RegisterCallback() {\r
- // |notify_item_| is used to store the result of the callback from\r
- // Explorer.exe, which happens synchronously during\r
- // RegisterCallbackWin8 or RegisterCallbackLegacy.\r
- DCHECK(notify_item_.get() == NULL);\r
-\r
- // TODO(dewittj): Add UMA logging here to report if either of our strategies\r
- // has a tendency to fail on particular versions of Windows.\r
- switch (interface_version_) {\r
- case INTERFACE_VERSION_WIN8:\r
- if (!RegisterCallbackWin8())\r
- VLOG(1) << "Unable to successfully run RegisterCallbackWin8.";\r
- break;\r
- case INTERFACE_VERSION_LEGACY:\r
- if (!RegisterCallbackLegacy())\r
- VLOG(1) << "Unable to successfully run RegisterCallbackLegacy.";\r
- break;\r
- default:\r
- NOTREACHED();\r
- }\r
-\r
- // Adding an intermediate scoped pointer here so that |notify_item_| is reset\r
- // to NULL.\r
- scoped_ptr<NOTIFYITEM> rv(notify_item_.release());\r
- return rv.Pass();\r
-}\r
-\r
-bool StatusTrayStateChangerWin::RegisterCallbackWin8() {\r
- base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify_win8;\r
- HRESULT hr = tray_notify_win8.QueryFrom(tray_notify_);\r
- if (FAILED(hr))\r
- return false;\r
-\r
- // The following two lines cause Windows Explorer to call us back with all the\r
- // existing tray icons and their preference. It would also presumably notify\r
- // us if changes were made in realtime while we registered as a callback, but\r
- // we just want to modify our own entry so we immediately unregister.\r
- unsigned long callback_id = 0;\r
- hr = tray_notify_win8->RegisterCallback(this, &callback_id);\r
- tray_notify_win8->UnregisterCallback(&callback_id);\r
- if (FAILED(hr)) {\r
- return false;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-bool StatusTrayStateChangerWin::RegisterCallbackLegacy() {\r
- base::win::ScopedComPtr<ITrayNotify> tray_notify;\r
- HRESULT hr = tray_notify.QueryFrom(tray_notify_);\r
- if (FAILED(hr)) {\r
- return false;\r
- }\r
-\r
- // The following two lines cause Windows Explorer to call us back with all the\r
- // existing tray icons and their preference. It would also presumably notify\r
- // us if changes were made in realtime while we registered as a callback. In\r
- // this version of the API, there can be only one registered callback so it is\r
- // better to unregister as soon as possible.\r
- // TODO(dewittj): Try to notice if the notification area icon customization\r
- // window is open and postpone this call until the user closes it;\r
- // registering the callback while the window is open can cause stale data to\r
- // be displayed to the user.\r
- hr = tray_notify->RegisterCallback(this);\r
- tray_notify->RegisterCallback(NULL);\r
- if (FAILED(hr)) {\r
- return false;\r
- }\r
-\r
- return true;\r
-}\r
-\r
-void StatusTrayStateChangerWin::SendNotifyItemUpdate(\r
- scoped_ptr<NOTIFYITEM> notify_item) {\r
- if (interface_version_ == INTERFACE_VERSION_LEGACY) {\r
- base::win::ScopedComPtr<ITrayNotify> tray_notify;\r
- HRESULT hr = tray_notify.QueryFrom(tray_notify_);\r
- if (SUCCEEDED(hr))\r
- tray_notify->SetPreference(notify_item.get());\r
- } else if (interface_version_ == INTERFACE_VERSION_WIN8) {\r
- base::win::ScopedComPtr<ITrayNotifyWin8> tray_notify;\r
- HRESULT hr = tray_notify.QueryFrom(tray_notify_);\r
- if (SUCCEEDED(hr))\r
- tray_notify->SetPreference(notify_item.get());\r
- }\r
-}\r
-\r
+++ /dev/null
-// Copyright 2014 The Chromium Authors. All rights reserved.\r
-// Use of this source code is governed by a BSD-style license that can be\r
-// found in the LICENSE file.\r
-\r
-#ifndef CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_\r
-#define CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_\r
-\r
-#include "base/memory/scoped_ptr.h"\r
-#include "base/strings/string16.h"\r
-#include "base/threading/non_thread_safe.h"\r
-#include "base/win/iunknown_impl.h"\r
-#include "base/win/scoped_comptr.h"\r
-\r
-// The known values for NOTIFYITEM's dwPreference member.\r
-enum NOTIFYITEM_PREFERENCE {\r
- // In Windows UI: "Only show notifications."\r
- PREFERENCE_SHOW_WHEN_ACTIVE = 0,\r
- // In Windows UI: "Hide icon and notifications."\r
- PREFERENCE_SHOW_NEVER = 1,\r
- // In Windows UI: "Show icon and notifications."\r
- PREFERENCE_SHOW_ALWAYS = 2\r
-};\r
-\r
-// NOTIFYITEM describes an entry in Explorer's registry of status icons.\r
-// Explorer keeps entries around for a process even after it exits.\r
-struct NOTIFYITEM {\r
- PWSTR exe_name; // The file name of the creating executable.\r
- PWSTR tip; // The last hover-text value associated with this status\r
- // item.\r
- HICON icon; // The icon associated with this status item.\r
- HWND hwnd; // The HWND associated with the status item.\r
- DWORD preference; // Determines the behavior of the icon with respect to\r
- // the taskbar. Values taken from NOTIFYITEM_PREFERENCE.\r
- UINT id; // The ID specified by the application. (hWnd, uID) is\r
- // unique.\r
- GUID guid; // The GUID specified by the application, alternative to\r
- // uID.\r
-};\r
-\r
-// INotificationCB is an interface that applications can implement in order to\r
-// receive notifications about the state of the notification area manager.\r
-class __declspec(uuid("D782CCBA-AFB0-43F1-94DB-FDA3779EACCB")) INotificationCB\r
- : public IUnknown {\r
- public:\r
- virtual HRESULT STDMETHODCALLTYPE\r
- Notify(ULONG event, NOTIFYITEM* notify_item) = 0;\r
-};\r
-\r
-// A class that is capable of reading and writing the state of the notification\r
-// area in the Windows taskbar. It is used to promote a tray icon from the\r
-// overflow area to the taskbar, and refuses to do anything if the user has\r
-// explicitly marked an icon to be always hidden.\r
-class StatusTrayStateChangerWin : public INotificationCB,\r
- public base::win::IUnknownImpl,\r
- public base::NonThreadSafe {\r
- public:\r
- StatusTrayStateChangerWin(UINT icon_id, HWND window);\r
-\r
- // Call this method to move the icon matching |icon_id| and |window| to the\r
- // taskbar from the overflow area. This will not make any changes if the\r
- // icon has been set to |PREFERENCE_SHOW_NEVER|, in order to comply with\r
- // the explicit wishes/configuration of the user.\r
- void EnsureTrayIconVisible();\r
-\r
- // IUnknown.\r
- virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE;\r
- virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE;\r
- virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, PVOID*) OVERRIDE;\r
-\r
- // INotificationCB.\r
- // Notify is called in response to RegisterCallback for each current\r
- // entry in Explorer's list of notification area icons, and ever time\r
- // one of them changes, until UnregisterCallback is called or |this|\r
- // is destroyed.\r
- virtual HRESULT STDMETHODCALLTYPE Notify(ULONG, NOTIFYITEM*);\r
-\r
- protected:\r
- virtual ~StatusTrayStateChangerWin();\r
-\r
- private:\r
- friend class StatusTrayStateChangerWinTest;\r
-\r
- enum InterfaceVersion {\r
- INTERFACE_VERSION_LEGACY = 0,\r
- INTERFACE_VERSION_WIN8,\r
- INTERFACE_VERSION_UNKNOWN\r
- };\r
-\r
- // Creates an instance of TrayNotify, and ensures that it supports either\r
- // ITrayNotify or ITrayNotifyWin8. Returns true on success.\r
- bool CreateTrayNotify();\r
-\r
- // Returns the NOTIFYITEM that corresponds to this executable and the\r
- // HWND/ID pair that were used to create the StatusTrayStateChangerWin.\r
- // Internally it calls the appropriate RegisterCallback{Win8,Legacy}.\r
- scoped_ptr<NOTIFYITEM> RegisterCallback();\r
-\r
- // Calls RegisterCallback with the appropriate interface required by\r
- // different versions of Windows. This will result in |notify_item_| being\r
- // updated when a matching item is passed into\r
- // StatusTrayStateChangerWin::Notify.\r
- bool RegisterCallbackWin8();\r
- bool RegisterCallbackLegacy();\r
-\r
- // Sends an update to Explorer with the passed NOTIFYITEM.\r
- void SendNotifyItemUpdate(scoped_ptr<NOTIFYITEM> notify_item);\r
-\r
- // Storing IUnknown since we will need to use different interfaces\r
- // for different versions of Windows.\r
- base::win::ScopedComPtr<IUnknown> tray_notify_;\r
- InterfaceVersion interface_version_;\r
-\r
- // The ID assigned to the notification area icon that we want to manipulate.\r
- const UINT icon_id_;\r
- // The HWND associated with the notification area icon that we want to\r
- // manipulate. This is an unretained pointer, do not dereference.\r
- const HWND window_;\r
- // Executable name of the current program. Along with |icon_id_| and\r
- // |window_|, this uniquely identifies a notification area entry to Explorer.\r
- base::string16 file_name_;\r
-\r
- // Temporary storage for the matched NOTIFYITEM. This is necessary because\r
- // Notify doesn't return anything. The call flow looks like this:\r
- // TrayNotify->RegisterCallback()\r
- // ... other COM stack frames ..\r
- // StatusTrayStateChangerWin->Notify(NOTIFYITEM);\r
- // so we can't just return the notifyitem we're looking for.\r
- scoped_ptr<NOTIFYITEM> notify_item_;\r
-\r
- DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerWin);\r
-};\r
-\r
-#endif // CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_
\ No newline at end of file