/* * Copyright 2013 Canonical Ltd. * Copyright 2021 Robert Tari * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * * Authors: * Charles Kerr * Robert Tari */ #include #include #include "dbus-alarm-properties.h" #include #include namespace ayatana { namespace indicator { namespace datetime { /*** **** ***/ class Exporter::Impl { public: explicit Impl(const std::shared_ptr& settings): m_settings(settings), m_alarm_props(datetime_alarm_properties_skeleton_new()) { alarm_properties_init(); } ~Impl() { if (m_bus != nullptr) { for(auto& id : m_exported_menu_ids) g_dbus_connection_unexport_menu_model(m_bus, id); if (m_exported_actions_id) g_dbus_connection_unexport_action_group(m_bus, m_exported_actions_id); } g_dbus_interface_skeleton_unexport(G_DBUS_INTERFACE_SKELETON(m_alarm_props)); g_clear_object(&m_alarm_props); if (m_own_id) g_bus_unown_name(m_own_id); g_clear_object(&m_bus); } core::Signal<> name_lost; void publish(const std::shared_ptr& actions, const std::vector>& menus) { m_actions = actions; m_menus = menus; m_own_id = g_bus_own_name(G_BUS_TYPE_SESSION, BUS_DATETIME_NAME, G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, on_bus_acquired, nullptr, on_name_lost, this, nullptr); } private: /*** **** ***/ static void on_gobject_notify_string(GObject* o, GParamSpec* pspec, gpointer p) { gchar* val = nullptr; g_object_get (o, pspec->name, &val, nullptr); static_cast*>(p)->set(val); g_free(val); } void bind_string_property(gpointer o, const char* propname, core::Property& p) { // initialize the GObject property from the Settings g_object_set(o, propname, p.get().c_str(), nullptr); // when the GObject changes, update the Settings const std::string notify_propname = std::string("notify::") + propname; g_signal_connect(o, notify_propname.c_str(), G_CALLBACK(on_gobject_notify_string), &p); // when the Settings changes, update the GObject p.changed().connect([o, propname](const std::string& val){ g_object_set(o, propname, val.c_str(), nullptr); }); } static void on_gobject_notify_uint(GObject* o, GParamSpec* pspec, gpointer p) { uint val = 0; g_object_get (o, pspec->name, &val, nullptr); static_cast*>(p)->set(val); } void bind_uint_property(gpointer o, const char* propname, core::Property& p) { // initialize the GObject property from the Settings g_object_set(o, propname, p.get(), nullptr); // when the GObject changes, update the Settings const std::string notify_propname = std::string("notify::") + propname; g_signal_connect(o, notify_propname.c_str(), G_CALLBACK(on_gobject_notify_uint), &p); // when the Settings changes, update the GObject p.changed().connect([o, propname](unsigned int val){ g_object_set(o, propname, val, nullptr); }); } void alarm_properties_init() { bind_uint_property(m_alarm_props, "duration", m_settings->alarm_duration); bind_uint_property(m_alarm_props, "default-volume", m_settings->alarm_volume); bind_string_property(m_alarm_props, "default-sound", m_settings->alarm_sound); bind_string_property(m_alarm_props, "haptic-feedback", m_settings->alarm_haptic); bind_uint_property(m_alarm_props, "snooze-duration", m_settings->snooze_duration); } /*** **** ***/ static void on_bus_acquired(GDBusConnection* connection, const gchar* name, gpointer gthis) { g_debug("bus acquired: %s", name); static_cast(gthis)->on_bus_acquired(connection, name); } void on_bus_acquired(GDBusConnection* bus, const gchar* /*name*/) { m_bus = static_cast(g_object_ref(bus)); // export the alarm properties GError * error = nullptr; g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(m_alarm_props), m_bus, BUS_DATETIME_PATH"/AlarmProperties", &error); // export the actions const auto id = g_dbus_connection_export_action_group(m_bus, BUS_DATETIME_PATH, m_actions->action_group(), &error); if (id) { m_exported_actions_id = id; } else { g_warning("cannot export action group: %s", error->message); g_clear_error(&error); } // export the menus for(auto& menu : m_menus) { const auto path = std::string(BUS_DATETIME_PATH) + "/" + menu->name(); const auto nId = g_dbus_connection_export_menu_model(m_bus, path.c_str(), menu->menu_model(), &error); if (nId) { m_exported_menu_ids.insert(nId); } else { if (error != nullptr) g_warning("cannot export %s menu: %s", menu->name().c_str(), error->message); g_clear_error(&error); } } } /*** **** ***/ static void on_name_lost(GDBusConnection*, const gchar* name, gpointer gthis) { g_debug("name lost: %s", name); static_cast(gthis)->name_lost(); } /*** **** ***/ std::shared_ptr m_settings; std::set m_exported_menu_ids; guint m_own_id = 0; guint m_exported_actions_id = 0; GDBusConnection* m_bus = nullptr; std::shared_ptr m_actions; std::vector> m_menus; DatetimeAlarmProperties* m_alarm_props = nullptr; }; /*** **** ***/ Exporter::Exporter(const std::shared_ptr& settings): p(new Impl(settings)) { } Exporter::~Exporter() { } core::Signal<>& Exporter::name_lost() { return p->name_lost; } void Exporter::publish(const std::shared_ptr& actions, const std::vector>& menus) { p->publish(actions, menus); } /*** **** ***/ } // namespace datetime } // namespace indicator } // namespace ayatana