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#ifndef CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_
6#define CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_
7
8#include "base/memory/scoped_ptr.h"
9#include "base/strings/string16.h"
10#include "base/threading/non_thread_safe.h"
11#include "base/win/iunknown_impl.h"
12#include "base/win/scoped_comptr.h"
13
14// The known values for NOTIFYITEM's dwPreference member.
15enum NOTIFYITEM_PREFERENCE {
16  // In Windows UI: "Only show notifications."
17  PREFERENCE_SHOW_WHEN_ACTIVE = 0,
18  // In Windows UI: "Hide icon and notifications."
19  PREFERENCE_SHOW_NEVER = 1,
20  // In Windows UI: "Show icon and notifications."
21  PREFERENCE_SHOW_ALWAYS = 2
22};
23
24// NOTIFYITEM describes an entry in Explorer's registry of status icons.
25// Explorer keeps entries around for a process even after it exits.
26struct NOTIFYITEM {
27  PWSTR exe_name;    // The file name of the creating executable.
28  PWSTR tip;         // The last hover-text value associated with this status
29                     // item.
30  HICON icon;        // The icon associated with this status item.
31  HWND hwnd;         // The HWND associated with the status item.
32  DWORD preference;  // Determines the behavior of the icon with respect to
33                     // the taskbar. Values taken from NOTIFYITEM_PREFERENCE.
34  UINT id;           // The ID specified by the application.  (hWnd, uID) is
35                     // unique.
36  GUID guid;         // The GUID specified by the application, alternative to
37                     // uID.
38};
39
40// INotificationCB is an interface that applications can implement in order to
41// receive notifications about the state of the notification area manager.
42class __declspec(uuid("D782CCBA-AFB0-43F1-94DB-FDA3779EACCB")) INotificationCB
43    : public IUnknown {
44 public:
45  virtual HRESULT STDMETHODCALLTYPE
46      Notify(ULONG event, NOTIFYITEM* notify_item) = 0;
47};
48
49// A class that is capable of reading and writing the state of the notification
50// area in the Windows taskbar.  It is used to promote a tray icon from the
51// overflow area to the taskbar, and refuses to do anything if the user has
52// explicitly marked an icon to be always hidden.
53class StatusTrayStateChangerWin : public INotificationCB,
54                                  public base::win::IUnknownImpl,
55                                  public base::NonThreadSafe {
56 public:
57  StatusTrayStateChangerWin(UINT icon_id, HWND window);
58
59  // Call this method to move the icon matching |icon_id| and |window| to the
60  // taskbar from the overflow area.  This will not make any changes if the
61  // icon has been set to |PREFERENCE_SHOW_NEVER|, in order to comply with
62  // the explicit wishes/configuration of the user.
63  void EnsureTrayIconVisible();
64
65  // IUnknown.
66  virtual ULONG STDMETHODCALLTYPE AddRef() OVERRIDE;
67  virtual ULONG STDMETHODCALLTYPE Release() OVERRIDE;
68  virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, PVOID*) OVERRIDE;
69
70  // INotificationCB.
71  // Notify is called in response to RegisterCallback for each current
72  // entry in Explorer's list of notification area icons, and ever time
73  // one of them changes, until UnregisterCallback is called or |this|
74  // is destroyed.
75  virtual HRESULT STDMETHODCALLTYPE Notify(ULONG, NOTIFYITEM*);
76
77 protected:
78  virtual ~StatusTrayStateChangerWin();
79
80 private:
81  friend class StatusTrayStateChangerWinTest;
82
83  enum InterfaceVersion {
84    INTERFACE_VERSION_LEGACY = 0,
85    INTERFACE_VERSION_WIN8,
86    INTERFACE_VERSION_UNKNOWN
87  };
88
89  // Creates an instance of TrayNotify, and ensures that it supports either
90  // ITrayNotify or ITrayNotifyWin8.  Returns true on success.
91  bool CreateTrayNotify();
92
93  // Returns the NOTIFYITEM that corresponds to this executable and the
94  // HWND/ID pair that were used to create the StatusTrayStateChangerWin.
95  // Internally it calls the appropriate RegisterCallback{Win8,Legacy}.
96  scoped_ptr<NOTIFYITEM> RegisterCallback();
97
98  // Calls RegisterCallback with the appropriate interface required by
99  // different versions of Windows.  This will result in |notify_item_| being
100  // updated when a matching item is passed into
101  // StatusTrayStateChangerWin::Notify.
102  bool RegisterCallbackWin8();
103  bool RegisterCallbackLegacy();
104
105  // Sends an update to Explorer with the passed NOTIFYITEM.
106  void SendNotifyItemUpdate(scoped_ptr<NOTIFYITEM> notify_item);
107
108  // Storing IUnknown since we will need to use different interfaces
109  // for different versions of Windows.
110  base::win::ScopedComPtr<IUnknown> tray_notify_;
111  InterfaceVersion interface_version_;
112
113  // The ID assigned to the notification area icon that we want to manipulate.
114  const UINT icon_id_;
115  // The HWND associated with the notification area icon that we want to
116  // manipulate.  This is an unretained pointer, do not dereference.
117  const HWND window_;
118  // Executable name of the current program.  Along with |icon_id_| and
119  // |window_|, this uniquely identifies a notification area entry to Explorer.
120  base::string16 file_name_;
121
122  // Temporary storage for the matched NOTIFYITEM.  This is necessary because
123  // Notify doesn't return anything.  The call flow looks like this:
124  //   TrayNotify->RegisterCallback()
125  //      ... other COM stack frames ..
126  //   StatusTrayStateChangerWin->Notify(NOTIFYITEM);
127  // so we can't just return the notifyitem we're looking for.
128  scoped_ptr<NOTIFYITEM> notify_item_;
129
130  DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerWin);
131};
132
133#endif  // CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_STATE_CHANGER_WIN_H_
134