Home | History | Annotate | Download | only in status_icons
      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/base/win/hwnd_util.h"
     13 #include "ui/gfx/screen.h"
     14 #include "win8/util/win8_util.h"
     15 
     16 static const UINT kStatusIconMessage = WM_APP + 1;
     17 
     18 namespace {
     19 // |kBaseIconId| is 2 to avoid conflicts with plugins that hard-code id 1.
     20 const UINT kBaseIconId = 2;
     21 
     22 UINT ReservedIconId(StatusTray::StatusIconType type) {
     23   return kBaseIconId + static_cast<UINT>(type);
     24 }
     25 }  // namespace
     26 
     27 StatusTrayWin::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   ui::CheckWindowCreated(window_);
     54   ui::SetWindowUserData(window_, this);
     55 }
     56 
     57 LRESULT 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 
     69 LRESULT 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 
    120 StatusTrayWin::~StatusTrayWin() {
    121   if (window_)
    122     DestroyWindow(window_);
    123 
    124   if (atom_)
    125     UnregisterClass(MAKEINTATOM(atom_), instance_);
    126 }
    127 
    128 StatusIcon* 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 
    149 UINT StatusTrayWin::NextIconId() {
    150   UINT icon_id = next_icon_id_++;
    151   return kBaseIconId + static_cast<UINT>(NAMED_STATUS_ICON_COUNT) + icon_id;
    152 }
    153 
    154 StatusTray* StatusTray::Create() {
    155   return new StatusTrayWin();
    156 }
    157