// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_ #define CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/strings/string16.h" #include "base/threading/non_thread_safe.h" #include "base/win/iunknown_impl.h" #include "base/win/scoped_comptr.h" // The known values for NOTIFYITEM's dwPreference member. enum NOTIFYITEM_PREFERENCE { // In Windows UI: "Only show notifications." PREFERENCE_SHOW_WHEN_ACTIVE = 0, // In Windows UI: "Hide icon and notifications." PREFERENCE_SHOW_NEVER = 1, // In Windows UI: "Show icon and notifications." PREFERENCE_SHOW_ALWAYS = 2 }; // NOTIFYITEM describes an entry in Explorer's registry of status icons. // Explorer keeps entries around for a process even after it exits. struct NOTIFYITEM { PWSTR exe_name; // The file name of the creating executable. PWSTR tip; // The last hover-text value associated with this status // item. HICON icon; // The icon associated with this status item. HWND hwnd; // The HWND associated with the status item. DWORD preference; // Determines the behavior of the icon with respect to // the taskbar. Values taken from NOTIFYITEM_PREFERENCE. UINT id; // The ID specified by the application. (hWnd, uID) is // unique. GUID guid; // The GUID specified by the application, alternative to // uID. }; // INotificationCB is an interface that applications can implement in order to // receive notifications about the state of the notification area manager. class __declspec(uuid("D782CCBA-AFB0-43F1-94DB-FDA3779EACCB")) INotificationCB : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Notify(ULONG event, NOTIFYITEM* notify_item) = 0; }; // A class that is capable of reading and writing the state of the notification // area in the Windows taskbar. It is used to promote a tray icon from the // overflow area to the taskbar, and refuses to do anything if the user has // explicitly marked an icon to be always hidden. class StatusTrayStateChangerWin : public INotificationCB, public base::win::IUnknownImpl, public base::NonThreadSafe { public: StatusTrayStateChangerWin(UINT icon_id, HWND window); // Call this method to move the icon matching |icon_id| and |window| to the // taskbar from the overflow area. This will not make any changes if the // icon has been set to |PREFERENCE_SHOW_NEVER|, in order to comply with // the explicit wishes/configuration of the user. void EnsureTrayIconVisible(); // IUnknown. ULONG STDMETHODCALLTYPE AddRef() override; ULONG STDMETHODCALLTYPE Release() override; HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, PVOID*) override; // INotificationCB. // Notify is called in response to RegisterCallback for each current // entry in Explorer's list of notification area icons, and ever time // one of them changes, until UnregisterCallback is called or |this| // is destroyed. HRESULT STDMETHODCALLTYPE Notify(ULONG, NOTIFYITEM*) override; protected: ~StatusTrayStateChangerWin() override; private: friend class StatusTrayStateChangerWinTest; enum InterfaceVersion { INTERFACE_VERSION_LEGACY = 0, INTERFACE_VERSION_WIN8, INTERFACE_VERSION_UNKNOWN }; // Creates an instance of TrayNotify, and ensures that it supports either // ITrayNotify or ITrayNotifyWin8. Returns true on success. bool CreateTrayNotify(); // Returns the NOTIFYITEM that corresponds to this executable and the // HWND/ID pair that were used to create the StatusTrayStateChangerWin. // Internally it calls the appropriate RegisterCallback{Win8,Legacy}. scoped_ptr RegisterCallback(); // Calls RegisterCallback with the appropriate interface required by // different versions of Windows. This will result in |notify_item_| being // updated when a matching item is passed into // StatusTrayStateChangerWin::Notify. bool RegisterCallbackWin8(); bool RegisterCallbackLegacy(); // Sends an update to Explorer with the passed NOTIFYITEM. void SendNotifyItemUpdate(scoped_ptr notify_item); // Storing IUnknown since we will need to use different interfaces // for different versions of Windows. base::win::ScopedComPtr tray_notify_; InterfaceVersion interface_version_; // The ID assigned to the notification area icon that we want to manipulate. const UINT icon_id_; // The HWND associated with the notification area icon that we want to // manipulate. This is an unretained pointer, do not dereference. const HWND window_; // Executable name of the current program. Along with |icon_id_| and // |window_|, this uniquely identifies a notification area entry to Explorer. base::string16 file_name_; // Temporary storage for the matched NOTIFYITEM. This is necessary because // Notify doesn't return anything. The call flow looks like this: // TrayNotify->RegisterCallback() // ... other COM stack frames .. // StatusTrayStateChangerWin->Notify(NOTIFYITEM); // so we can't just return the notifyitem we're looking for. scoped_ptr notify_item_; DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerWin); }; #endif // CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_