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