devilhorns pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=ed3a1f39587187c8acf305fd793f92218995c486
commit ed3a1f39587187c8acf305fd793f92218995c486 Author: Chris Michael <cpmich...@osg.samsung.com> Date: Thu Mar 31 12:34:32 2016 -0400 elput: Add input manager interface and APIs to connect & disconnect This commit adds the start of the Elput Manager & Interface code. This will be used as an inteface to various backend methods of session & device control (ie: systemd, direct interface, etc). This will provide various abstractions for working with libinput when opening/closing input devices. Signed-off-by: Chris Michael <cpmich...@osg.samsung.com> --- src/Makefile_Elput.am | 2 + src/lib/elput/Elput.h | 36 ++++ src/lib/elput/elput_logind.c | 450 ++++++++++++++++++++++++++++++++++++++++++ src/lib/elput/elput_manager.c | 39 ++++ src/lib/elput/elput_private.h | 32 +++ 5 files changed, 559 insertions(+) diff --git a/src/Makefile_Elput.am b/src/Makefile_Elput.am index 851d4ee..3e1ed58 100644 --- a/src/Makefile_Elput.am +++ b/src/Makefile_Elput.am @@ -9,6 +9,8 @@ dist_installed_elputmainheaders_DATA = \ lib/elput/Elput.h lib_elput_libelput_la_SOURCES = \ +lib/elput/elput_logind.c \ +lib/elput/elput_manager.c \ lib/elput/elput.c \ lib/elput/elput_private.h diff --git a/src/lib/elput/Elput.h b/src/lib/elput/Elput.h index 7c88e4b..e098b13 100644 --- a/src/lib/elput/Elput.h +++ b/src/lib/elput/Elput.h @@ -25,6 +25,9 @@ # ifdef EFL_BETA_API_SUPPORT +/* opaque structure to represent an input manager */ +typedef struct _Elput_Manager Elput_Manager; + /** * @file * @brief Ecore functions for dealing with libinput @@ -35,6 +38,7 @@ * Elput provides a wrapper and functions for using libinput * * @li @ref Elput_Init_Group + * @li @ref Elput_Manager_Group * */ @@ -66,6 +70,38 @@ EAPI int elput_init(void); */ EAPI int elput_shutdown(void); +/** + * @defgroup Elput_Manager_Group + * + * Functions that deal with connecting, disconnecting, opening, closing + * of input devices. + * + */ + +/** + * Create an input manager on the specified seat + * + * @param seat + * @param tty + * @param sync + * + * @return A Elput_Manager on success, NULL on failure + * + * @ingroup Elput_Manager_Group + * @since 1.18 + */ +EAPI Elput_Manager *elput_manager_connect(const char *seat, unsigned int tty, Eina_Bool sync); + +/** + * Disconnect an input manager + * + * @param manager + * + * @ingroup Elput_Manager_Group + * @since 1.18 + */ +EAPI void elput_manager_disconnect(Elput_Manager *manager); + # endif # undef EAPI diff --git a/src/lib/elput/elput_logind.c b/src/lib/elput/elput_logind.c new file mode 100644 index 0000000..d649bf3 --- /dev/null +++ b/src/lib/elput/elput_logind.c @@ -0,0 +1,450 @@ +#include "elput_private.h" + +#ifdef HAVE_SYSTEMD + +static void +_logind_device_pause_complete(Elput_Manager *em, uint32_t major, uint32_t minor) +{ + Eldbus_Proxy *proxy; + Eldbus_Message *msg; + + proxy = + eldbus_proxy_get(em->dbus.obj, "org.freedesktop.login1.Session"); + if (!proxy) + { + ERR("Could not get proxy for session"); + return; + } + + msg = eldbus_proxy_method_call_new(proxy, "PauseDeviceComplete"); + if (!msg) + { + ERR("Could not create method call for proxy"); + goto end; + } + + eldbus_message_arguments_append(msg, "uu", major, minor); + + eldbus_proxy_send(proxy, msg, NULL, NULL, -1); + +end: + eldbus_message_unref(msg); + eldbus_proxy_unref(proxy); +} + +static void +_cb_session_removed(void *data, const Eldbus_Message *msg) +{ + Elput_Manager *em; + const char *errname, *errmsg; + const char *sid; + + em = data; + + if (eldbus_message_error_get(msg, &errname, &errmsg)) + { + ERR("Eldbus Message Error: %s %s", errname, errmsg); + return; + } + + if (eldbus_message_arguments_get(msg, "s", &sid)) + { + if (!strcmp(sid, em->sid)) + { + WRN("Logind session removed"); + /* TODO: call manager restore function */ + } + } +} + +static void +_cb_device_paused(void *data, const Eldbus_Message *msg) +{ + Elput_Manager *em; + const char *errname, *errmsg; + const char *type; + uint32_t maj, min; + + em = data; + + if (eldbus_message_error_get(msg, &errname, &errmsg)) + { + ERR("Eldbus Message Error: %s %s", errname, errmsg); + return; + } + + if (eldbus_message_arguments_get(msg, "uus", &maj, &min, &type)) + { + if (!strcmp(type, "pause")) + _logind_device_pause_complete(em, maj, min); + + /* TODO */ + /* if ((em->sync) && (maj == DRM_MAJOR)) */ + /* _ecore_drm2_launcher_activate_send(em, EINA_FALSE); */ + } +} + +static void +_cb_device_resumed(void *data, const Eldbus_Message *msg) +{ + Elput_Manager *em; + const char *errname, *errmsg; + uint32_t maj, min; + int fd; + + em = data; + + if (eldbus_message_error_get(msg, &errname, &errmsg)) + { + ERR("Eldbus Message Error: %s %s", errname, errmsg); + return; + } + + if (eldbus_message_arguments_get(msg, "uuh", &maj, &min, &fd)) + { + /* TODO */ + /* if ((em->sync) && (maj == DRM_MAJOR)) */ + /* _ecore_drm2_launcher_activate_send(em, EINA_TRUE); */ + } +} + +static void +_cb_property_changed(void *data, Eldbus_Proxy *proxy EINA_UNUSED, void *event) +{ + Elput_Manager *em; + Eldbus_Proxy_Event_Property_Changed *ev; + Eina_Bool active = EINA_FALSE; + + em = data; + ev = event; + + DBG("DBus Property Changed: %s", ev->name); + + if (!strcmp(ev->name, "Active")) + { + eina_value_get(ev->value, &active); + /* TODO */ + /* if ((!em->sync) || (!active)) */ + /* _ecore_drm2_launcher_activate_send(em, active); */ + } +} + +static Eina_Bool +_logind_session_vt_get(const char *sid, unsigned int *vt) +{ +# ifdef HAVE_SYSTEMD_LOGIN_209 + return (sd_session_get_vt(sid, vt) >= 0); +# else + int ret = 0; + char *tty; + + ret = sd_session_get_tty(sid, &tty); + if (ret < 0) return ret; + + ret = sscanf(tty, "tty%u", vt); + free(tty); + + if (ret != 1) return EINA_FALSE; + return EINA_TRUE; +# endif +} + +static Eina_Bool +_logind_dbus_open(Eldbus_Connection **conn) +{ + if (!eldbus_init()) return EINA_FALSE; + + *conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM); + if (!*conn) return EINA_FALSE; + + return EINA_TRUE; +} + +static void +_logind_dbus_close(Eldbus_Connection *conn) +{ + if (conn) eldbus_connection_unref(conn); + eldbus_shutdown(); +} + +static Eina_Bool +_logind_dbus_setup(Elput_Manager *em) +{ + Eldbus_Proxy *proxy; + int ret = 0; + + ret = asprintf(&em->dbus.path, + "/org/freedesktop/login1/session/%s", em->sid); + if (ret < 0) return EINA_FALSE; + + em->dbus.obj = + eldbus_object_get(em->dbus.conn, "org.freedesktop.login1", + em->dbus.path); + if (!em->dbus.obj) + { + ERR("Could not get dbus object"); + goto obj_err; + } + + proxy = + eldbus_proxy_get(em->dbus.obj, "org.freedesktop.login1.Manager"); + if (!proxy) + { + ERR("Could not get dbus proxy"); + goto proxy_err; + } + + eldbus_proxy_signal_handler_add(proxy, "SessionRemoved", + _cb_session_removed, em); + eldbus_proxy_unref(proxy); + + proxy = + eldbus_proxy_get(em->dbus.obj, "org.freedesktop.login1.Session"); + if (!proxy) + { + ERR("Could not get dbus proxy"); + goto proxy_err; + } + + eldbus_proxy_signal_handler_add(proxy, "PauseDevice", + _cb_device_paused, em); + eldbus_proxy_signal_handler_add(proxy, "ResumeDevice", + _cb_device_resumed, em); + eldbus_proxy_unref(proxy); + + proxy = + eldbus_proxy_get(em->dbus.obj, "org.freedesktop.DBus.Properties"); + if (!proxy) + { + ERR("Could not get dbus proxy"); + goto proxy_err; + } + + eldbus_proxy_properties_monitor(proxy, EINA_TRUE); + eldbus_proxy_event_callback_add(proxy, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED, + _cb_property_changed, em); + eldbus_proxy_unref(proxy); + + return EINA_TRUE; + +proxy_err: + eldbus_object_unref(em->dbus.obj); +obj_err: + free(em->dbus.path); + return EINA_FALSE; +} + +static Eina_Bool +_logind_control_take(Elput_Manager *em) +{ + Eldbus_Proxy *proxy; + Eldbus_Message *msg, *reply; + const char *errname, *errmsg; + + proxy = + eldbus_proxy_get(em->dbus.obj, "org.freedesktop.login1.Session"); + if (!proxy) + { + ERR("Could not get proxy for session"); + return EINA_FALSE; + } + + msg = eldbus_proxy_method_call_new(proxy, "TakeControl"); + if (!msg) + { + ERR("Could not create method call for proxy"); + goto msg_err; + } + + eldbus_message_arguments_append(msg, "b", EINA_FALSE); + + reply = eldbus_proxy_send_and_block(proxy, msg, -1); + if (eldbus_message_error_get(reply, &errname, &errmsg)) + { + ERR("Eldbus Message Error: %s %s", errname, errmsg); + goto msg_err; + } + + eldbus_message_unref(reply); + eldbus_proxy_unref(proxy); + + return EINA_TRUE; + +msg_err: + eldbus_proxy_unref(proxy); + return EINA_FALSE; +} + +static void +_logind_control_release(Elput_Manager *em) +{ + Eldbus_Proxy *proxy; + Eldbus_Message *msg; + + proxy = + eldbus_proxy_get(em->dbus.obj, "org.freedesktop.login1.Session"); + if (!proxy) + { + ERR("Could not get proxy for session"); + return; + } + + msg = eldbus_proxy_method_call_new(proxy, "ReleaseControl"); + if (!msg) + { + ERR("Could not create method call for proxy"); + goto end; + } + + eldbus_proxy_send(proxy, msg, NULL, NULL, -1); + +end: + eldbus_proxy_unref(proxy); +} + +static Eina_Bool +_logind_activate(Elput_Manager *em) +{ + Eldbus_Proxy *proxy; + Eldbus_Message *msg; + + proxy = + eldbus_proxy_get(em->dbus.obj, "org.freedesktop.login1.Session"); + if (!proxy) + { + ERR("Could not get proxy for session"); + return EINA_FALSE; + } + + msg = eldbus_proxy_method_call_new(proxy, "Activate"); + if (!msg) + { + ERR("Could not create method call for proxy"); + goto msg_err; + } + + eldbus_proxy_send(proxy, msg, NULL, NULL, -1); + + eldbus_proxy_unref(proxy); + + return EINA_TRUE; + +msg_err: + eldbus_proxy_unref(proxy); + return EINA_FALSE; +} + +static Eina_Bool +_logind_connect(Elput_Manager **manager, const char *seat, unsigned int tty, Eina_Bool sync) +{ + Elput_Manager *em; + int ret = 0; + char *s; + + em = calloc(1, sizeof(Elput_Manager)); + if (!em) return EINA_FALSE; + + em->interface = &_logind_interface; + em->sync = sync; + em->seat = eina_stringshare_add(seat); + + ret = sd_pid_get_session(getpid(), &em->sid); + if (ret < 0) + { + ERR("Could not get systemd session"); + goto session_err; + } + + ret = sd_session_get_seat(em->sid, &s); + if (ret < 0) + { + ERR("Failed to get session seat"); + free(s); + goto seat_err; + } + else if ((seat) && (strcmp(seat, s))) + { + ERR("Seat '%s' differs from session seat '%s'", seat, s); + free(s); + goto seat_err; + } + + if (!_logind_session_vt_get(em->sid, &em->vt_num)) + { + ERR("Could not get session vt"); + goto vt_err; + } + else if ((tty > 0) && (em->vt_num != tty)) + { + ERR("Requested VT %u differs from session VT %u", tty, em->vt_num); + goto vt_err; + } + + free(s); + + if (!_logind_dbus_open(&em->dbus.conn)) + { + ERR("Could not connect to dbus"); + goto vt_err; + } + + if (!_logind_dbus_setup(em)) + { + ERR("Could not setup dbus"); + goto dbus_err; + } + + if (!_logind_control_take(em)) + { + ERR("Could not take control of session"); + goto ctrl_err; + } + + if (!_logind_activate(em)) + { + ERR("Could not activate session"); + goto actv_err; + } + + *(Elput_Manager **)manager = em; + + return EINA_TRUE; + +actv_err: + _logind_control_release(em); +ctrl_err: + eldbus_object_unref(em->dbus.obj); + free(em->dbus.path); +dbus_err: + _logind_dbus_close(em->dbus.conn); +vt_err: +seat_err: + free(em->sid); +session_err: + free(em); + return EINA_FALSE; +} + +static void +_logind_disconnect(Elput_Manager *em) +{ + _logind_control_release(em); + eldbus_object_unref(em->dbus.obj); + free(em->dbus.path); + _logind_dbus_close(em->dbus.conn); + eina_stringshare_del(em->seat); + free(em->sid); + free(em); +} + +Elput_Interface _logind_interface = +{ + _logind_connect, + _logind_disconnect, + NULL, + NULL, + NULL, + NULL, +}; + +#endif diff --git a/src/lib/elput/elput_manager.c b/src/lib/elput/elput_manager.c new file mode 100644 index 0000000..2073ff7 --- /dev/null +++ b/src/lib/elput/elput_manager.c @@ -0,0 +1,39 @@ +#include "elput_private.h" + +static Elput_Interface *_ifaces[] = +{ +#ifdef HAVE_SYSTEMD + &_logind_interface, +#endif + NULL, // launcher + NULL, // direct + NULL, +}; + +EAPI Elput_Manager * +elput_manager_connect(const char *seat, unsigned int tty, Eina_Bool sync) +{ + Elput_Interface **it; + + for (it = _ifaces; *it != NULL; it++) + { + Elput_Interface *iface; + Elput_Manager *em; + + iface = *it; + if (iface->connect(&em, seat, tty, sync)) + return em; + } + + return NULL; +} + +EAPI void +elput_manager_disconnect(Elput_Manager *manager) +{ + EINA_SAFETY_ON_NULL_RETURN(manager); + EINA_SAFETY_ON_NULL_RETURN(manager->interface); + + if (manager->interface->disconnect) + manager->interface->disconnect(manager); +} diff --git a/src/lib/elput/elput_private.h b/src/lib/elput/elput_private.h index 62b7395..07e147b 100644 --- a/src/lib/elput/elput_private.h +++ b/src/lib/elput/elput_private.h @@ -12,6 +12,7 @@ # include "Eldbus.h" # include <Elput.h> +# include <unistd.h> # include <linux/vt.h> # include <linux/kd.h> # include <linux/major.h> @@ -54,4 +55,35 @@ extern int _elput_log_dom; # endif # define CRIT(...) EINA_LOG_DOM_CRIT(_elput_log_dom, __VA_ARGS__) +typedef struct _Elput_Interface +{ + Eina_Bool (*connect)(Elput_Manager **manager, const char *seat, unsigned int tty, Eina_Bool sync); + void (*disconnect)(Elput_Manager *manager); + int (*open)(Elput_Manager *manager, const char *path, int flags); + void (*close)(Elput_Manager *manager, int fd); + int (*activate)(Elput_Manager *manager, int vt); + void (*restore)(Elput_Manager *manager); +} Elput_Interface; + +struct _Elput_Manager +{ + Elput_Interface *interface; + + int fd; + char *sid; + const char *seat; + unsigned int vt_num; + + struct + { + char *path; + Eldbus_Object *obj; + Eldbus_Connection *conn; + } dbus; + + Eina_Bool sync : 1; +}; + +extern Elput_Interface _logind_interface; + #endif --