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