summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Blumenkrantz <zmike@osg.samsung.com>2016-05-24 16:11:20 -0400
committerMike Blumenkrantz <zmike@osg.samsung.com>2016-05-25 12:57:27 -0400
commit5f088b026d8f39aafc6b6e70fe3b04dff79b179e (patch)
tree06909671c2b23b105009d19608f7a7d7e108cf2a
parent33a5d44dcf36557b13aeba1088461504bae97373 (diff)
downloadefl-5f088b026d8f39aafc6b6e70fe3b04dff79b179e.tar.gz
elput: define and implement an async device opening interface for libinput
this adds an overly-complex method of removing blocking dbus calls from libinput's synchronous device initialization architecture. libinput was clearly never meant to be used in this way, but we're doing it anyway because we're efl. #SamsungFeatures
-rw-r--r--src/lib/elput/Elput.h3
-rw-r--r--src/lib/elput/elput_input.c191
-rw-r--r--src/lib/elput/elput_logind.c226
-rw-r--r--src/lib/elput/elput_manager.c8
-rw-r--r--src/lib/elput/elput_private.h16
5 files changed, 299 insertions, 145 deletions
diff --git a/src/lib/elput/Elput.h b/src/lib/elput/Elput.h
index 07ebfa2f97..2f311608a4 100644
--- a/src/lib/elput/Elput.h
+++ b/src/lib/elput/Elput.h
@@ -240,14 +240,13 @@ EAPI const Eina_List *elput_manager_seats_get(Elput_Manager *manager);
* Initialize input
*
* @param manager
- * @param seat
*
* @return EINA_TRUE on success, EINA_FALSE on failure
*
* @ingroup Elput_Input_Group
* @since 1.18
*/
-EAPI Eina_Bool elput_input_init(Elput_Manager *manager, const char *seat);
+EAPI Eina_Bool elput_input_init(Elput_Manager *manager);
/**
* Shutdown input
diff --git a/src/lib/elput/elput_input.c b/src/lib/elput/elput_input.c
index d49a2d0236..8431c290b5 100644
--- a/src/lib/elput/elput_input.c
+++ b/src/lib/elput/elput_input.c
@@ -1,12 +1,82 @@
#include "elput_private.h"
+#include <libudev.h>
+
+void
+_elput_input_window_update(Elput_Manager *manager)
+{
+ Eina_List *l, *ll;
+ Elput_Seat *seat;
+ Elput_Device *device;
+
+ if (manager->input.thread) return;
+ EINA_LIST_FOREACH(manager->input.seats, l, seat)
+ EINA_LIST_FOREACH(seat->devices, ll, device)
+ device->window = manager->window;
+}
+
+void
+_elput_input_pointer_max_update(Elput_Manager *manager)
+{
+ Eina_List *l;
+ Elput_Seat *eseat;
+
+ if (manager->input.thread) return;
+ EINA_LIST_FOREACH(manager->input.seats, l, eseat)
+ {
+ if (!eseat->ptr) continue;
+
+ eseat->ptr->maxw = manager->input.pointer_w;
+ eseat->ptr->maxh = manager->input.pointer_h;
+ }
+}
static int
_cb_open_restricted(const char *path, int flags, void *data)
{
- Elput_Manager *em;
-
- em = data;
- return elput_manager_open(em, path, flags);
+ Elput_Manager *em = data;
+ int ret = -1;
+ Elput_Async_Open *ao;
+ int p[2];
+
+ if (!em->input.thread)
+ return em->interface->open(em, path, flags);
+ if (!em->interface->open_async) return ret;
+ ao = calloc(1, sizeof(Elput_Async_Open));
+ if (!ao) return ret;
+ if (pipe2(p, O_CLOEXEC) < 0)
+ {
+ free(ao);
+ return ret;
+ }
+ ao->manager = em;
+ ao->path = strdup(path);
+ ao->flags = flags;
+ em->input.pipe = p[1];
+ ecore_thread_feedback(em->input.thread, ao);
+ while (!ecore_thread_check(em->input.thread))
+ {
+ int avail, fd;
+ fd_set rfds, wfds, exfds;
+ struct timeval tv, *t;
+
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ FD_ZERO(&exfds);
+ FD_SET(p[0], &rfds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 300;
+ t = &tv;
+ avail = select(p[0] + 1, &rfds, &wfds, &exfds, t);
+ if (avail > 0)
+ {
+ read(p[0], &fd, sizeof(int));
+ ret = fd;
+ break;
+ }
+ if (avail < 0) break;
+ }
+ close(p[0]);
+ return ret;
}
static void
@@ -209,52 +279,91 @@ _cb_input_dispatch(void *data, Ecore_Fd_Handler *hdlr EINA_UNUSED)
return EINA_TRUE;
}
-EAPI Eina_Bool
-elput_input_init(Elput_Manager *manager, const char *seat)
+static void
+_elput_input_init_cancel(void *data, Ecore_Thread *eth EINA_UNUSED)
{
- int fd;
-
- EINA_SAFETY_ON_NULL_RETURN_VAL(manager, EINA_FALSE);
+ Elput_Manager *manager = data;
- memset(&manager->input, 0, sizeof(Elput_Input));
-
- manager->input.lib =
- libinput_udev_create_context(&_input_interface, manager, eeze_udev_get());
- if (!manager->input.lib)
+ manager->input.thread = NULL;
+ if (manager->input.current_pending)
{
- ERR("libinput could not create udev context");
- goto udev_err;
+ eldbus_pending_cancel(manager->input.current_pending);
+ if (manager->input.pipe >= 0)
+ close(manager->input.pipe);
}
+ if (manager->del)
+ elput_manager_disconnect(manager);
+}
- /* if not seat name is passed in, just use default seat name */
- if (!seat) seat = "seat0";
+static void
+_elput_input_init_end(void *data, Ecore_Thread *eth EINA_UNUSED)
+{
+ Elput_Manager *manager = data;
- if (libinput_udev_assign_seat(manager->input.lib, seat) != 0)
+ manager->input.thread = NULL;
+ if (!manager->input.lib) return;
+ manager->input.hdlr =
+ ecore_main_fd_handler_add(libinput_get_fd(manager->input.lib), ECORE_FD_READ,
+ _cb_input_dispatch, &manager->input, NULL, NULL);
+
+ if (manager->input.hdlr)
{
- ERR("libinput could not assign udev seat");
- goto seat_err;
+ _process_events(&manager->input);
+ _elput_input_window_update(manager);
+ _elput_input_pointer_max_update(manager);
+ }
+ else
+ {
+ ERR("Could not create input fd handler");
+ libinput_unref(manager->input.lib);
+ manager->input.lib = NULL;
}
+}
- _process_events(&manager->input);
+static void
+_elput_input_init_notify(void *data EINA_UNUSED, Ecore_Thread *eth EINA_UNUSED, void *msg_data)
+{
+ Elput_Async_Open *ao = msg_data;
- fd = libinput_get_fd(manager->input.lib);
+ ao->manager->interface->open_async(ao->manager, ao->path, ao->flags);
+ free(ao->path);
+ free(ao);
+}
- manager->input.hdlr =
- ecore_main_fd_handler_add(fd, ECORE_FD_READ, _cb_input_dispatch,
- &manager->input, NULL, NULL);
- if (!manager->input.hdlr)
+static void
+_elput_input_init_thread(void *data, Ecore_Thread *eth EINA_UNUSED)
+{
+ Elput_Manager *manager = data;
+ struct udev *udev = udev_new();
+
+ manager->input.lib =
+ libinput_udev_create_context(&_input_interface, manager, udev);
+ if (!manager->input.lib)
{
- ERR("Could not create input fd handler");
- goto hdlr_err;
+ ERR("libinput could not create udev context");
+ return;
}
+ udev_unref(udev);
- return EINA_TRUE;
+ if (libinput_udev_assign_seat(manager->input.lib, manager->seat))
+ {
+ ERR("libinput could not assign udev seat");
+ libinput_unref(manager->input.lib);
+ manager->input.lib = NULL;
+ }
+}
+
+EAPI Eina_Bool
+elput_input_init(Elput_Manager *manager)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(manager, EINA_FALSE);
+ EINA_SAFETY_ON_TRUE_RETURN_VAL(!!manager->input.hdlr, EINA_TRUE);
-hdlr_err:
-seat_err:
- libinput_unref(manager->input.lib);
-udev_err:
- return EINA_FALSE;
+ memset(&manager->input, 0, sizeof(Elput_Input));
+ manager->input.thread =
+ ecore_thread_feedback_run(_elput_input_init_thread, _elput_input_init_notify,
+ _elput_input_init_end, _elput_input_init_cancel, manager, 1);
+ return !!manager->input.thread;
}
EAPI void
@@ -263,14 +372,18 @@ elput_input_shutdown(Elput_Manager *manager)
Elput_Seat *seat;
EINA_SAFETY_ON_NULL_RETURN(manager);
- EINA_SAFETY_ON_NULL_RETURN(&manager->input);
- if (manager->input.hdlr) ecore_main_fd_handler_del(manager->input.hdlr);
+ ecore_main_fd_handler_del(manager->input.hdlr);
EINA_LIST_FREE(manager->input.seats, seat)
_udev_seat_destroy(seat);
-
- libinput_unref(manager->input.lib);
+ if (manager->input.thread)
+ ecore_thread_cancel(manager->input.thread);
+ else
+ {
+ libinput_unref(manager->input.lib);
+ manager->input.lib = NULL;
+ }
}
EAPI void
diff --git a/src/lib/elput/elput_logind.c b/src/lib/elput/elput_logind.c
index 3beb8b4eae..8db4a113fa 100644
--- a/src/lib/elput/elput_logind.c
+++ b/src/lib/elput/elput_logind.c
@@ -30,31 +30,19 @@ _logind_session_active_send(Elput_Manager *em, Eina_Bool active)
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");
+ msg = eldbus_proxy_method_call_new(em->dbus.session, "PauseDeviceComplete");
if (!msg)
{
ERR("Could not create method call for proxy");
- goto end;
+ eldbus_message_unref(msg);
+ return;
}
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);
+ eldbus_proxy_send(em->dbus.session, msg, NULL, NULL, -1);
}
static void
@@ -194,10 +182,10 @@ _logind_dbus_setup(Elput_Manager *em)
ERR("Could not get dbus proxy");
goto proxy_err;
}
+ em->dbus.manager = proxy;
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");
@@ -206,13 +194,12 @@ _logind_dbus_setup(Elput_Manager *em)
ERR("Could not get dbus proxy");
goto proxy_err;
}
+ em->dbus.session = proxy;
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)
@@ -235,173 +222,189 @@ obj_err:
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");
+ msg = eldbus_proxy_method_call_new(em->dbus.session, "TakeControl");
if (!msg)
{
ERR("Could not create method call for proxy");
- goto msg_err;
+ return EINA_FALSE;
}
eldbus_message_arguments_append(msg, "b", EINA_FALSE);
- reply = eldbus_proxy_send_and_block(proxy, msg, -1);
+ reply = eldbus_proxy_send_and_block(em->dbus.session, msg, -1);
if (eldbus_message_error_get(reply, &errname, &errmsg))
{
ERR("Eldbus Message Error: %s %s", errname, errmsg);
- goto msg_err;
+ return EINA_FALSE;
}
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)
+ msg = eldbus_proxy_method_call_new(em->dbus.session, "ReleaseControl");
+ if (!msg)
{
- ERR("Could not get proxy for session");
+ ERR("Could not create method call for proxy");
return;
}
- msg = eldbus_proxy_method_call_new(proxy, "ReleaseControl");
+ eldbus_proxy_send(em->dbus.session, msg, NULL, NULL, -1);
+}
+
+static void
+_logind_device_release(Elput_Manager *em, uint32_t major, uint32_t minor)
+{
+ Eldbus_Message *msg;
+
+ msg = eldbus_proxy_method_call_new(em->dbus.session, "ReleaseDevice");
if (!msg)
{
ERR("Could not create method call for proxy");
- goto end;
+ return;
}
- eldbus_proxy_send(proxy, msg, NULL, NULL, -1);
+ eldbus_message_arguments_append(msg, "uu", major, minor);
-end:
- eldbus_proxy_unref(proxy);
+ eldbus_proxy_send(em->dbus.session, msg, NULL, NULL, -1);
}
-static int
-_logind_device_take(Elput_Manager *em, uint32_t major, uint32_t minor)
+static void
+_logind_pipe_write_fd(Elput_Manager *em, int fd)
+{
+ write(em->input.pipe, &fd, sizeof(int));
+ close(em->input.pipe);
+ em->input.pipe = -1;
+}
+
+static void
+_logind_device_take_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)
{
- Eldbus_Proxy *proxy;
- Eldbus_Message *msg, *reply;
Eina_Bool p = EINA_FALSE;
const char *errname, *errmsg;
- int fd = -1;
-
- proxy =
- eldbus_proxy_get(em->dbus.obj, "org.freedesktop.login1.Session");
- if (!proxy)
- {
- ERR("Could not get dbus proxy");
- return -1;
- }
-
- msg = eldbus_proxy_method_call_new(proxy, "TakeDevice");
- if (!msg)
- {
- ERR("Could not create method call for proxy");
- goto err;
- }
+ int ret, fd = -1;
+ int fl, flags;
+ Elput_Manager *em = data;
- eldbus_message_arguments_append(msg, "uu", major, minor);
+ if (em->input.current_pending == pending)
+ em->input.current_pending = NULL;
- reply = eldbus_proxy_send_and_block(proxy, msg, -1);
- if (eldbus_message_error_get(reply, &errname, &errmsg))
+ if (eldbus_message_error_get(msg, &errname, &errmsg))
{
ERR("Eldbus Message Error: %s %s", errname, errmsg);
goto err;
}
- if (!eldbus_message_arguments_get(reply, "hb", &fd, &p))
+ if (!eldbus_message_arguments_get(msg, "hb", &fd, &p))
ERR("Could not get UNIX_FD from dbus message");
- eldbus_message_unref(reply);
+ if (fd < 0) goto err;
+
+ fl = fcntl(fd, F_GETFL);
+ if (fl < 0) goto err;
+
+ flags = (intptr_t)eldbus_pending_data_get(pending, "flags");
+
+ if (flags & O_NONBLOCK)
+ fl |= O_NONBLOCK;
+
+ ret = fcntl(fd, F_SETFL, fl);
+ if (ret < 0) goto err;
+
+ _logind_pipe_write_fd(em, fd);
+ return;
err:
- eldbus_proxy_unref(proxy);
- return fd;
+ if (fd >= 0)
+ {
+ uintptr_t majo, mino;
+
+ close(fd);
+ majo = (uintptr_t)eldbus_pending_data_get(pending, "major");
+ mino = (uintptr_t)eldbus_pending_data_get(pending, "minor");
+ _logind_device_release(em, majo, mino);
+ }
+ fd = -1;
+ _logind_pipe_write_fd(em, fd);
}
static void
-_logind_device_release(Elput_Manager *em, uint32_t major, uint32_t minor)
+_logind_device_take_async(Elput_Manager *em, int flags, uint32_t major, uint32_t minor)
{
- Eldbus_Proxy *proxy;
Eldbus_Message *msg;
+ intptr_t fd = -1;
- proxy =
- eldbus_proxy_get(em->dbus.obj, "org.freedesktop.login1.Session");
- if (!proxy)
+ msg = eldbus_proxy_method_call_new(em->dbus.session, "TakeDevice");
+ if (!msg)
{
- ERR("Could not get proxy for session");
+ ERR("Could not create method call for proxy");
+ _logind_pipe_write_fd(em, fd);
return;
}
- msg = eldbus_proxy_method_call_new(proxy, "ReleaseDevice");
+ eldbus_message_arguments_append(msg, "uu", major, minor);
+
+ em->input.current_pending = eldbus_proxy_send(em->dbus.session, msg, _logind_device_take_cb, em, -1);
+ if (!em->input.current_pending) CRIT("FAIL!");
+ eldbus_pending_data_set(em->input.current_pending, "major", (uintptr_t*)(uintptr_t)major);
+ eldbus_pending_data_set(em->input.current_pending, "minor", (uintptr_t*)(uintptr_t)minor);
+ eldbus_pending_data_set(em->input.current_pending, "flags", (intptr_t*)(intptr_t)flags);
+}
+
+static int
+_logind_device_take(Elput_Manager *em, uint32_t major, uint32_t minor)
+{
+ Eldbus_Message *msg, *reply;
+ Eina_Bool p = EINA_FALSE;
+ const char *errname, *errmsg;
+ int fd = -1;
+
+ msg = eldbus_proxy_method_call_new(em->dbus.session, "TakeDevice");
if (!msg)
{
ERR("Could not create method call for proxy");
- goto end;
+ return -1;
}
eldbus_message_arguments_append(msg, "uu", major, minor);
- eldbus_proxy_send(proxy, msg, NULL, NULL, -1);
+ reply = eldbus_proxy_send_and_block(em->dbus.session, msg, -1);
+ if (eldbus_message_error_get(reply, &errname, &errmsg))
+ {
+ ERR("Eldbus Message Error: %s %s", errname, errmsg);
+ return -1;
+ }
-end:
- eldbus_proxy_unref(proxy);
+ if (!eldbus_message_arguments_get(reply, "hb", &fd, &p))
+ ERR("Could not get UNIX_FD from dbus message");
+
+ eldbus_message_unref(reply);
+ return fd;
}
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");
+ msg = eldbus_proxy_method_call_new(em->dbus.session, "Activate");
if (!msg)
{
ERR("Could not create method call for proxy");
- goto msg_err;
+ return EINA_FALSE;
}
- eldbus_proxy_send(proxy, msg, NULL, NULL, -1);
-
- eldbus_proxy_unref(proxy);
-
+ eldbus_proxy_send(em->dbus.session, msg, NULL, NULL, -1);
return EINA_TRUE;
-
-msg_err:
- eldbus_proxy_unref(proxy);
- return EINA_FALSE;
}
static Eina_Bool
@@ -498,6 +501,8 @@ static void
_logind_disconnect(Elput_Manager *em)
{
_logind_control_release(em);
+ eldbus_proxy_unref(em->dbus.manager);
+ eldbus_proxy_unref(em->dbus.session);
eldbus_object_unref(em->dbus.obj);
free(em->dbus.path);
_logind_dbus_close(em->dbus.conn);
@@ -506,6 +511,18 @@ _logind_disconnect(Elput_Manager *em)
free(em);
}
+static void
+_logind_open_async(Elput_Manager *em, const char *path, int flags)
+{
+ struct stat st;
+ intptr_t fd = -1;
+
+ if ((stat(path, &st) < 0) || (!S_ISCHR(st.st_mode)))
+ _logind_pipe_write_fd(em, fd);
+ else
+ _logind_device_take_async(em, flags, major(st.st_rdev), minor(st.st_rdev));
+}
+
static int
_logind_open(Elput_Manager *em, const char *path, int flags)
{
@@ -606,6 +623,7 @@ Elput_Interface _logind_interface =
_logind_connect,
_logind_disconnect,
_logind_open,
+ _logind_open_async,
_logind_close,
_logind_vt_set,
};
diff --git a/src/lib/elput/elput_manager.c b/src/lib/elput/elput_manager.c
index b1378f55b0..3b127afdc7 100644
--- a/src/lib/elput/elput_manager.c
+++ b/src/lib/elput/elput_manager.c
@@ -58,6 +58,14 @@ elput_manager_disconnect(Elput_Manager *manager)
EINA_SAFETY_ON_NULL_RETURN(manager);
EINA_SAFETY_ON_NULL_RETURN(manager->interface);
+
+ if (manager->input.thread)
+ {
+ ecore_thread_cancel(manager->input.thread);
+ manager->del = 1;
+ return;
+ }
+
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 c2f4b007ea..a934bf1d23 100644
--- a/src/lib/elput/elput_private.h
+++ b/src/lib/elput/elput_private.h
@@ -71,6 +71,7 @@ typedef struct _Elput_Interface
Eina_Bool (*connect)(Elput_Manager **manager, const char *seat, unsigned int tty);
void (*disconnect)(Elput_Manager *manager);
int (*open)(Elput_Manager *manager, const char *path, int flags);
+ void (*open_async)(Elput_Manager *manager, const char *path, int flags);
void (*close)(Elput_Manager *manager, int fd);
Eina_Bool (*vt_set)(Elput_Manager *manager, int vt);
} Elput_Interface;
@@ -82,6 +83,9 @@ typedef struct _Elput_Input
Ecore_Fd_Handler *hdlr;
Eina_List *seats;
+ Ecore_Thread *thread;
+ Eldbus_Pending *current_pending;
+ int pipe;
Eina_Bool suspended : 1;
} Elput_Input;
@@ -224,18 +228,30 @@ struct _Elput_Manager
char *sid;
const char *seat;
unsigned int vt_num;
+ int vt_fd;
Ecore_Event_Handler *vt_hdlr;
+ uint32_t window;
struct
{
char *path;
Eldbus_Object *obj;
Eldbus_Connection *conn;
+ Eldbus_Proxy *session;
+ Eldbus_Proxy *manager;
} dbus;
Elput_Input input;
+ Eina_Bool del : 1;
};
+typedef struct _Elput_Async_Open
+{
+ Elput_Manager *manager;
+ char *path;
+ int flags;
+} Elput_Async_Open;
+
int _evdev_event_process(struct libinput_event *event);
Elput_Device *_evdev_device_create(Elput_Seat *seat, struct libinput_device *device);
void _evdev_device_destroy(Elput_Device *edev);