status_tray_win.cc revision d0247b1b59f9c528cb6df88b4f2b9afaf80d181e
1// Copyright (c) 2012 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#include "chrome/browser/ui/views/status_icons/status_tray_win.h" 6 7#include <commctrl.h> 8 9#include "base/win/wrapped_window_proc.h" 10#include "chrome/browser/ui/views/status_icons/status_icon_win.h" 11#include "chrome/common/chrome_constants.h" 12#include "ui/gfx/screen.h" 13#include "ui/gfx/win/hwnd_util.h" 14#include "win8/util/win8_util.h" 15 16static const UINT kStatusIconMessage = WM_APP + 1; 17 18namespace { 19// |kBaseIconId| is 2 to avoid conflicts with plugins that hard-code id 1. 20const UINT kBaseIconId = 2; 21 22UINT ReservedIconId(StatusTray::StatusIconType type) { 23 return kBaseIconId + static_cast<UINT>(type); 24} 25} // namespace 26 27StatusTrayWin::StatusTrayWin() 28 : next_icon_id_(1), 29 atom_(0), 30 instance_(NULL), 31 window_(NULL) { 32 // Register our window class 33 WNDCLASSEX window_class; 34 base::win::InitializeWindowClass( 35 chrome::kStatusTrayWindowClass, 36 &base::win::WrappedWindowProc<StatusTrayWin::WndProcStatic>, 37 0, 0, 0, NULL, NULL, NULL, NULL, NULL, 38 &window_class); 39 instance_ = window_class.hInstance; 40 atom_ = RegisterClassEx(&window_class); 41 CHECK(atom_); 42 43 // If the taskbar is re-created after we start up, we have to rebuild all of 44 // our icons. 45 taskbar_created_message_ = RegisterWindowMessage(TEXT("TaskbarCreated")); 46 47 // Create an offscreen window for handling messages for the status icons. We 48 // create a hidden WS_POPUP window instead of an HWND_MESSAGE window, because 49 // only top-level windows such as popups can receive broadcast messages like 50 // "TaskbarCreated". 51 window_ = CreateWindow(MAKEINTATOM(atom_), 52 0, WS_POPUP, 0, 0, 0, 0, 0, 0, instance_, 0); 53 gfx::CheckWindowCreated(window_); 54 gfx::SetWindowUserData(window_, this); 55} 56 57LRESULT CALLBACK StatusTrayWin::WndProcStatic(HWND hwnd, 58 UINT message, 59 WPARAM wparam, 60 LPARAM lparam) { 61 StatusTrayWin* msg_wnd = reinterpret_cast<StatusTrayWin*>( 62 GetWindowLongPtr(hwnd, GWLP_USERDATA)); 63 if (msg_wnd) 64 return msg_wnd->WndProc(hwnd, message, wparam, lparam); 65 else 66 return ::DefWindowProc(hwnd, message, wparam, lparam); 67} 68 69LRESULT CALLBACK StatusTrayWin::WndProc(HWND hwnd, 70 UINT message, 71 WPARAM wparam, 72 LPARAM lparam) { 73 if (message == taskbar_created_message_) { 74 // We need to reset all of our icons because the taskbar went away. 75 for (StatusIcons::const_iterator i(status_icons().begin()); 76 i != status_icons().end(); ++i) { 77 StatusIconWin* win_icon = static_cast<StatusIconWin*>(*i); 78 win_icon->ResetIcon(); 79 } 80 return TRUE; 81 } else if (message == kStatusIconMessage) { 82 StatusIconWin* win_icon = NULL; 83 84 // Find the selected status icon. 85 for (StatusIcons::const_iterator i(status_icons().begin()); 86 i != status_icons().end(); 87 ++i) { 88 StatusIconWin* current_win_icon = static_cast<StatusIconWin*>(*i); 89 if (current_win_icon->icon_id() == wparam) { 90 win_icon = current_win_icon; 91 break; 92 } 93 } 94 95 // It is possible for this procedure to be called with an obsolete icon 96 // id. In that case we should just return early before handling any 97 // actions. 98 if (!win_icon) 99 return TRUE; 100 101 switch (lparam) { 102 case TB_INDETERMINATE: 103 win_icon->HandleBalloonClickEvent(); 104 return TRUE; 105 106 case WM_LBUTTONDOWN: 107 case WM_RBUTTONDOWN: 108 case WM_CONTEXTMENU: 109 // Walk our icons, find which one was clicked on, and invoke its 110 // HandleClickEvent() method. 111 gfx::Point cursor_pos( 112 gfx::Screen::GetNativeScreen()->GetCursorScreenPoint()); 113 win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN); 114 return TRUE; 115 } 116 } 117 return ::DefWindowProc(hwnd, message, wparam, lparam); 118} 119 120StatusTrayWin::~StatusTrayWin() { 121 if (window_) 122 DestroyWindow(window_); 123 124 if (atom_) 125 UnregisterClass(MAKEINTATOM(atom_), instance_); 126} 127 128StatusIcon* StatusTrayWin::CreatePlatformStatusIcon( 129 StatusTray::StatusIconType type, 130 const gfx::ImageSkia& image, 131 const string16& tool_tip) { 132 UINT next_icon_id; 133 if (type == StatusTray::OTHER_ICON) 134 next_icon_id = NextIconId(); 135 else 136 next_icon_id = ReservedIconId(type); 137 138 StatusIcon* icon = NULL; 139 if (win8::IsSingleWindowMetroMode()) 140 icon = new StatusIconMetro(next_icon_id); 141 else 142 icon = new StatusIconWin(next_icon_id, window_, kStatusIconMessage); 143 144 icon->SetImage(image); 145 icon->SetToolTip(tool_tip); 146 return icon; 147} 148 149UINT StatusTrayWin::NextIconId() { 150 UINT icon_id = next_icon_id_++; 151 return kBaseIconId + static_cast<UINT>(NAMED_STATUS_ICON_COUNT) + icon_id; 152} 153 154StatusTray* StatusTray::Create() { 155 return new StatusTrayWin(); 156} 157