*/
#include "modes.h"
+#include <stdlib.h>
#include <glib.h>
#include "mdsc.h"
#include "common/dbus.h"
-struct mdsc_noti_data_s {
+typedef struct {
modes_noti_fn cb;
void *user_data;
-};
+} mdsc_noti_data_s;
static gulong mdsc_noti_signal_ID = 0;
-static struct mdsc_noti_data_s mdsc_noti_data;
+static GList *mdsc_noti_cb_list = NULL;
-static void _on_changed_mode(mdsDbus *mdsc_dbus, const char *mode, int state, gpointer user_data)
+static gint _compare_cb(gconstpointer a, gconstpointer b)
{
- //TODO:: should support multi callback
- //RET_IF(NULL == user_data);
+ RETV_IF(NULL == a, 1);
+ RETV_IF(NULL == b, 1);
+
+ const mdsc_noti_data_s *a_data = a;
+ const mdsc_noti_data_s *b_data = b;
+ if ((a_data->cb == b_data->cb)
+ && (a_data->user_data == b_data->user_data))
+ return 0;
+ return -1;
+}
- mdsc_noti_data.cb(mode, state, mdsc_noti_data.user_data);
+static void _on_changed_mode(mdsDbus *mdsc_dbus, const char *mode, int state, gpointer user_data)
+{
+ GList *it;
+ for (it = mdsc_noti_cb_list; it != NULL; it = g_list_next(it)) {
+ mdsc_noti_data_s *data = it->data;
+ if (data && data->cb)
+ data->cb(mode, state, data->user_data);
+ }
}
API int modes_subscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_data)
{
- RETV_IF(0 != mdsc_noti_signal_ID, MODES_ERROR_ALREADY);
RETV_IF(NULL == handle, MODES_ERROR_INVALID_PARAMETER);
RETV_IF(NULL == handle->conn, MODES_ERROR_INVALID_PARAMETER);
- mdsc_noti_data.cb = cb;
- mdsc_noti_data.user_data = user_data;
+ mdsc_noti_data_s search_data = { cb, user_data };
+ GList *found = g_list_find_custom(mdsc_noti_cb_list, &search_data, _compare_cb);
+ if (NULL != found) {
+ ERR("callback and user_data already exist in notification callback list");
+ return MODES_ERROR_ALREADY;
+ }
- mdsc_noti_signal_ID = g_signal_connect(handle->conn,
- "changed-mode",
- G_CALLBACK(_on_changed_mode),
- NULL);
+ mdsc_noti_data_s *data = malloc(sizeof(mdsc_noti_data_s));
+ if (NULL == data) {
+ ERR("malloc() Fail");
+ return MODES_ERROR_SYSTEM;
+ }
+
+ data->cb = cb;
+ data->user_data = user_data;
+
+ if (NULL == mdsc_noti_cb_list)
+ mdsc_noti_signal_ID = g_signal_connect(handle->conn,
+ "changed-mode",
+ G_CALLBACK(_on_changed_mode),
+ NULL);
+ mdsc_noti_cb_list = g_list_append(mdsc_noti_cb_list, data);
return MODES_ERROR_NONE;
}
-//TODO: multi callbacks
-API void modes_unsubscribe_mode_changes(modes_h handle)
+API void modes_unsubscribe_mode_changes(modes_h handle, modes_noti_fn cb, void *user_data)
{
RET_IF(0 == mdsc_noti_signal_ID);
RET_IF(NULL == handle);
RET_IF(NULL == handle->conn);
- g_signal_handler_disconnect(handle->conn, mdsc_noti_signal_ID);
- mdsc_noti_signal_ID = 0;
- mdsc_noti_data.cb = NULL;
- mdsc_noti_data.user_data = NULL;
+ mdsc_noti_data_s search = { cb, user_data };
+ GList *found = g_list_find_custom(mdsc_noti_cb_list, &search, _compare_cb);
+ if (NULL == found) {
+ WARN("g_list_find_custom() Fail");
+ return;
+ }
+
+ mdsc_noti_data_s *data = found->data;
+ mdsc_noti_cb_list = g_list_remove(mdsc_noti_cb_list, found->data);
+ free(data);
+ if (NULL == mdsc_noti_cb_list) {
+ g_signal_handler_disconnect(handle->conn, mdsc_noti_signal_ID);
+ mdsc_noti_signal_ID = 0;
+ }
+
}
int ret = modes_undo_mode(handle, (const char*)data);
EXPECT_EQ(MODES_ERROR_NONE, ret);
- return G_SOURCE_REMOVE;
+ return G_SOURCE_REMOVE;
}
static int notiFunc(const char *modeName, int state, void *user_data)
{
char *requestMode = (char*)user_data;
- std::cout << "Changed Mode : " << modeName << std::endl;
+ std::cout << "notiFunc Changed Mode : " << modeName << std::endl;
EXPECT_EQ(requestMode, std::string(modeName));
std::cout << "state : " << state << std::endl;
EXPECT_EQ(expectedState, state);
{
char *requestMode = (char*)user_data;
- std::cout << "Changed Mode : " << modeName << std::endl;
+ std::cout << "changeFn Changed Mode : " << modeName << std::endl;
EXPECT_EQ(requestMode, std::string(modeName));
std::cout << "state : " << state << std::endl;
return MODES_ERROR_NONE;
}
+
+ static int notiMultiFunc1(const char *modeName, int state, void *user_data)
+ {
+ std::cout << "notiMultiFunc1 Changed Mode : " << modeName << std::endl;
+ std::cout << "state : " << state << std::endl;
+
+ calledbit1 |= 0x1 << state;
+
+ return MODES_ERROR_NONE;
+ }
+
+ static int notiMultiFunc2(const char *modeName, int state, void *user_data)
+ {
+ std::cout << "notiMultiFunc2 Changed Mode : " << modeName << std::endl;
+ std::cout << "state : " << state << std::endl;
+
+ calledbit2 |= 0x1 << state;
+
+ return MODES_ERROR_NONE;
+ }
+
+ static int notiMultiFunc3(const char *modeName, int state, void *user_data)
+ {
+ std::cout << "notiMultiFunc3 Changed Mode : " << modeName << std::endl;
+ std::cout << "state : " << state << std::endl;
+
+ EXPECT_TRUE(NULL == user_data || notiTestMode == user_data);
+
+ if (NULL == user_data)
+ calledbit3 |= 0x1 << state;
+ if (notiTestMode == user_data)
+ calledbit4 |= 0x1 << state;
+
+ if (0x3 == calledbit3 && 0x3 == calledbit4)
+ g_main_loop_quit(loop);
+
+ return MODES_ERROR_NONE;
+ }
+
+
static modes_h handle;
static int expectedState;
static GMainLoop *loop;
+ static unsigned char calledbit1;
+ static unsigned char calledbit2;
+ static unsigned char calledbit3;
+ static unsigned char calledbit4;
+ static const char *notiTestMode;
};
modes_h ClientNotiTest::handle = NULL;
int ClientNotiTest::expectedState = 1;
+unsigned char ClientNotiTest::calledbit1 = 0;
+unsigned char ClientNotiTest::calledbit2 = 0;
+unsigned char ClientNotiTest::calledbit3 = 0;
+unsigned char ClientNotiTest::calledbit4 = 0;
GMainLoop *ClientNotiTest::loop = NULL;
+const char *ClientNotiTest::notiTestMode = "ex2";
TEST_F(ClientNotiTest, notiConnect)
{
g_main_loop_run(loop);
- modes_unsubscribe_mode_changes(handle);
+ modes_unsubscribe_mode_changes(handle, notiFunc, (void*)testMode);
+}
+TEST_F(ClientNotiTest, notiMultiCb)
+{
+ calledbit1 = 0;
+ calledbit2 = 0;
+ calledbit3 = 0;
+
+ int ret = modes_subscribe_mode_changes(handle, notiMultiFunc1, NULL);
+ EXPECT_EQ(MODES_ERROR_NONE, ret);
+
+ ret = modes_subscribe_mode_changes(handle, notiMultiFunc2, NULL);
+ EXPECT_EQ(MODES_ERROR_NONE, ret);
+
+ ret = modes_subscribe_mode_changes(handle, notiMultiFunc3, (void*)notiTestMode);
+ EXPECT_EQ(MODES_ERROR_NONE, ret);
+
+ ret = modes_subscribe_mode_changes(handle, notiMultiFunc3, NULL);
+ EXPECT_EQ(MODES_ERROR_NONE, ret);
+
+ ret = modes_apply_mode(handle, notiTestMode);
+ EXPECT_EQ(MODES_ERROR_NONE, ret);
+
+ g_timeout_add_seconds(1, undoTimeout, (void*)notiTestMode);
+ g_main_loop_run(loop);
+
+ modes_unsubscribe_mode_changes(handle, notiMultiFunc1, NULL);
+ modes_unsubscribe_mode_changes(handle, notiMultiFunc2, NULL);
+ modes_unsubscribe_mode_changes(handle, notiMultiFunc3, NULL);
+ modes_unsubscribe_mode_changes(handle, notiMultiFunc3, (void*)notiTestMode);
+
+ EXPECT_EQ(calledbit1, 1 << 0 | 1 << 1);
+ EXPECT_EQ(calledbit2, 1 << 0 | 1 << 1);
+ EXPECT_EQ(calledbit3, 1 << 0 | 1 << 1);
+ EXPECT_EQ(calledbit4, 1 << 0 | 1 << 1);
}
TEST_F(ClientNotiTest, essential)
g_main_loop_run(loop);
- modes_unsubscribe_mode_changes(handle);
+ modes_unsubscribe_mode_changes(handle, changeFn, (void*)testMode);
}