f3ee044b091515c2945579a9033c47e0891b3c66
[platform/core/uifw/libds-tizen.git] / src / libds / backend / libinput / backend.c
1 #include <assert.h>
2 #include <stdbool.h>
3 #include <stdlib.h>
4 #include <sys/stat.h>
5 #include <sys/types.h>
6 #include <fcntl.h>
7 #include <unistd.h>
8
9 #include "libds/log.h"
10
11 #include "backend.h"
12
13 static const struct ds_backend_interface libinput_backend_interface;
14 static void libinput_backend_handle_display_destroy(
15         struct wl_listener *listener, void *data);
16
17 WL_EXPORT struct ds_backend *
18 ds_libinput_backend_create(struct wl_display *display)
19 {
20     struct ds_libinput_backend *libinput_backend;
21
22     libinput_backend = calloc(1, sizeof *libinput_backend);
23     if (!libinput_backend) {
24         ds_log_errno(DS_ERR, "Could not allocate memory");
25         return NULL;
26     }
27
28     ds_backend_init(&libinput_backend->base, &libinput_backend_interface);
29
30     libinput_backend->display = display;
31     wl_list_init(&libinput_backend->devices);
32
33     libinput_backend->display_destroy.notify =
34             libinput_backend_handle_display_destroy;
35     wl_display_add_destroy_listener(display,
36             &libinput_backend->display_destroy);
37
38     ds_inf("Libinput backend(%p) created",
39             libinput_backend);
40
41     return &libinput_backend->base;
42 }
43
44 WL_EXPORT struct ds_libinput_backend *
45 libinput_backend_from_backend(struct ds_backend *backend)
46 {
47     assert(backend->iface == &libinput_backend_interface);
48     return (struct ds_libinput_backend *)backend;
49 }
50
51 void
52 destroy_libinput_input_device(struct ds_libinput_input_device *dev)
53 {
54     ds_input_device_destroy(&dev->base);
55     libinput_device_unref(dev->handle);
56     wl_list_remove(&dev->link);
57     free(dev);
58 }
59
60 static void
61 libinput_backend_destroy(struct ds_libinput_backend *backend)
62 {
63     struct ds_libinput_input_device *dev, *tmp_dev;
64
65     wl_list_for_each_safe(dev, tmp_dev, &backend->devices, link)
66         destroy_libinput_input_device(dev);
67
68     ds_backend_finish(&backend->base);
69     wl_list_remove(&backend->display_destroy.link);
70     wl_event_source_remove(backend->server_event_source);
71     udev_unref(backend->udev);
72     libinput_unref(backend->libinput_context);
73
74     free(backend);
75 }
76
77 static int
78 libinput_open_restricted(const char *path, int flags, void *_backend)
79 {
80     int fd = -1;
81     struct stat s;
82
83     fd = open(path, flags | O_CLOEXEC);
84
85     if (fd < 0 || (fstat(fd, &s) == -1)) {
86         ds_log(DS_ERR, "Could not open device");
87         close(fd);
88         return -1;
89     }
90     return fd;
91 }
92
93 static void
94 libinput_close_restricted(int fd, void *_backend)
95 {
96     if (fd >= 0) close(fd);
97 }
98
99 static const struct libinput_interface libinput_impl = {
100     .open_restricted = libinput_open_restricted,
101     .close_restricted = libinput_close_restricted
102 };
103
104 static int
105 handle_libinput_readable(int fd, uint32_t mask, void *_backend)
106 {
107     struct ds_libinput_backend *backend = _backend;
108     struct libinput_event *event;
109     int ret;
110
111     ret = libinput_dispatch(backend->libinput_context);
112     if (ret != 0) {
113         ds_log(DS_ERR, "Failed to dispatch libinput: %s", strerror(-ret));
114         wl_display_terminate(backend->display);
115         return 0;
116     }
117
118     while ((event = libinput_get_event(backend->libinput_context))) {
119         handle_libinput_event(backend, event);
120         libinput_event_destroy(event);
121     }
122     return 0;
123 }
124
125 static void
126 log_libinput(struct libinput *libinput_context,
127         enum libinput_log_priority priority, const char *fmt, va_list args)
128 {
129     char buf[1024] = {0,};
130
131     vsnprintf(buf, 1024, fmt, args);
132     switch (priority) {
133         case LIBINPUT_LOG_PRIORITY_DEBUG:
134            ds_log(DS_DBG,"%s", buf);
135            break;
136         case LIBINPUT_LOG_PRIORITY_INFO:
137            ds_log(DS_INF, "%s", buf);
138            break;
139         case LIBINPUT_LOG_PRIORITY_ERROR:
140            ds_log(DS_ERR, "%s", buf);
141            break;
142         default:
143            break;
144      }
145 }
146
147 static bool
148 libinput_backend_iface_start(struct ds_backend *ds_backend)
149 {
150     struct ds_libinput_backend *backend;
151     struct wl_event_loop *event_loop;
152     int libinput_fd;
153
154     backend = libinput_backend_from_backend(ds_backend);
155     ds_log(DS_DBG, "Starting libinput backend");
156
157     backend->udev = udev_new();
158     backend->libinput_context = libinput_udev_create_context(&libinput_impl,
159             backend, backend->udev);
160     if (!backend->libinput_context) {
161         ds_log(DS_ERR, "Failed to create libinput context");
162         return false;
163     }
164
165     if (libinput_udev_assign_seat(backend->libinput_context, "seat0") != 0) {
166         ds_log(DS_ERR, "Failed to assign libinput seat");
167         return false;
168     }
169
170     libinput_log_set_handler(backend->libinput_context, log_libinput);
171     libinput_log_set_priority(backend->libinput_context,
172             LIBINPUT_LOG_PRIORITY_DEBUG);
173
174     libinput_fd = libinput_get_fd(backend->libinput_context);
175     if (wl_list_empty(&backend->devices)) {
176         handle_libinput_readable(libinput_fd, WL_EVENT_READABLE, backend);
177         if (wl_list_empty(&backend->devices)) {
178             ds_log(DS_ERR, "libinput initialization failed, no input devices");
179             return false;
180         }
181     }
182
183     event_loop = wl_display_get_event_loop(backend->display);
184     if (backend->server_event_source) {
185         wl_event_source_remove(backend->server_event_source);
186     }
187     backend->server_event_source =
188             wl_event_loop_add_fd(event_loop, libinput_fd, WL_EVENT_READABLE,
189             handle_libinput_readable, backend);
190     if (!backend->server_event_source) {
191         ds_log(DS_ERR, "Failed to create input event on event loop");
192         return false;
193     }
194     ds_log(DS_DBG, "libinput successfully initialized");
195
196     return true;
197 }
198
199 static void
200 libinput_backend_iface_destroy(struct ds_backend *backend)
201 {
202     struct ds_libinput_backend *libinput_backend;
203
204     if (!backend)
205         return;
206
207     libinput_backend = libinput_backend_from_backend(backend);
208     libinput_backend_destroy(libinput_backend);
209 }
210
211 static const struct ds_backend_interface libinput_backend_interface =
212 {
213     .start = libinput_backend_iface_start,
214     .destroy = libinput_backend_iface_destroy,
215     .get_drm_fd = NULL,
216 };
217
218 static void
219 libinput_backend_handle_display_destroy(struct wl_listener *listener,
220         void *data)
221 {
222     struct ds_libinput_backend *libinput_backend;
223
224     libinput_backend =
225             wl_container_of(listener, libinput_backend, display_destroy);
226     libinput_backend_destroy(libinput_backend);
227 }