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