// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // Funnel of Chrome Extension Events to be sent to Chrome. #include "ceee/ie/broker/window_events_funnel.h" #include "base/json/json_writer.h" #include "base/logging.h" #include "base/scoped_ptr.h" #include "base/values.h" #include "ceee/common/com_utils.h" #include "ceee/common/windows_constants.h" #include "ceee/common/window_utils.h" #include "ceee/ie/broker/chrome_postman.h" #include "ceee/ie/common/ie_util.h" #include "chrome/browser/extensions/extension_event_names.h" #include "chrome/browser/extensions/extension_tabs_module_constants.h" namespace ext_event_names = extension_event_names; namespace keys = extension_tabs_module_constants; namespace { // The Shell Hook uses a registered message to communicate with registered // windows. const UINT kShellHookMessage = ::RegisterWindowMessage(L"SHELLHOOK"); // The HWND, Class and WindowProc for the Registered Shell Hook Window. HWND shell_hook_window = NULL; const wchar_t kShellHookWindowClassName[] = L"CeeeShellHookWindow"; LRESULT CALLBACK WindowEventsFunnelWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { if (message == kShellHookMessage) { switch (wparam) { // case HSHELL_WINDOWCREATED: { // if (window_utils::IsWindowClass(reinterpret_cast(lparam), // windows::kIeFrameWindowClass)) { // WindowEventsFunnel window_events_funnel; // window_events_funnel.OnCreated(lparam); // } // break; // } // case HSHELL_WINDOWDESTROYED: { // if (window_utils::IsWindowClass(reinterpret_cast(lparam), // windows::kIeFrameWindowClass)) { // WindowEventsFunnel window_events_funnel; // window_events_funnel.OnRemoved(lparam); // } // break; // } case HSHELL_WINDOWACTIVATED: { if (window_utils::IsWindowClass(reinterpret_cast(lparam), windows::kIeFrameWindowClass)) { WindowEventsFunnel window_events_funnel; window_events_funnel.OnFocusChanged(lparam); } break; } } } return ::DefWindowProc(hwnd, message, wparam, lparam); } } void WindowEventsFunnel::Initialize() { if (shell_hook_window) return; WNDCLASSEX shell_window_hook_class = {0}; shell_window_hook_class.cbSize = sizeof(WNDCLASSEX); shell_window_hook_class.lpfnWndProc = WindowEventsFunnelWindowProc; shell_window_hook_class.hInstance = GetModuleHandle(NULL); shell_window_hook_class.lpszClassName = kShellHookWindowClassName; ATOM class_registration = ::RegisterClassEx(&shell_window_hook_class); DCHECK(class_registration != NULL) << "Couldn't register Shell Hook Window class!" << com::LogWe(); if (!class_registration) return; shell_hook_window = ::CreateWindow( reinterpret_cast(class_registration), L"", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); DCHECK(shell_hook_window != NULL) << "Couldn't Create Shell Hook Window!" << com::LogWe(); if (shell_hook_window) { BOOL success = ::RegisterShellHookWindow(shell_hook_window); DCHECK(success) << "Couldn't register shell hook window!" << com::LogWe(); } } void WindowEventsFunnel::Terminate() { if (shell_hook_window) { BOOL success = ::DeregisterShellHookWindow(shell_hook_window); DCHECK(success) << "Couldn't unregister shell hook window!" << com::LogWe(); success = ::DestroyWindow(shell_hook_window); shell_hook_window = NULL; DCHECK(success) << "Couldn't destroy shell hook window!" << com::LogWe(); } } HRESULT WindowEventsFunnel::SendEvent(const char* event_name, const Value& event_args) { // Event arguments are always stored in a list. std::string event_args_str; if (event_args.IsType(Value::TYPE_LIST)) { base::JSONWriter::Write(&event_args, false, &event_args_str); } else { ListValue list; list.Append(event_args.DeepCopy()); base::JSONWriter::Write(&list, false, &event_args_str); } DCHECK(ChromePostman::GetInstance() != NULL); ChromePostman::GetInstance()->FireEvent(event_name, event_args_str.c_str()); return S_OK; } HRESULT WindowEventsFunnel::OnCreated(HWND window) { RECT window_rect; if (!::GetWindowRect(window, &window_rect)) { DWORD we = ::GetLastError(); DCHECK(false) << "GetWindowRect failed " << com::LogWe(we); return HRESULT_FROM_WIN32(we); } scoped_ptr dict(new DictionaryValue()); dict->SetInteger(keys::kIdKey, reinterpret_cast(window)); dict->SetBoolean(keys::kFocusedKey, (window == window_utils::GetTopLevelParent(::GetForegroundWindow()))); dict->SetInteger(keys::kLeftKey, window_rect.left); dict->SetInteger(keys::kTopKey, window_rect.top); dict->SetInteger(keys::kWidthKey, window_rect.right - window_rect.left); dict->SetInteger(keys::kHeightKey, window_rect.bottom - window_rect.top); dict->SetBoolean(keys::kIncognitoKey, ie_util::GetIEIsInPrivateBrowsing()); // TODO(mad@chromium.org): for now, always setting to "normal" since // we don't yet have a way to tell if the window is a popup or not. dict->SetString(keys::kWindowTypeKey, keys::kWindowTypeValueNormal); return SendEvent(ext_event_names::kOnWindowCreated, *dict.get()); } HRESULT WindowEventsFunnel::OnFocusChanged(int window_id) { scoped_ptr args(Value::CreateIntegerValue(window_id)); return SendEvent(ext_event_names::kOnWindowFocusedChanged, *args.get()); } HRESULT WindowEventsFunnel::OnRemoved(HWND window) { scoped_ptr args(Value::CreateIntegerValue( reinterpret_cast(window))); return SendEvent(ext_event_names::kOnWindowRemoved, *args.get()); }