#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
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
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
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
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");
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)
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
_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);
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)
{
_logind_connect,
_logind_disconnect,
_logind_open,
+ _logind_open_async,
_logind_close,
_logind_vt_set,
};