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_tray_win.h"
6
7#include "base/win/wrapped_window_proc.h"
8#include "chrome/browser/ui/views/status_icons/status_icon_win.h"
9#include "chrome/common/chrome_constants.h"
10#include "ui/base/win/hwnd_util.h"
11
12static const UINT kStatusIconMessage = WM_APP + 1;
13
14StatusTrayWin::StatusTrayWin()
15    : next_icon_id_(1) {
16  // Register our window class
17  HINSTANCE hinst = GetModuleHandle(NULL);
18  WNDCLASSEX wc = {0};
19  wc.cbSize = sizeof(wc);
20  wc.lpfnWndProc = base::win::WrappedWindowProc<StatusTrayWin::WndProcStatic>;
21  wc.hInstance = hinst;
22  wc.lpszClassName = chrome::kStatusTrayWindowClass;
23  ATOM clazz = RegisterClassEx(&wc);
24  DCHECK(clazz);
25
26  // If the taskbar is re-created after we start up, we have to rebuild all of
27  // our icons.
28  taskbar_created_message_ = RegisterWindowMessage(TEXT("TaskbarCreated"));
29
30  // Create an offscreen window for handling messages for the status icons. We
31  // create a hidden WS_POPUP window instead of an HWND_MESSAGE window, because
32  // only top-level windows such as popups can receive broadcast messages like
33  // "TaskbarCreated".
34  window_ = CreateWindow(chrome::kStatusTrayWindowClass,
35                         0, WS_POPUP, 0, 0, 0, 0, 0, 0, hinst, 0);
36  ui::CheckWindowCreated(window_);
37  ui::SetWindowUserData(window_, this);
38}
39
40LRESULT CALLBACK StatusTrayWin::WndProcStatic(HWND hwnd,
41                                              UINT message,
42                                              WPARAM wparam,
43                                              LPARAM lparam) {
44  StatusTrayWin* msg_wnd = reinterpret_cast<StatusTrayWin*>(
45      GetWindowLongPtr(hwnd, GWLP_USERDATA));
46  if (msg_wnd)
47    return msg_wnd->WndProc(hwnd, message, wparam, lparam);
48  else
49    return ::DefWindowProc(hwnd, message, wparam, lparam);
50}
51
52LRESULT CALLBACK StatusTrayWin::WndProc(HWND hwnd,
53                                        UINT message,
54                                        WPARAM wparam,
55                                        LPARAM lparam) {
56  if (message == taskbar_created_message_) {
57    // We need to reset all of our icons because the taskbar went away.
58    for (StatusIconList::const_iterator iter = status_icons().begin();
59         iter != status_icons().end();
60         ++iter) {
61      StatusIconWin* win_icon = static_cast<StatusIconWin*>(*iter);
62      win_icon->ResetIcon();
63    }
64    return TRUE;
65  } else if (message == kStatusIconMessage) {
66    switch (lparam) {
67      case WM_LBUTTONDOWN:
68      case WM_RBUTTONDOWN:
69      case WM_CONTEXTMENU:
70        // Walk our icons, find which one was clicked on, and invoke its
71        // HandleClickEvent() method.
72        for (StatusIconList::const_iterator iter = status_icons().begin();
73             iter != status_icons().end();
74             ++iter) {
75          StatusIconWin* win_icon = static_cast<StatusIconWin*>(*iter);
76          if (win_icon->icon_id() == wparam) {
77            POINT p;
78            GetCursorPos(&p);
79            win_icon->HandleClickEvent(p.x, p.y, lparam == WM_LBUTTONDOWN);
80          }
81        }
82        return TRUE;
83    }
84  }
85  return ::DefWindowProc(hwnd, message, wparam, lparam);
86}
87
88StatusTrayWin::~StatusTrayWin() {
89  if (window_)
90    DestroyWindow(window_);
91  UnregisterClass(chrome::kStatusTrayWindowClass, GetModuleHandle(NULL));
92}
93
94StatusIcon* StatusTrayWin::CreatePlatformStatusIcon() {
95  return new StatusIconWin(next_icon_id_++, window_, kStatusIconMessage);
96}
97
98StatusTray* StatusTray::Create() {
99  return new StatusTrayWin();
100}
101