summaryrefslogtreecommitdiffstats
path: root/chrome_frame/test/win_event_receiver.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome_frame/test/win_event_receiver.cc')
-rw-r--r--chrome_frame/test/win_event_receiver.cc110
1 files changed, 110 insertions, 0 deletions
diff --git a/chrome_frame/test/win_event_receiver.cc b/chrome_frame/test/win_event_receiver.cc
new file mode 100644
index 0000000..152fb0e
--- /dev/null
+++ b/chrome_frame/test/win_event_receiver.cc
@@ -0,0 +1,110 @@
+// 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.
+
+#include "chrome_frame/test/win_event_receiver.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+
+#include "chrome_frame/function_stub.h"
+
+// WinEventReceiver methods
+WinEventReceiver::WinEventReceiver() : hook_(NULL), hook_stub_(NULL) {
+}
+
+WinEventReceiver::~WinEventReceiver() {
+ StopReceivingEvents();
+}
+
+void WinEventReceiver::SetListenerForEvent(WinEventListener* listener,
+ DWORD event) {
+ SetListenerForEvents(listener, event, event);
+}
+
+void WinEventReceiver::SetListenerForEvents(WinEventListener* listener,
+ DWORD event_min, DWORD event_max) {
+ DCHECK(listener != NULL);
+ StopReceivingEvents();
+
+ listener_ = listener;
+
+ InitializeHook(event_min, event_max);
+}
+
+void WinEventReceiver::StopReceivingEvents() {
+ if (hook_) {
+ ::UnhookWinEvent(hook_);
+ hook_ = NULL;
+ FunctionStub::Destroy(hook_stub_);
+ hook_stub_ = NULL;
+ }
+}
+
+bool WinEventReceiver::InitializeHook(DWORD event_min, DWORD event_max) {
+ DCHECK(hook_ == NULL);
+ DCHECK(hook_stub_ == NULL);
+ hook_stub_ = FunctionStub::Create(reinterpret_cast<uintptr_t>(this),
+ WinEventHook);
+ hook_ = SetWinEventHook(event_min, event_max, NULL,
+ reinterpret_cast<WINEVENTPROC>(hook_stub_->code()), 0,
+ 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
+ DLOG_IF(ERROR, hook_ == NULL) << "Unable to SetWinEvent hook";
+ return hook_ != NULL;
+}
+
+// static
+void WinEventReceiver::WinEventHook(WinEventReceiver* me, HWINEVENTHOOK hook,
+ DWORD event, HWND hwnd, LONG object_id,
+ LONG child_id, DWORD event_thread_id,
+ DWORD event_time) {
+ DCHECK(me->listener_ != NULL);
+ me->listener_->OnEventReceived(event, hwnd);
+}
+
+// WindowWatchdog methods
+void WindowWatchdog::AddObserver(WindowObserver* observer,
+ const std::string& window_class) {
+ if (observers_.empty())
+ win_event_receiver_.SetListenerForEvent(this, EVENT_OBJECT_SHOW);
+
+ WindowObserverEntry new_entry = { observer, window_class };
+ observers_.push_back(new_entry);
+}
+
+void WindowWatchdog::RemoveObserver(WindowObserver* observer) {
+ for (ObserverMap::iterator i = observers_.begin(); i != observers_.end();) {
+ i = (observer == i->observer) ? observers_.erase(i) : ++i;
+ }
+
+ if (observers_.empty())
+ win_event_receiver_.StopReceivingEvents();
+}
+
+void WindowWatchdog::OnEventReceived(DWORD event, HWND hwnd) {
+ // We need to look for top level windows and a natural check is for
+ // WS_CHILD. Instead, checking for WS_CAPTION allows us to filter
+ // out other stray popups
+ if (!(WS_CAPTION & GetWindowLong(hwnd, GWL_STYLE)))
+ return;
+
+ char class_name[MAX_PATH] = {0};
+ ::GetClassNameA(hwnd, class_name, arraysize(class_name));
+
+ ObserverMap interested_observers;
+ for (ObserverMap::iterator i = observers_.begin();
+ i != observers_.end(); i++) {
+ if (0 == lstrcmpA(i->window_class.c_str(), class_name)) {
+ interested_observers.push_back(*i);
+ }
+ }
+
+ std::string caption;
+ int len = ::GetWindowTextLength(hwnd) + 1;
+ ::GetWindowTextA(hwnd, WriteInto(&caption, len), len);
+
+ for (ObserverMap::iterator i = interested_observers.begin();
+ i != interested_observers.end(); i++) {
+ i->observer->OnWindowDetected(hwnd, caption);
+ }
+}