blob: 92b2e00edc745e91e45f74b2d91b862f3a30a163 [file] [log] [blame]
// Copyright 2016 The Android Open Source Project
// This software is licensed under the terms of the GNU General Public
// License version 2, as published by the Free Software Foundation, and
// may be copied, distributed, and modified under those terms.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
#include "android/skin/qt/event-capturer.h"
EventCapturer::SubscriberToken EventCapturer::subscribeToEvents(
QObject* root,
const EventCapturer::ObjectPredicate& child_predicate,
const EventCapturer::EventTypeSet& event_types,
const EventCapturer::Callback& callback) {
// This will contain the set of objects whose events the caller
// should be subscribed to.
std::unordered_set<QObject*> objects;
// Traverse the object hierarchy starting at root. For each object,
// check the value of |child_predicate|. If it is true, include it
// into the set of monitored objects.
auto watch_if_needed = [&child_predicate, &objects, this](QObject* obj) {
if (child_predicate(obj)) {
objects.insert(obj);
obj->installEventFilter(this);
}
};
watch_if_needed(root);
for (QObject* obj : root->findChildren<QObject*>()) {
watch_if_needed(obj);
if (child_predicate(obj)) {
objects.insert(obj);
obj->installEventFilter(this);
}
}
return mSubscribers.emplace(event_types, std::move(objects), callback);
}
bool EventCapturer::eventFilter(QObject* target, QEvent* event) {
// Indicates whether |target| still has any subscribers
// interested in its events.
bool has_subscribers = false;
for (auto& subscriber : mSubscribers) {
if (subscriber.objects.count(target)) {
has_subscribers = true;
if(subscriber.event_types.count(event->type())) {
subscriber.callback(target, event);
}
}
}
if (!has_subscribers) {
// If there are no subscribers interested in events from
// this object, it is safe to remove the event filter for
// it.
target->removeEventFilter(this);
}
return QObject::eventFilter(target, event);
}