aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/com.canonical.indicator.datetime.AlarmProperties.xml31
-rw-r--r--include/datetime/exporter.h3
-rw-r--r--src/CMakeLists.txt31
-rw-r--r--src/exporter.cpp115
-rw-r--r--src/main.cpp2
-rw-r--r--tests/CMakeLists.txt2
-rw-r--r--tests/test-exporter.cpp93
7 files changed, 261 insertions, 16 deletions
diff --git a/data/com.canonical.indicator.datetime.AlarmProperties.xml b/data/com.canonical.indicator.datetime.AlarmProperties.xml
new file mode 100644
index 0000000..d25fa82
--- /dev/null
+++ b/data/com.canonical.indicator.datetime.AlarmProperties.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+ <interface name="com.canonical.indicator.datetime.AlarmProperties">
+
+ <property name="DefaultSound" type="s" access="readwrite">
+ <doc:doc>
+ <doc:description>
+ <doc:para>The default alarm sound's filename.</doc:para>
+ </doc:description>
+ </doc:doc>
+ </property>
+
+ <property name="DefaultVolume" type="i" access="readwrite">
+ <doc:doc>
+ <doc:description>
+ <doc:para>How loudly to play alarm sounds. [Range: 1-100]</doc:para>
+ </doc:description>
+ </doc:doc>
+ </property>
+
+ <property name="Duration" type="i" access="readwrite">
+ <doc:doc>
+ <doc:description>
+ <doc:para>How long an alarm's sound should be looped.</doc:para>
+ </doc:description>
+ </doc:doc>
+ </property>
+
+ </interface>
+</node>
diff --git a/include/datetime/exporter.h b/include/datetime/exporter.h
index 8ae70b1..dd57263 100644
--- a/include/datetime/exporter.h
+++ b/include/datetime/exporter.h
@@ -22,6 +22,7 @@
#include <datetime/actions.h>
#include <datetime/menu.h>
+#include <datetime/settings.h>
#include <core/signal.h>
@@ -38,7 +39,7 @@ namespace datetime {
class Exporter
{
public:
- Exporter();
+ Exporter(const std::shared_ptr<Settings>&);
~Exporter();
core::Signal<>& name_lost();
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ffa1523..af09c71 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,13 +1,13 @@
set (SERVICE_LIB "indicatordatetimeservice")
set (SERVICE_EXEC "indicator-datetime-service")
-SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -g ${CXX_WARNING_ARGS} ${GCOV_FLAGS}")
-SET (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g ${CXX_WARNING_ARGS} ${GCOV_FLAGS}")
-
add_definitions (-DTIMEZONE_FILE="/etc/timezone"
-DG_LOG_DOMAIN="Indicator-Datetime")
-set (SERVICE_SOURCES
+# handwritten sources
+set (SERVICE_C_SOURCES
+ utils.c)
+set (SERVICE_CXX_SOURCES
actions.cpp
actions-live.cpp
alarm-queue-simple.cpp
@@ -32,16 +32,33 @@ set (SERVICE_SOURCES
timezones-live.cpp
utils.c
wakeup-timer-mainloop.cpp)
-
if (HAVE_UBUNTU_HW_ALARM_H)
- set (SERVICE_SOURCES ${SERVICE_SOURCES} wakeup-timer-uha.cpp)
+ set (SERVICE_CXX_SOURCES ${SERVICE_CXX_SOURCES} wakeup-timer-uha.cpp)
endif ()
-add_library (${SERVICE_LIB} STATIC ${SERVICE_SOURCES})
+# generated sources
+include (GdbusCodegen)
+set(SERVICE_GENERATED_SOURCES)
+add_gdbus_codegen(SERVICE_GENERATED_SOURCES dbus-alarm-properties
+ com.canonical.indicator
+ ${CMAKE_SOURCE_DIR}/data/com.canonical.indicator.datetime.AlarmProperties.xml)
+
+# add warnings/coverage info on handwritten files
+# but not the autogenerated ones...
+set_source_files_properties(${SERVICE_CXX_SOURCES}
+ PROPERTIES COMPILE_FLAGS "${CXX_WARNING_ARGS} ${GCOV_FLAGS} -g -std=c++11")
+set_source_files_properties(${SERVICE_C_SOURCES}
+ PROPERTIES COMPILE_FLAGS "${CXX_WARNING_ARGS} ${GCOV_FLAGS} -g -std=c99")
+
+# add the bin dir to our include path so our code can find the generated header files
+include_directories (${CMAKE_CURRENT_BINARY_DIR})
+
+add_library (${SERVICE_LIB} STATIC ${SERVICE_C_SOURCES} ${SERVICE_CXX_SOURCES} ${SERVICE_GENERATED_SOURCES})
include_directories (${CMAKE_SOURCE_DIR})
link_directories (${SERVICE_DEPS_LIBRARY_DIRS})
add_executable (${SERVICE_EXEC} main.cpp)
+set_source_files_properties(${SERVICE_SOURCES} main.cpp PROPERTIES COMPILE_FLAGS "${CXX_WARNING_ARGS} -g -std=c++11")
target_link_libraries (${SERVICE_EXEC} ${SERVICE_LIB} ${SERVICE_DEPS_LIBRARIES} ${GCOV_LIBS})
install (TARGETS ${SERVICE_EXEC} RUNTIME DESTINATION ${CMAKE_INSTALL_FULL_PKGLIBEXECDIR})
diff --git a/src/exporter.cpp b/src/exporter.cpp
index a4919e9..3ba95bf 100644
--- a/src/exporter.cpp
+++ b/src/exporter.cpp
@@ -20,6 +20,8 @@
#include <datetime/dbus-shared.h>
#include <datetime/exporter.h>
+#include "dbus-alarm-properties.h"
+
#include <glib/gi18n.h>
#include <gio/gio.h>
@@ -35,9 +37,11 @@ class Exporter::Impl
{
public:
- Impl (Exporter* owner):
- m_owner(owner)
+ Impl(const std::shared_ptr<Settings>& settings):
+ m_settings(settings),
+ m_alarm_props(datetime_alarm_properties_skeleton_new())
{
+ alarm_properties_init();
}
~Impl()
@@ -51,6 +55,9 @@ public:
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);
@@ -76,6 +83,95 @@ public:
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<core::Property<std::string>*>(p)->set(val);
+ g_free(val);
+ }
+ void bind_string_property(gpointer o, const char* propname,
+ core::Property<std::string>& 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& s){
+ g_object_set(o, propname, s.c_str(), nullptr);
+ });
+ }
+
+
+ static void
+ on_gobject_notify_int(GObject* o, GParamSpec* pspec, gpointer p)
+ {
+ int val = 0;
+ g_object_get (o, pspec->name, &val, nullptr);
+ static_cast<core::Property<int>*>(p)->set(val);
+ }
+ void bind_int_property(gpointer o, const char* propname, core::Property<int>& 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_int), &p);
+
+ // when the Settings changes, update the GObject
+ p.changed().connect([o, propname](int i){
+ g_object_set(o, propname, i, nullptr);
+ });
+ }
+
+
+ static void
+ on_gobject_notify_volume(GObject* o, GParamSpec* pspec, gpointer p)
+ {
+ int val = 0;
+ g_object_get (o, pspec->name, &val, nullptr);
+ static_cast<core::Property<AlarmVolume>*>(p)->set(AlarmVolume(val));
+ }
+ void bind_volume_property(gpointer o, const char* propname, core::Property<AlarmVolume>& p)
+ {
+ // initialize the GObject property from the Settings
+ g_object_set(o, propname, (int)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_volume), &p);
+
+ // when the Settings changes, update the GObject
+ p.changed().connect([o, propname](AlarmVolume i){
+ g_object_set(o, propname, (int)i, nullptr);
+ });
+ }
+
+
+ void alarm_properties_init()
+ {
+ bind_int_property(m_alarm_props, "duration", m_settings->alarm_duration);
+ bind_volume_property(m_alarm_props, "default-volume", m_settings->alarm_volume);
+ bind_string_property(m_alarm_props, "default-sound", m_settings->alarm_sound);
+ }
+
+ /***
+ ****
+ ***/
+
static void on_bus_acquired(GDBusConnection* connection,
const gchar* name,
gpointer gthis)
@@ -88,8 +184,14 @@ private:
{
m_bus = static_cast<GDBusConnection*>(g_object_ref(G_OBJECT(bus)));
- // export the actions
+ // export the alarm properties
GError * error = nullptr;
+ g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(m_alarm_props),
+ m_bus,
+ BUS_PATH"/AlarmProperties",
+ &error);
+
+ // export the actions
const auto id = g_dbus_connection_export_action_group(m_bus,
BUS_PATH,
m_actions->action_group(),
@@ -136,13 +238,14 @@ private:
****
***/
- Exporter const * m_owner;
+ std::shared_ptr<Settings> m_settings;
std::set<guint> m_exported_menu_ids;
guint m_own_id = 0;
guint m_exported_actions_id = 0;
GDBusConnection* m_bus = nullptr;
std::shared_ptr<Actions> m_actions;
std::vector<std::shared_ptr<Menu>> m_menus;
+ DatetimeAlarmProperties* m_alarm_props = nullptr;
};
@@ -150,8 +253,8 @@ private:
****
***/
-Exporter::Exporter():
- p(new Impl(this))
+Exporter::Exporter(const std::shared_ptr<Settings>& settings):
+ p(new Impl(settings))
{
}
diff --git a/src/main.cpp b/src/main.cpp
index 04845ce..cc81cd7 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -163,7 +163,7 @@ main(int /*argc*/, char** /*argv*/)
// export them & run until we lose the busname
auto loop = g_main_loop_new(nullptr, false);
- Exporter exporter;
+ Exporter exporter(state->settings);
exporter.name_lost().connect([loop](){
g_message("%s exiting; failed/lost bus ownership", GETTEXT_PACKAGE);
g_main_loop_quit(loop);
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index fe6d7eb..26b326d 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -27,9 +27,11 @@ add_custom_command (OUTPUT gschemas.compiled
# look for headers in our src dir, and also in the directories where we autogenerate files...
include_directories (${CMAKE_SOURCE_DIR}/src)
+include_directories (${CMAKE_BINARY_DIR}/src)
include_directories (${CMAKE_CURRENT_BINARY_DIR})
include_directories (${DBUSTEST_INCLUDE_DIRS})
+
add_definitions (-DSANDBOX="${CMAKE_CURRENT_BINARY_DIR}")
diff --git a/tests/test-exporter.cpp b/tests/test-exporter.cpp
index 4fb2c54..3f502cf 100644
--- a/tests/test-exporter.cpp
+++ b/tests/test-exporter.cpp
@@ -21,6 +21,8 @@
#include "state-mock.h"
#include "glib-fixture.h"
+#include "dbus-alarm-properties.h"
+
#include <datetime/actions.h>
#include <datetime/dbus-shared.h>
#include <datetime/exporter.h>
@@ -76,13 +78,14 @@ TEST_F(ExporterFixture, Publish)
{
std::shared_ptr<State> state(new MockState);
std::shared_ptr<Actions> actions(new MockActions(state));
+ std::shared_ptr<Settings> settings(new Settings);
std::vector<std::shared_ptr<Menu>> menus;
MenuFactory menu_factory (actions, state);
for(int i=0; i<Menu::NUM_PROFILES; i++)
menus.push_back(menu_factory.buildMenu(Menu::Profile(i)));
- Exporter exporter;
+ Exporter exporter(settings);
exporter.publish(actions, menus);
wait_msec();
@@ -135,3 +138,91 @@ TEST_F(ExporterFixture, Publish)
g_clear_object(&exported);
g_clear_object(&connection);
}
+
+TEST_F(ExporterFixture, AlarmProperties)
+{
+ /***
+ **** Set up the exporter
+ ***/
+
+ std::shared_ptr<State> state(new MockState);
+ std::shared_ptr<Actions> actions(new MockActions(state));
+ std::shared_ptr<Settings> settings(new Settings);
+ std::vector<std::shared_ptr<Menu>> menus;
+
+ MenuFactory menu_factory (actions, state);
+ for(int i=0; i<Menu::NUM_PROFILES; i++)
+ menus.push_back(menu_factory.buildMenu(Menu::Profile(i)));
+
+ Exporter exporter(settings);
+ exporter.publish(actions, menus);
+ wait_msec();
+
+ /***
+ **** Set up the proxy
+ ***/
+
+ auto on_proxy_ready = [](GObject*, GAsyncResult* res, gpointer gproxy){
+ GError* error = nullptr;
+ *reinterpret_cast<DatetimeAlarmProperties**>(gproxy) = datetime_alarm_properties_proxy_new_for_bus_finish(res, &error);
+ EXPECT_TRUE(error == nullptr);
+ };
+
+ DatetimeAlarmProperties* proxy = nullptr;
+ datetime_alarm_properties_proxy_new_for_bus(G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ BUS_NAME,
+ BUS_PATH"/AlarmProperties",
+ nullptr,
+ on_proxy_ready,
+ &proxy);
+ wait_msec(100);
+ ASSERT_TRUE(proxy != nullptr);
+
+ /***
+ **** Try changing the Settings -- do the DBus properties change to match it?
+ ***/
+
+ auto expected_volume = ALARM_VOLUME_VERY_LOUD;
+ int expected_duration = 60;
+ const char * expected_sound = "/tmp/foo.wav";
+ settings->alarm_volume.set(expected_volume);
+ settings->alarm_duration.set(expected_duration);
+ settings->alarm_sound.set(expected_sound);
+ wait_msec();
+
+ static constexpr const char* const SOUND_PROP {"default-sound"};
+ static constexpr const char* const VOLUME_PROP {"default-volume"};
+ static constexpr const char* const DURATION_PROP {"duration"};
+
+ char* sound = nullptr;
+ int volume = -1;
+ int duration = -1;
+ g_object_get(proxy, SOUND_PROP, &sound,
+ VOLUME_PROP, &volume,
+ DURATION_PROP, &duration,
+ nullptr);
+ EXPECT_STREQ(expected_sound, sound);
+ EXPECT_EQ(expected_volume, volume);
+ EXPECT_EQ(expected_duration, duration);
+
+ /***
+ **** Try chaning the DBus properties -- do the Settings change to match it?
+ ***/
+
+ expected_volume = ALARM_VOLUME_VERY_QUIET;
+ expected_duration = 30;
+ expected_sound = "/tmp/bar.wav";
+ g_object_set(proxy, SOUND_PROP, expected_sound,
+ VOLUME_PROP, expected_volume,
+ DURATION_PROP, expected_duration,
+ nullptr);
+ wait_msec();
+
+ EXPECT_STREQ(expected_sound, settings->alarm_sound.get().c_str());
+ EXPECT_EQ(expected_volume, settings->alarm_volume.get());
+ EXPECT_EQ(expected_duration, settings->alarm_duration.get());
+
+ // cleanup
+ g_clear_object(&proxy);
+}