1a143ce0d6d6aed4024f35388b92897a5f94f64c
[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_surface *
36 get_ivi_shell_surface(struct weston_surface *surface)
37 {
38         struct weston_desktop_surface *desktop_surface =
39                 weston_surface_get_desktop_surface(surface);
40
41         if (desktop_surface)
42                 return weston_desktop_surface_get_user_data(desktop_surface);
43
44         return NULL;
45 }
46
47 static void
48 ivi_shell_seat_handle_destroy(struct wl_listener *listener, void *data)
49 {
50         struct ivi_shell_seat *shseat =
51                 container_of(listener,
52                              struct ivi_shell_seat, seat_destroy_listener);
53
54         wl_list_remove(&shseat->keyboard_focus_listener.link);
55         wl_list_remove(&shseat->caps_changed_listener.link);
56         wl_list_remove(&shseat->pointer_focus_listener.link);
57         wl_list_remove(&shseat->seat_destroy_listener.link);
58
59         free(shseat);
60 }
61
62 struct ivi_shell_seat *
63 get_ivi_shell_seat(struct weston_seat *seat)
64 {
65         struct wl_listener *listener;
66
67         if (!seat)
68                 return NULL;
69
70
71         listener = wl_signal_get(&seat->destroy_signal,
72                                  ivi_shell_seat_handle_destroy);
73         if (!listener)
74                 return NULL;
75
76         return container_of(listener,
77                             struct ivi_shell_seat, seat_destroy_listener);
78 }
79
80 struct weston_seat *
81 get_ivi_shell_weston_first_seat(struct ivi_compositor *ivi)
82 {
83         struct wl_list *node;
84         struct weston_compositor *compositor = ivi->compositor;
85
86         if (wl_list_empty(&compositor->seat_list))
87                 return NULL;
88
89         node = compositor->seat_list.next;
90         return container_of(node, struct weston_seat, link);
91 }
92
93 static void
94 ivi_shell_seat_handle_pointer_focus(struct wl_listener *listener, void *data)
95 {
96         struct weston_pointer *pointer = data;
97         struct ivi_shell_seat *shseat = get_ivi_shell_seat(pointer->seat);
98         struct wl_resource *resource;
99         int resources = 0;
100
101         /* FIXME: should probably query it and not assume all caps */
102         uint32_t caps = (WL_SEAT_CAPABILITY_POINTER |
103                          WL_SEAT_CAPABILITY_TOUCH |
104                          WL_SEAT_CAPABILITY_KEYBOARD);
105
106         wl_resource_for_each(resource, &pointer->seat->base_resource_list)
107                 resources++;
108
109         /* remove the POINTER capability such that the client will not install
110          * a cursor surface */
111         if (shseat->hide_cursor && !shseat->new_caps_sent && resources) {
112                 caps &= ~WL_SEAT_CAPABILITY_POINTER;
113                 wl_resource_for_each(resource, &pointer->seat->base_resource_list) {
114                         wl_seat_send_capabilities(resource, caps);
115                 }
116                 shseat->new_caps_sent = true;
117         }
118 }
119
120 static void
121 ivi_shell_seat_handle_caps_changed(struct wl_listener *listener, void *data)
122 {
123         struct weston_pointer *pointer;
124         struct ivi_shell_seat *shseat;
125
126         shseat = container_of(listener, struct ivi_shell_seat,
127                               caps_changed_listener);
128         pointer = weston_seat_get_pointer(shseat->seat);
129
130         if (pointer && wl_list_empty(&shseat->pointer_focus_listener.link)) {
131                 wl_signal_add(&pointer->focus_signal,
132                               &shseat->pointer_focus_listener);
133         } else {
134                 wl_list_remove(&shseat->pointer_focus_listener.link);
135                 wl_list_init(&shseat->pointer_focus_listener.link);
136         }
137 }
138
139 static struct ivi_shell_seat *
140 ivi_shell_seat_create(struct weston_seat *seat, bool hide_cursor)
141 {
142         struct ivi_shell_seat *shseat;
143
144         shseat = zalloc(sizeof(*shseat));
145         if (!shseat) {
146                 weston_log("no memory to allocate shell seat\n");
147                 return NULL;
148         }
149
150         shseat->seat = seat;
151         shseat->hide_cursor = hide_cursor;
152         shseat->new_caps_sent = false;
153
154         shseat->seat_destroy_listener.notify = ivi_shell_seat_handle_destroy;
155         wl_signal_add(&seat->destroy_signal, &shseat->seat_destroy_listener);
156
157         wl_list_init(&shseat->keyboard_focus_listener.link);
158
159         shseat->pointer_focus_listener.notify =
160                 ivi_shell_seat_handle_pointer_focus;
161         wl_list_init(&shseat->pointer_focus_listener.link);
162
163         shseat->caps_changed_listener.notify =
164                 ivi_shell_seat_handle_caps_changed;
165         wl_signal_add(&seat->updated_caps_signal, &shseat->caps_changed_listener);
166
167         ivi_shell_seat_handle_caps_changed(&shseat->caps_changed_listener, NULL);
168
169         return shseat;
170 }
171
172
173 static void
174 ivi_shell_handle_seat_created(struct wl_listener *listener, void *data)
175 {
176         struct weston_seat *seat = data;
177         struct ivi_compositor *ivi =
178                 container_of(listener, struct ivi_compositor, seat_created_listener);
179
180         weston_log("Cursor is %s\n", ivi->hide_cursor ? "set" : "not set");
181         ivi_shell_seat_create(seat, ivi->hide_cursor);
182 }
183
184 /*
185  * useful to reset the fact that 'new' capabilities have seent
186  */
187 void
188 ivi_seat_reset_caps_sent(struct ivi_compositor *ivi)
189 {
190         struct weston_compositor *ec = ivi->compositor;
191         struct weston_seat *seat;
192
193         wl_list_for_each(seat, &ec->seat_list, link) {
194                 struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(seat);
195                 ivi_seat->new_caps_sent = false;
196         }
197 }
198
199 void
200 ivi_seat_init(struct ivi_compositor *ivi)
201 {
202         struct weston_compositor *ec = ivi->compositor;
203         struct weston_seat *seat;
204
205         wl_list_for_each(seat, &ec->seat_list, link) {
206                 weston_log("Seat %p, cursor is %s\n", seat, ivi->hide_cursor ?
207                                 "set" : "not set");
208                 ivi_shell_seat_create(seat, ivi->hide_cursor);
209         }
210
211         ivi->seat_created_listener.notify = ivi_shell_handle_seat_created;
212         wl_signal_add(&ec->seat_created_signal, &ivi->seat_created_listener);
213 }