mpd/src/lib/dbus/Watch.hxx
2020-10-15 16:06:19 +02:00

158 lines
3.8 KiB
C++

/*
* Copyright 2007-2020 CM4all GmbH
* All rights reserved.
*
* author: Max Kellermann <mk@cm4all.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ODBUS_WATCH_HXX
#define ODBUS_WATCH_HXX
#include "Connection.hxx"
#include "event/SocketEvent.hxx"
#include "event/DeferEvent.hxx"
#include <dbus/dbus.h>
#include <map>
class EventLoop;
namespace ODBus {
class WatchManagerObserver {
public:
virtual void OnDBusClosed() noexcept = 0;
};
/**
* Integrate a DBusConnection into the #EventLoop.
*/
class WatchManager {
WatchManagerObserver &observer;
Connection connection;
class Watch {
WatchManager &parent;
DBusWatch &watch;
SocketEvent event;
public:
Watch(EventLoop &event_loop, WatchManager &_parent,
DBusWatch &_watch) noexcept;
void Toggled() noexcept;
private:
void OnSocketReady(unsigned events) noexcept;
};
std::map<DBusWatch *, Watch> watches;
DeferEvent defer_dispatch;
public:
WatchManager(EventLoop &event_loop,
WatchManagerObserver &_observer) noexcept
:observer(_observer),
defer_dispatch(event_loop, BIND_THIS_METHOD(Dispatch))
{
}
template<typename C>
WatchManager(EventLoop &event_loop, WatchManagerObserver &_observer,
C &&_connection) noexcept
:WatchManager(event_loop, _observer)
{
SetConnection(std::forward<C>(_connection));
}
~WatchManager() noexcept {
Shutdown();
}
WatchManager(const WatchManager &) = delete;
WatchManager &operator=(const WatchManager &) = delete;
void Shutdown() noexcept;
auto &GetEventLoop() const noexcept {
return defer_dispatch.GetEventLoop();
}
Connection &GetConnection() noexcept {
return connection;
}
template<typename C>
void SetConnection(C &&_connection) noexcept {
Shutdown();
connection = std::forward<C>(_connection);
if (connection)
dbus_connection_set_watch_functions(connection,
AddFunction,
RemoveFunction,
ToggledFunction,
(void *)this,
nullptr);
}
private:
void ScheduleDispatch() noexcept {
defer_dispatch.Schedule();
}
void Dispatch() noexcept;
bool Add(DBusWatch *watch) noexcept;
void Remove(DBusWatch *watch) noexcept;
void Toggled(DBusWatch *watch) noexcept;
static dbus_bool_t AddFunction(DBusWatch *watch, void *data) noexcept {
auto &wm = *(WatchManager *)data;
return wm.Add(watch);
}
static void RemoveFunction(DBusWatch *watch, void *data) noexcept {
auto &wm = *(WatchManager *)data;
wm.Remove(watch);
}
static void ToggledFunction(DBusWatch *watch, void *data) noexcept {
auto &wm = *(WatchManager *)data;
wm.Toggled(watch);
}
};
} /* namespace ODBus */
#endif