64d23ef308876a843a6056c29123913c6ec52cde
[src/agl-compositor.git] / src / input.c
1 /*
2  * Copyright © 2020 Collabora, Ltd.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the
13  * next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25
26 #include <assert.h>
27 #include <linux/input.h>
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <string.h>
31
32 #include "ivi-compositor.h"
33 #include "shared/helpers.h"
34
35 struct ivi_shell_seat {
36         struct weston_seat *seat;
37         struct weston_surface *focused_surface;
38
39         bool hide_cursor;
40         bool new_caps_sent;
41
42         struct wl_listener seat_destroy_listener;
43         struct wl_listener caps_changed_listener;
44         struct wl_listener keyboard_focus_listener;
45         struct wl_listener pointer_focus_listener;
46 };
47
48 static struct ivi_surface *
49 get_ivi_shell_surface(struct weston_surface *surface)
50 {
51         struct weston_desktop_surface *desktop_surface =
52                 weston_surface_get_desktop_surface(surface);
53
54         if (desktop_surface)
55                 return weston_desktop_surface_get_user_data(desktop_surface);
56
57         return NULL;
58 }
59
60 static void
61 ivi_shell_seat_handle_destroy(struct wl_listener *listener, void *data)
62 {
63         struct ivi_shell_seat *shseat =
64                 container_of(listener,
65                              struct ivi_shell_seat, seat_destroy_listener);
66
67         wl_list_remove(&shseat->keyboard_focus_listener.link);
68         wl_list_remove(&shseat->caps_changed_listener.link);
69         wl_list_remove(&shseat->pointer_focus_listener.link);
70         wl_list_remove(&shseat->seat_destroy_listener.link);
71
72         free(shseat);
73 }
74
75 static struct ivi_shell_seat *
76 get_ivi_shell_seat(struct weston_seat *seat)
77 {
78         struct wl_listener *listener;
79
80         listener = wl_signal_get(&seat->destroy_signal,
81                                  ivi_shell_seat_handle_destroy);
82         assert(listener != NULL);
83
84         return container_of(listener,
85                             struct ivi_shell_seat, seat_destroy_listener);
86 }
87
88
89 static void
90 ivi_shell_seat_handle_keyboard_focus(struct wl_listener *listener, void *data)
91 {
92         struct weston_keyboard *keyboard = data;
93         struct ivi_shell_seat *shseat = get_ivi_shell_seat(keyboard->seat);
94
95         if (shseat->focused_surface) {
96                 struct ivi_surface *surf =
97                         get_ivi_shell_surface(shseat->focused_surface);
98                 if (surf && --surf->focus_count == 0)
99                         weston_desktop_surface_set_activated(surf->dsurface, false);
100         }
101
102         shseat->focused_surface = weston_surface_get_main_surface(keyboard->focus);
103
104         if (shseat->focused_surface) {
105                 struct ivi_surface *surf =
106                         get_ivi_shell_surface(shseat->focused_surface);
107                 if (surf && surf->focus_count++ == 0)
108                         weston_desktop_surface_set_activated(surf->dsurface, true);
109         }
110 }
111
112 static void
113 ivi_shell_seat_handle_pointer_focus(struct wl_listener *listener, void *data)
114 {
115         struct weston_pointer *pointer = data;
116         struct ivi_shell_seat *shseat = get_ivi_shell_seat(pointer->seat);
117         struct wl_resource *resource;
118         int resources = 0;
119
120         /* FIXME: should probably query it and not assume all caps */
121         uint32_t caps = (WL_SEAT_CAPABILITY_POINTER |
122                          WL_SEAT_CAPABILITY_TOUCH |
123                          WL_SEAT_CAPABILITY_KEYBOARD);
124
125         wl_resource_for_each(resource, &pointer->seat->base_resource_list)
126                 resources++;
127
128         /* remove the POINTER capability such that the client will not install
129          * a cursor surface */
130         if (shseat->hide_cursor && !shseat->new_caps_sent && resources) {
131                 caps &= ~WL_SEAT_CAPABILITY_POINTER;
132                 wl_resource_for_each(resource, &pointer->seat->base_resource_list) {
133                         wl_seat_send_capabilities(resource, caps);
134                 }
135                 shseat->new_caps_sent = true;
136         }
137 }
138
139 static void
140 ivi_shell_seat_handle_caps_changed(struct wl_listener *listener, void *data)
141 {
142         struct weston_keyboard *keyboard;
143         struct weston_pointer *pointer;
144         struct ivi_shell_seat *shseat;
145
146         shseat = container_of(listener, struct ivi_shell_seat,
147                               caps_changed_listener);
148         keyboard = weston_seat_get_keyboard(shseat->seat);
149         pointer = weston_seat_get_pointer(shseat->seat);
150
151         if (pointer && wl_list_empty(&shseat->pointer_focus_listener.link)) {
152                 wl_signal_add(&pointer->focus_signal,
153                               &shseat->pointer_focus_listener);
154         } else {
155                 wl_list_remove(&shseat->pointer_focus_listener.link);
156                 wl_list_init(&shseat->pointer_focus_listener.link);
157         }
158
159         if (keyboard &&
160             wl_list_empty(&shseat->keyboard_focus_listener.link)) {
161                 wl_signal_add(&keyboard->focus_signal,
162                               &shseat->keyboard_focus_listener);
163         } else if (!keyboard) {
164                 wl_list_remove(&shseat->keyboard_focus_listener.link);
165                 wl_list_init(&shseat->keyboard_focus_listener.link);
166         }
167 }
168
169 static struct ivi_shell_seat *
170 ivi_shell_seat_create(struct weston_seat *seat, bool hide_cursor)
171 {
172         struct ivi_shell_seat *shseat;
173
174         shseat = zalloc(sizeof(*shseat));
175         if (!shseat) {
176                 weston_log("no memory to allocate shell seat\n");
177                 return NULL;
178         }
179
180         shseat->seat = seat;
181         shseat->hide_cursor = hide_cursor;
182         shseat->new_caps_sent = false;
183
184         shseat->seat_destroy_listener.notify = ivi_shell_seat_handle_destroy;
185         wl_signal_add(&seat->destroy_signal, &shseat->seat_destroy_listener);
186
187         shseat->keyboard_focus_listener.notify =
188                 ivi_shell_seat_handle_keyboard_focus;
189         wl_list_init(&shseat->keyboard_focus_listener.link);
190
191         shseat->pointer_focus_listener.notify =
192                 ivi_shell_seat_handle_pointer_focus;
193         wl_list_init(&shseat->pointer_focus_listener.link);
194
195         shseat->caps_changed_listener.notify =
196                 ivi_shell_seat_handle_caps_changed;
197         wl_signal_add(&seat->updated_caps_signal, &shseat->caps_changed_listener);
198
199         ivi_shell_seat_handle_caps_changed(&shseat->caps_changed_listener, NULL);
200
201         return shseat;
202 }
203
204
205 static void
206 ivi_shell_handle_seat_created(struct wl_listener *listener, void *data)
207 {
208         struct weston_seat *seat = data;
209         struct ivi_compositor *ivi =
210                 container_of(listener, struct ivi_compositor, seat_created_listener);
211
212         weston_log("Cursor is %s\n", ivi->hide_cursor ? "set" : "not set");
213         ivi_shell_seat_create(seat, ivi->hide_cursor);
214 }
215
216 /*
217  * useful to reset the fact that 'new' capabilities have seent
218  */
219 void
220 ivi_seat_reset_caps_sent(struct ivi_compositor *ivi)
221 {
222         struct weston_compositor *ec = ivi->compositor;
223         struct weston_seat *seat;
224
225         wl_list_for_each(seat, &ec->seat_list, link) {
226                 struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(seat);
227                 ivi_seat->new_caps_sent = false;
228         }
229 }
230
231 void
232 ivi_seat_init(struct ivi_compositor *ivi)
233 {
234         struct weston_compositor *ec = ivi->compositor;
235         struct weston_seat *seat;
236
237         wl_list_for_each(seat, &ec->seat_list, link) {
238                 weston_log("Seat %p, cursor is %s\n", seat, ivi->hide_cursor ?
239                                 "set" : "not set");
240                 ivi_shell_seat_create(seat, ivi->hide_cursor);
241         }
242
243         ivi->seat_created_listener.notify = ivi_shell_handle_seat_created;
244         wl_signal_add(&ec->seat_created_signal, &ivi->seat_created_listener);
245 }