15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/status_icons/status_tray_win.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <commctrl.h>
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/bind.h"
105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/threading/non_thread_safe.h"
115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/threading/thread.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/wrapped_window_proc.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/status_icons/status_icon_win.h"
145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/chrome_constants.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/screen.h"
17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/gfx/win/hwnd_util.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const UINT kStatusIconMessage = WM_APP + 1;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochnamespace {
22ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch// |kBaseIconId| is 2 to avoid conflicts with plugins that hard-code id 1.
23ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdochconst UINT kBaseIconId = 2;
24ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
25ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochUINT ReservedIconId(StatusTray::StatusIconType type) {
26ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return kBaseIconId + static_cast<UINT>(type);
27ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
28ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}  // namespace
29ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Default implementation for StatusTrayStateChanger that communicates to
315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// Exporer.exe via COM.  It spawns a background thread with a fresh COM
325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// apartment and requests that the visibility be increased unless the user
335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu// has explicitly set the icon to be hidden.
345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass StatusTrayStateChangerProxyImpl : public StatusTrayStateChangerProxy,
355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                        public base::NonThreadSafe {
365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  StatusTrayStateChangerProxyImpl()
385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      : pending_requests_(0),
395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        worker_thread_("StatusIconCOMWorkerThread"),
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        weak_factory_(this) {
415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    worker_thread_.init_com_with_mta(false);
425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void EnqueueChange(UINT icon_id, HWND window) OVERRIDE {
455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(CalledOnValidThread());
465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (pending_requests_ == 0)
475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      worker_thread_.Start();
485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ++pending_requests_;
505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    worker_thread_.message_loop_proxy()->PostTaskAndReply(
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        FROM_HERE,
525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        base::Bind(
535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            &StatusTrayStateChangerProxyImpl::EnqueueChangeOnWorkerThread,
545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            icon_id,
555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu            window),
565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        base::Bind(&StatusTrayStateChangerProxyImpl::ChangeDone,
575c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                   weak_factory_.GetWeakPtr()));
585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Must be called only on |worker_thread_|, to ensure the correct COM
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // apartment.
635c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  static void EnqueueChangeOnWorkerThread(UINT icon_id, HWND window) {
645c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // It appears that IUnknowns are coincidentally compatible with
655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // scoped_refptr.  Normally I wouldn't depend on that but it seems that
665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // base::win::IUnknownImpl itself depends on that coincidence so it's
675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    // already being assumed elsewhere.
685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    scoped_refptr<StatusTrayStateChangerWin> status_tray_state_changer(
695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        new StatusTrayStateChangerWin(icon_id, window));
705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    status_tray_state_changer->EnsureTrayIconVisible();
715c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
725c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
735c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Called on UI thread.
745c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  void ChangeDone() {
755c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK(CalledOnValidThread());
765c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DCHECK_GT(pending_requests_, 0);
775c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
785c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if (--pending_requests_ == 0)
795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      worker_thread_.Stop();
805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  int pending_requests_;
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::Thread worker_thread_;
855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::WeakPtrFactory<StatusTrayStateChangerProxyImpl> weak_factory_;
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
875c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerProxyImpl);
885c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatusTrayWin::StatusTrayWin()
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : next_icon_id_(1),
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      atom_(0),
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      instance_(NULL),
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      window_(NULL) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register our window class
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WNDCLASSEX window_class;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::InitializeWindowClass(
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::kStatusTrayWindowClass,
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &base::win::WrappedWindowProc<StatusTrayWin::WndProcStatic>,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      0, 0, 0, NULL, NULL, NULL, NULL, NULL,
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &window_class);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  instance_ = window_class.hInstance;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  atom_ = RegisterClassEx(&window_class);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(atom_);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the taskbar is re-created after we start up, we have to rebuild all of
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // our icons.
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  taskbar_created_message_ = RegisterWindowMessage(TEXT("TaskbarCreated"));
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an offscreen window for handling messages for the status icons. We
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // create a hidden WS_POPUP window instead of an HWND_MESSAGE window, because
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // only top-level windows such as popups can receive broadcast messages like
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // "TaskbarCreated".
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  window_ = CreateWindow(MAKEINTATOM(atom_),
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                         0, WS_POPUP, 0, 0, 0, 0, 0, 0, instance_, 0);
116d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  gfx::CheckWindowCreated(window_);
117d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  gfx::SetWindowUserData(window_, this);
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuStatusTrayWin::~StatusTrayWin() {
1215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (window_)
1225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    DestroyWindow(window_);
1235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (atom_)
1255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    UnregisterClass(MAKEINTATOM(atom_), instance_);
1265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid StatusTrayWin::UpdateIconVisibilityInBackground(
1295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    StatusIconWin* status_icon) {
1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (!state_changer_proxy_.get())
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    state_changer_proxy_.reset(new StatusTrayStateChangerProxyImpl);
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  state_changer_proxy_->EnqueueChange(status_icon->icon_id(),
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                      status_icon->window());
1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LRESULT CALLBACK StatusTrayWin::WndProcStatic(HWND hwnd,
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              UINT message,
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              WPARAM wparam,
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              LPARAM lparam) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StatusTrayWin* msg_wnd = reinterpret_cast<StatusTrayWin*>(
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      GetWindowLongPtr(hwnd, GWLP_USERDATA));
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (msg_wnd)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return msg_wnd->WndProc(hwnd, message, wparam, lparam);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ::DefWindowProc(hwnd, message, wparam, lparam);
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LRESULT CALLBACK StatusTrayWin::WndProc(HWND hwnd,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        UINT message,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        WPARAM wparam,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        LPARAM lparam) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (message == taskbar_created_message_) {
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We need to reset all of our icons because the taskbar went away.
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (StatusIcons::const_iterator i(status_icons().begin());
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         i != status_icons().end(); ++i) {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      StatusIconWin* win_icon = static_cast<StatusIconWin*>(*i);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      win_icon->ResetIcon();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return TRUE;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (message == kStatusIconMessage) {
162eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    StatusIconWin* win_icon = NULL;
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Find the selected status icon.
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    for (StatusIcons::const_iterator i(status_icons().begin());
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch         i != status_icons().end();
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch         ++i) {
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      StatusIconWin* current_win_icon = static_cast<StatusIconWin*>(*i);
169eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      if (current_win_icon->icon_id() == wparam) {
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        win_icon = current_win_icon;
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        break;
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // It is possible for this procedure to be called with an obsolete icon
1763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // id.  In that case we should just return early before handling any
1773551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // actions.
1783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (!win_icon)
1793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      return TRUE;
1803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (lparam) {
182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      case TB_INDETERMINATE:
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        win_icon->HandleBalloonClickEvent();
184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        return TRUE;
185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case WM_LBUTTONDOWN:
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case WM_RBUTTONDOWN:
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case WM_CONTEXTMENU:
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Walk our icons, find which one was clicked on, and invoke its
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // HandleClickEvent() method.
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        gfx::Point cursor_pos(
192eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
193eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN);
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return TRUE;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ::DefWindowProc(hwnd, message, wparam, lparam);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
200ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochStatusIcon* StatusTrayWin::CreatePlatformStatusIcon(
201a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    StatusTray::StatusIconType type,
202a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const gfx::ImageSkia& image,
203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::string16& tool_tip) {
204ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  UINT next_icon_id;
205ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  if (type == StatusTray::OTHER_ICON)
206ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    next_icon_id = NextIconId();
207ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  else
208ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch    next_icon_id = ReservedIconId(type);
209ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
2100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  StatusIcon* icon =
2115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      new StatusIconWin(this, next_icon_id, window_, kStatusIconMessage);
212a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
213a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  icon->SetImage(image);
214a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  icon->SetToolTip(tool_tip);
215a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return icon;
216ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch}
217ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch
218ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben MurdochUINT StatusTrayWin::NextIconId() {
219ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  UINT icon_id = next_icon_id_++;
220ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch  return kBaseIconId + static_cast<UINT>(NAMED_STATUS_ICON_COUNT) + icon_id;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuvoid StatusTrayWin::SetStatusTrayStateChangerProxyForTest(
2245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    scoped_ptr<StatusTrayStateChangerProxy> proxy) {
2255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  state_changer_proxy_ = proxy.Pass();
2265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)StatusTray* StatusTray::Create() {
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return new StatusTrayWin();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
231