ecore: add system modules, implement 'systemd'.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Thu, 8 Aug 2013 23:32:53 +0000 (20:32 -0300)
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Fri, 9 Aug 2013 17:28:02 +0000 (14:28 -0300)
Ecore will now load "system modules" on ecore_init(). The "systemd"
module will use DBus to monitor localed, hostnamed and timedated and
add system events related to those changes.

configure.ac
data/Makefile.am
data/ecore/checkme [new file with mode: 0644]
pc/ecore.pc.in
src/Makefile_Ecore.am
src/lib/ecore/ecore.c
src/modules/ecore/system/systemd/ecore_system_systemd.c [new file with mode: 0644]

index 0d4f96b..1a01978 100644 (file)
@@ -549,6 +549,8 @@ AC_ARG_ENABLE([systemd],
     fi
    ],
    [want_systemd="no"])
+AM_CONDITIONAL([WANT_SYSTEMD], [test "${want_systemd}" = "yes"])
+
 
 #### Platform-dependent
 DL_LIBS=""
index e6926e5..5cd88de 100644 (file)
@@ -22,6 +22,12 @@ eezefiles_DATA = eeze/checkme
 EXTRA_DIST += $(eezefiles_DATA)
 
 ########################################################################
+# Ecore
+ecorefilesdir = $(datadir)/ecore
+ecorefiles_DATA = ecore/checkme
+EXTRA_DIST += $(ecorefiles_DATA)
+
+########################################################################
 # Ecore_Imf
 ecoreimffilesdir = $(datadir)/ecore_imf
 ecoreimffiles_DATA = ecore_imf/checkme
diff --git a/data/ecore/checkme b/data/ecore/checkme
new file mode 100644 (file)
index 0000000..1688a66
--- /dev/null
@@ -0,0 +1 @@
+This is just a test file used to help ecore determine its prefix location.
index 2f0de2a..ab7004a 100644 (file)
@@ -2,6 +2,8 @@ prefix=@prefix@
 exec_prefix=@exec_prefix@
 libdir=@libdir@
 includedir=@includedir@
+modules=@libdir@/ecore
+module_arch=@MODULE_ARCH@
 
 Name: ecore
 Description: Ecore event abstraction library
index 40329a0..5e6515b 100644 (file)
@@ -52,11 +52,41 @@ lib_ecore_libecore_la_SOURCES += lib/ecore/ecore_signal.c lib/ecore/ecore_exe.c
 endif
 endif
 
-lib_ecore_libecore_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_CFLAGS@
+lib_ecore_libecore_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \
+-DPACKAGE_BIN_DIR=\"$(bindir)\" \
+-DPACKAGE_LIB_DIR=\"$(libdir)\" \
+-DPACKAGE_DATA_DIR=\"$(datadir)/ecore\" \
+-DPACKAGE_BUILD_DIR=\"`pwd`/$(top_builddir)\" \
+@ECORE_CFLAGS@
 lib_ecore_libecore_la_LIBADD = @ECORE_LIBS@
 lib_ecore_libecore_la_DEPENDENCIES = @ECORE_INTERNAL_LIBS@
 lib_ecore_libecore_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@
 
+
+### Modules
+
+# systemd
+
+if WANT_SYSTEMD
+ecoresystemdpkgdir = $(libdir)/ecore/system/systemd/$(MODULE_ARCH)
+ecoresystemdpkg_LTLIBRARIES = modules/ecore/system/systemd/module.la
+modules_ecore_system_systemd_module_la_SOURCES = \
+modules/ecore/system/systemd/ecore_system_systemd.c
+modules_ecore_system_systemd_module_la_CPPFLAGS = \
+-I$(top_builddir)/src/lib/efl \
+@ECORE_CFLAGS@ \
+@ELDBUS_CFLAGS@
+modules_ecore_system_systemd_module_la_LIBADD = \
+@USE_ECORE_LIBS@ \
+@USE_ELDBUS_LIBS@
+modules_ecore_system_systemd_module_la_DEPENDENCIES = \
+@USE_ECORE_INTERNAL_LIBS@ \
+@USE_ELDBUS_INTERNAL_LIBS@
+modules_ecore_system_systemd_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@
+modules_ecore_system_systemd_module_la_LIBTOOLFLAGS = --tag=disable-static
+endif
+
+
 ### Unit tests
 
 if EFL_ENABLE_TESTS
index 28726a2..489dc60 100644 (file)
@@ -116,6 +116,77 @@ int _ecore_main_lock_count;
 # define CODESET "INVALID"
 #endif
 
+static Eina_Prefix *_ecore_pfx = NULL;
+static Eina_Array *module_list = NULL;
+
+static void
+ecore_system_modules_load(void)
+{
+   char buf[PATH_MAX] = "";
+   char *path;
+
+   if (getenv("EFL_RUN_IN_TREE"))
+     {
+        struct stat st;
+        snprintf(buf, sizeof(buf), "%s/src/modules/ecore/system",
+                 PACKAGE_BUILD_DIR);
+        if (stat(buf, &st) == 0)
+          {
+             const char *built_modules[] = {
+#ifdef HAVE_SYSTEMD
+               "systemd",
+#endif
+               NULL
+             };
+             const char **itr;
+             for (itr = built_modules; *itr != NULL; itr++)
+               {
+                  snprintf(buf, sizeof(buf),
+                           "%s/src/modules/ecore/system/%s/.libs",
+                           PACKAGE_BUILD_DIR, *itr);
+                  module_list = eina_module_list_get(module_list, buf,
+                                                     EINA_FALSE, NULL, NULL);
+               }
+
+             if (module_list)
+               eina_module_list_load(module_list);
+             return;
+          }
+     }
+
+   path = eina_module_environment_path_get("ECORE_MODULES_DIR",
+                                           "/ecore/system");
+   if (path)
+     {
+        module_list = eina_module_arch_list_get(module_list, path, MODULE_ARCH);
+        free(path);
+     }
+
+   path = eina_module_environment_path_get("HOME", "/.ecore/system");
+   if (path)
+     {
+        module_list = eina_module_arch_list_get(module_list, path, MODULE_ARCH);
+        free(path);
+     }
+
+   snprintf(buf, sizeof(buf), "%s/ecore/system",
+            eina_prefix_lib_get(_ecore_pfx));
+   module_list = eina_module_arch_list_get(module_list, buf, MODULE_ARCH);
+
+   eina_module_list_load(module_list);
+}
+
+static void
+ecore_system_modules_unload(void)
+{
+   if (module_list)
+     {
+        eina_module_list_free(module_list);
+        eina_array_free(module_list);
+        module_list = NULL;
+     }
+}
+
 /**
  * @addtogroup Ecore_Init_Group
  *
@@ -170,6 +241,16 @@ ecore_init(void)
         goto shutdown_log_dom;
      }
 
+   _ecore_pfx = eina_prefix_new(NULL, ecore_init,
+                                "ECORE", "ecore", "checkme",
+                                PACKAGE_BIN_DIR, PACKAGE_LIB_DIR,
+                                PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
+   if (!_ecore_pfx)
+     {
+        ERR("Could not get ecore installation prefix");
+        goto shutdown_log_dom;
+     }
+
    eo_init();
 
    if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1;
@@ -230,6 +311,9 @@ ecore_init(void)
                   EINA_LOG_STATE_STOP,
                   EINA_LOG_STATE_INIT);
 
+
+   ecore_system_modules_load();
+
    return _ecore_init_count;
 
 shutdown_mempool:
@@ -273,6 +357,8 @@ ecore_shutdown(void)
      if (--_ecore_init_count != 0)
        goto unlock;
 
+     ecore_system_modules_unload();
+
      eina_log_timing(_ecore_log_dom,
                     EINA_LOG_STATE_START,
                     EINA_LOG_STATE_SHUTDOWN);
@@ -345,6 +431,10 @@ ecore_shutdown(void)
      ecore_mempool_shutdown();
      eina_log_domain_unregister(_ecore_log_dom);
      _ecore_log_dom = -1;
+
+     eina_prefix_free(_ecore_pfx);
+     _ecore_pfx = NULL;
+
      eina_shutdown();
 #ifdef HAVE_EVIL
      evil_shutdown();
diff --git a/src/modules/ecore/system/systemd/ecore_system_systemd.c b/src/modules/ecore/system/systemd/ecore_system_systemd.c
new file mode 100644 (file)
index 0000000..0943775
--- /dev/null
@@ -0,0 +1,354 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Eldbus.h>
+#include <Ecore.h>
+#include <locale.h>
+
+static int _log_dom = -1;
+static Eldbus_Connection *_conn = NULL;
+
+static Eina_List *_objs = NULL;
+static Eina_List *_proxies = NULL;
+
+#ifdef CRITICAL
+#undef CRITICAL
+#endif
+#define CRITICAL(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__)
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
+
+#ifdef WRN
+#undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
+
+
+static void
+_props_changed_hostname(void *data EINA_UNUSED, const Eldbus_Message *msg)
+{
+   Eldbus_Message_Iter *changed, *entry, *invalidated;
+   const char *iface, *prop;
+
+   if (!eldbus_message_arguments_get(msg, "sa{sv}as",
+                                     &iface, &changed, &invalidated))
+     {
+        ERR("Error getting data from properties changed signal.");
+        return;
+     }
+
+   while (eldbus_message_iter_get_and_next(changed, 'e', &entry))
+     {
+        const void *key;
+        Eldbus_Message_Iter *var;
+        if (!eldbus_message_iter_arguments_get(entry, "sv", &key, &var))
+          continue;
+        if (strcmp(key, "Hostname") == 0)
+          goto changed_hostname;
+     }
+
+   while (eldbus_message_iter_get_and_next(invalidated, 's', &prop))
+     {
+        if (strcmp(prop, "Hostname") == 0)
+          goto changed_hostname;
+     }
+
+   return;
+
+ changed_hostname:
+   ecore_event_add(ECORE_EVENT_HOSTNAME_CHANGED, NULL, NULL, NULL);
+}
+
+static void
+_props_changed_timedate(void *data EINA_UNUSED, const Eldbus_Message *msg)
+{
+   Eldbus_Message_Iter *changed, *entry, *invalidated;
+   const char *iface, *prop;
+
+   if (!eldbus_message_arguments_get(msg, "sa{sv}as",
+                                     &iface, &changed, &invalidated))
+     {
+        ERR("Error getting data from properties changed signal.");
+        return;
+     }
+
+   while (eldbus_message_iter_get_and_next(changed, 'e', &entry))
+     {
+        const void *key;
+        Eldbus_Message_Iter *var;
+        if (!eldbus_message_iter_arguments_get(entry, "sv", &key, &var))
+          continue;
+        if (strcmp(key, "Timezone") == 0)
+          goto changed_timedate;
+     }
+
+   while (eldbus_message_iter_get_and_next(invalidated, 's', &prop))
+     {
+        if (strcmp(prop, "Timezone") == 0)
+          goto changed_timedate;
+     }
+
+   return;
+
+ changed_timedate:
+   ecore_event_add(ECORE_EVENT_SYSTEM_TIMEDATE_CHANGED, NULL, NULL, NULL);
+}
+
+struct locale_cat_desc {
+   int cat;
+   int namelen;
+   const char *name;
+};
+
+static const struct locale_cat_desc locale_cat_desc[] = {
+#define CAT(name) {name, sizeof(#name) - 1, #name}
+   CAT(LC_CTYPE),
+   CAT(LC_NUMERIC),
+   CAT(LC_TIME),
+   CAT(LC_COLLATE),
+   CAT(LC_MONETARY),
+   CAT(LC_MESSAGES),
+   CAT(LC_ALL),
+   CAT(LC_PAPER),
+   CAT(LC_NAME),
+   CAT(LC_ADDRESS),
+   CAT(LC_TELEPHONE),
+   CAT(LC_MEASUREMENT),
+   CAT(LC_IDENTIFICATION),
+#undef CAT
+   {-1, -1, NULL}
+};
+
+static int _locale_parse(const char *str, int *cat, const char **value)
+{
+   const struct locale_cat_desc *itr;
+   const char *p = strchr(str, '=');
+   int klen;
+
+   if (!p) goto end;
+
+   klen = p - str;
+   for (itr = locale_cat_desc; itr->name != NULL; itr++)
+     {
+        if ((klen == itr->namelen) && (memcmp(str, itr->name, klen) == 0))
+          {
+             *cat = itr->cat;
+             *value = str + itr->namelen + 1;
+             return itr - locale_cat_desc;
+          }
+     }
+
+ end:
+   *cat = -1;
+   *value = NULL;
+   return -1;
+}
+
+static void _locale_get(void *data EINA_UNUSED, const Eldbus_Message *msg,
+                        Eldbus_Pending *pending EINA_UNUSED)
+{
+   Eldbus_Message_Iter *variant, *array;
+   const char *errname, *errmsg, *val;
+   Eina_Bool setlocs[EINA_C_ARRAY_LENGTH(locale_cat_desc)];
+   unsigned int i;
+
+   if (eldbus_message_error_get(msg, &errname, &errmsg))
+     {
+        ERR("Message error %s - %s", errname, errmsg);
+        goto end;
+     }
+   if (!eldbus_message_arguments_get(msg, "v", &variant))
+     {
+        ERR("Error getting arguments.");
+        goto end;
+     }
+
+   if (!eldbus_message_iter_get_and_next(variant, 'a', &array))
+     {
+        ERR("Error getting array.");
+        goto end;
+     }
+
+   memset(setlocs, 0, sizeof(setlocs));
+   while (eldbus_message_iter_get_and_next(array, 's', &val))
+     {
+        int cat, idx;
+        const char *value;
+        idx = _locale_parse(val, &cat, &value);
+        if (idx >= 0)
+          setlocs[idx] = EINA_TRUE;
+        setlocale(cat, value);
+     }
+
+   for (i = 0; i < EINA_C_ARRAY_LENGTH(locale_cat_desc); i++)
+     {
+        if ((!setlocs[i]) && (locale_cat_desc[i].cat != LC_ALL))
+          setlocale(locale_cat_desc[i].cat, "C");
+     }
+
+ end:
+   ecore_event_add(ECORE_EVENT_LOCALE_CHANGED, NULL, NULL, NULL);
+}
+
+static void
+_props_changed_locale(void *data, const Eldbus_Message *msg)
+{
+   Eldbus_Proxy *proxy = data;
+   Eldbus_Message_Iter *changed, *entry, *invalidated;
+   const char *iface, *prop;
+
+   if (!eldbus_message_arguments_get(msg, "sa{sv}as",
+                                     &iface, &changed, &invalidated))
+     {
+        ERR("Error getting data from properties changed signal.");
+        return;
+     }
+
+   while (eldbus_message_iter_get_and_next(changed, 'e', &entry))
+     {
+        const void *key;
+        Eldbus_Message_Iter *var;
+        if (!eldbus_message_iter_arguments_get(entry, "sv", &key, &var))
+          continue;
+        if (strcmp(key, "Locale") == 0)
+          goto changed_locale;
+     }
+
+   while (eldbus_message_iter_get_and_next(invalidated, 's', &prop))
+     {
+        if (strcmp(prop, "Locale") == 0)
+          goto changed_locale;
+     }
+
+   return;
+
+ changed_locale:
+   eldbus_proxy_property_get(proxy, "Locale", _locale_get, NULL);
+}
+
+static Eina_Bool
+_property_change_monitor(const char *name,
+                         const char *path,
+                         const char *iface,
+                         Eldbus_Signal_Cb cb)
+{
+   Eldbus_Object *o;
+   Eldbus_Proxy *p;
+   Eldbus_Signal_Handler *s;
+
+   o = eldbus_object_get(_conn, name, path);
+   if (!o)
+     {
+        ERR("could not get object name=%s, path=%s", name, path);
+        return EINA_FALSE;
+     }
+
+   p = eldbus_proxy_get(o, iface);
+   if (!p)
+     {
+        ERR("could not get proxy interface=%s, name=%s, path=%s",
+            iface, name, path);
+        eldbus_object_unref(o);
+        return EINA_FALSE;
+     }
+
+   s = eldbus_proxy_properties_changed_callback_add(p, cb, p);
+   if (!s)
+     {
+        ERR("could not add signal handler for properties changed for proxy "
+            "interface=%s, name=%s, path=%s", iface, name, path);
+        eldbus_proxy_unref(p);
+        eldbus_object_unref(o);
+        return EINA_FALSE;
+     }
+
+   _objs = eina_list_append(_objs, o);
+   _proxies = eina_list_append(_proxies, p);
+   return EINA_TRUE;
+}
+
+static void _ecore_system_systemd_shutdown(void);
+
+static Eina_Bool
+_ecore_system_systemd_init(void)
+{
+   eldbus_init();
+
+   _log_dom = eina_log_domain_register("ecore_system_systemd", NULL);
+   if (_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: ecore_system_systemd");
+        goto error;
+     }
+
+   _conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM);
+
+   if (!_property_change_monitor("org.freedesktop.hostname1",
+                                 "/org/freedesktop/hostname1",
+                                 "org.freedesktop.hostname1",
+                                 _props_changed_hostname))
+     goto error;
+
+   if (!_property_change_monitor("org.freedesktop.timedate1",
+                                 "/org/freedesktop/timedate1",
+                                 "org.freedesktop.timedate1",
+                                 _props_changed_timedate))
+     goto error;
+
+   if (!_property_change_monitor("org.freedesktop.locale1",
+                                 "/org/freedesktop/locale1",
+                                 "org.freedesktop.locale1",
+                                 _props_changed_locale))
+     goto error;
+
+   DBG("ecore system 'systemd' loaded");
+   return EINA_TRUE;
+
+ error:
+   _ecore_system_systemd_shutdown();
+   return EINA_FALSE;
+}
+
+static void
+_ecore_system_systemd_shutdown(void)
+{
+   DBG("ecore system 'systemd' unloaded");
+
+   while (_proxies)
+     {
+        eldbus_proxy_unref(_proxies->data);
+        _proxies = eina_list_remove_list(_proxies, _proxies);
+     }
+
+   while (_objs)
+     {
+        eldbus_object_unref(_objs->data);
+        _objs = eina_list_remove_list(_objs, _objs);
+     }
+
+   if (_conn)
+     {
+        eldbus_connection_unref(_conn);
+        _conn = NULL;
+     }
+
+   if (_log_dom > 0)
+     {
+        eina_log_domain_unregister(_log_dom);
+        _log_dom = -1;
+     }
+
+   eldbus_shutdown();
+}
+
+EINA_MODULE_INIT(_ecore_system_systemd_init);
+EINA_MODULE_SHUTDOWN(_ecore_system_systemd_shutdown);