1 // Copyright (c) 2011 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_icon_win.h" 6 7 #include "base/sys_string_conversions.h" 8 #include "third_party/skia/include/core/SkBitmap.h" 9 #include "ui/gfx/icon_util.h" 10 #include "ui/gfx/point.h" 11 #include "views/controls/menu/menu_2.h" 12 13 StatusIconWin::StatusIconWin(UINT id, HWND window, UINT message) 14 : icon_id_(id), 15 window_(window), 16 message_id_(message) { 17 NOTIFYICONDATA icon_data; 18 InitIconData(&icon_data); 19 icon_data.uFlags = NIF_MESSAGE; 20 icon_data.uCallbackMessage = message_id_; 21 BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data); 22 // This can happen if the explorer process isn't running when we try to 23 // create the icon for some reason (for example, at startup). 24 if (!result) 25 LOG(WARNING) << "Unable to create status tray icon."; 26 } 27 28 StatusIconWin::~StatusIconWin() { 29 // Remove our icon. 30 NOTIFYICONDATA icon_data; 31 InitIconData(&icon_data); 32 Shell_NotifyIcon(NIM_DELETE, &icon_data); 33 } 34 35 void StatusIconWin::SetImage(const SkBitmap& image) { 36 // Create the icon. 37 NOTIFYICONDATA icon_data; 38 InitIconData(&icon_data); 39 icon_data.uFlags = NIF_ICON; 40 icon_.Set(IconUtil::CreateHICONFromSkBitmap(image)); 41 icon_data.hIcon = icon_.Get(); 42 BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); 43 if (!result) 44 LOG(WARNING) << "Error setting status tray icon image"; 45 } 46 47 void StatusIconWin::ResetIcon() { 48 NOTIFYICONDATA icon_data; 49 InitIconData(&icon_data); 50 // Delete any previously existing icon. 51 Shell_NotifyIcon(NIM_DELETE, &icon_data); 52 InitIconData(&icon_data); 53 icon_data.uFlags = NIF_MESSAGE; 54 icon_data.uCallbackMessage = message_id_; 55 icon_data.hIcon = icon_.Get(); 56 // If we have an image, then set the NIF_ICON flag, which tells 57 // Shell_NotifyIcon() to set the image for the status icon it creates. 58 if (icon_data.hIcon) 59 icon_data.uFlags |= NIF_ICON; 60 // Re-add our icon. 61 BOOL result = Shell_NotifyIcon(NIM_ADD, &icon_data); 62 if (!result) 63 LOG(WARNING) << "Unable to re-create status tray icon."; 64 } 65 66 void StatusIconWin::SetPressedImage(const SkBitmap& image) { 67 // Ignore pressed images, since the standard on Windows is to not highlight 68 // pressed status icons. 69 } 70 71 void StatusIconWin::SetToolTip(const string16& tool_tip) { 72 // Create the icon. 73 NOTIFYICONDATA icon_data; 74 InitIconData(&icon_data); 75 icon_data.uFlags = NIF_TIP; 76 wcscpy_s(icon_data.szTip, tool_tip.c_str()); 77 BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); 78 if (!result) 79 LOG(WARNING) << "Unable to set tooltip for status tray icon"; 80 } 81 82 void StatusIconWin::DisplayBalloon(const string16& title, 83 const string16& contents) { 84 NOTIFYICONDATA icon_data; 85 InitIconData(&icon_data); 86 icon_data.uFlags = NIF_INFO; 87 icon_data.dwInfoFlags = NIIF_INFO; 88 wcscpy_s(icon_data.szInfoTitle, title.c_str()); 89 wcscpy_s(icon_data.szInfo, contents.c_str()); 90 icon_data.uTimeout = 0; 91 BOOL result = Shell_NotifyIcon(NIM_MODIFY, &icon_data); 92 if (!result) 93 LOG(WARNING) << "Unable to create status tray balloon."; 94 } 95 96 void StatusIconWin::UpdatePlatformContextMenu(ui::MenuModel* menu) { 97 // If no items are passed, blow away our context menu. 98 if (!menu) { 99 context_menu_.reset(); 100 return; 101 } 102 103 // Create context menu with the new contents. 104 context_menu_.reset(new views::Menu2(menu)); 105 } 106 107 void StatusIconWin::HandleClickEvent(int x, int y, bool left_mouse_click) { 108 // Pass to the observer if appropriate. 109 if (left_mouse_click && HasObservers()) { 110 DispatchClickEvent(); 111 return; 112 } 113 114 // Event not sent to the observer, so display the context menu if one exists. 115 if (context_menu_.get()) { 116 // Set our window as the foreground window, so the context menu closes when 117 // we click away from it. 118 SetForegroundWindow(window_); 119 context_menu_->RunContextMenuAt(gfx::Point(x, y)); 120 } 121 } 122 123 void StatusIconWin::InitIconData(NOTIFYICONDATA* icon_data) { 124 icon_data->cbSize = sizeof(NOTIFYICONDATA); 125 icon_data->hWnd = window_; 126 icon_data->uID = icon_id_; 127 } 128