summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarius Vlad <marius.vlad@collabora.com>2020-09-17 00:24:31 +0300
committerJan-Simon Moeller <jsmoeller@linuxfoundation.org>2020-09-30 13:43:12 +0000
commit3ba840cd3a5a2fa1966b01ef286de0347e64aa46 (patch)
treeb5916f33b400b73b561e7c8d4ace407b03a3a98d
parentbe8288cc5b127074fae6e2da052d6cd5cd623ae2 (diff)
input: Add basic seat handling
This allows for basic input handling, to better customize how we handle out seat capabilities to the client. One useful outcome of this is the fact that we re-advertise to the client that in some situations there might not be a pointer available. That should let the client know as to avoid creating a pointer surface. Bug-AGL: SPEC-3591 Signed-off-by: Marius Vlad <marius.vlad@collabora.com> Change-Id: I4624a956264e9fa12a86da005944e9b426dde10a
-rw-r--r--meson.build1
-rw-r--r--src/desktop.c3
-rw-r--r--src/input.c245
-rw-r--r--src/ivi-compositor.h9
-rw-r--r--src/main.c10
5 files changed, 267 insertions, 1 deletions
diff --git a/meson.build b/meson.build
index 6809579..ab4f086 100644
--- a/meson.build
+++ b/meson.build
@@ -144,6 +144,7 @@ srcs_agl_compositor = [
'src/policy.c',
'src/shell.c',
'src/screenshooter.c',
+ 'src/input.c',
'shared/option-parser.c',
'shared/os-compatibility.c',
agl_shell_server_protocol_h,
diff --git a/src/desktop.c b/src/desktop.c
index 0fca2fd..58d2887 100644
--- a/src/desktop.c
+++ b/src/desktop.c
@@ -99,6 +99,9 @@ desktop_surface_added(struct weston_desktop_surface *dsurface, void *userdata)
if ((active_output = ivi_layout_find_with_app_id(app_id, ivi)))
ivi_set_pending_desktop_surface_remote(active_output, app_id);
+ /* reset any caps to make sure we apply the new caps */
+ ivi_seat_reset_caps_sent(ivi);
+
if (ivi->shell_client.ready) {
ivi_check_pending_desktop_surface(surface);
weston_log("Added surface %p, app_id %s, role %s\n", surface,
diff --git a/src/input.c b/src/input.c
new file mode 100644
index 0000000..64d23ef
--- /dev/null
+++ b/src/input.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright © 2020 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <assert.h>
+#include <linux/input.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "ivi-compositor.h"
+#include "shared/helpers.h"
+
+struct ivi_shell_seat {
+ struct weston_seat *seat;
+ struct weston_surface *focused_surface;
+
+ bool hide_cursor;
+ bool new_caps_sent;
+
+ struct wl_listener seat_destroy_listener;
+ struct wl_listener caps_changed_listener;
+ struct wl_listener keyboard_focus_listener;
+ struct wl_listener pointer_focus_listener;
+};
+
+static struct ivi_surface *
+get_ivi_shell_surface(struct weston_surface *surface)
+{
+ struct weston_desktop_surface *desktop_surface =
+ weston_surface_get_desktop_surface(surface);
+
+ if (desktop_surface)
+ return weston_desktop_surface_get_user_data(desktop_surface);
+
+ return NULL;
+}
+
+static void
+ivi_shell_seat_handle_destroy(struct wl_listener *listener, void *data)
+{
+ struct ivi_shell_seat *shseat =
+ container_of(listener,
+ struct ivi_shell_seat, seat_destroy_listener);
+
+ wl_list_remove(&shseat->keyboard_focus_listener.link);
+ wl_list_remove(&shseat->caps_changed_listener.link);
+ wl_list_remove(&shseat->pointer_focus_listener.link);
+ wl_list_remove(&shseat->seat_destroy_listener.link);
+
+ free(shseat);
+}
+
+static struct ivi_shell_seat *
+get_ivi_shell_seat(struct weston_seat *seat)
+{
+ struct wl_listener *listener;
+
+ listener = wl_signal_get(&seat->destroy_signal,
+ ivi_shell_seat_handle_destroy);
+ assert(listener != NULL);
+
+ return container_of(listener,
+ struct ivi_shell_seat, seat_destroy_listener);
+}
+
+
+static void
+ivi_shell_seat_handle_keyboard_focus(struct wl_listener *listener, void *data)
+{
+ struct weston_keyboard *keyboard = data;
+ struct ivi_shell_seat *shseat = get_ivi_shell_seat(keyboard->seat);
+
+ if (shseat->focused_surface) {
+ struct ivi_surface *surf =
+ get_ivi_shell_surface(shseat->focused_surface);
+ if (surf && --surf->focus_count == 0)
+ weston_desktop_surface_set_activated(surf->dsurface, false);
+ }
+
+ shseat->focused_surface = weston_surface_get_main_surface(keyboard->focus);
+
+ if (shseat->focused_surface) {
+ struct ivi_surface *surf =
+ get_ivi_shell_surface(shseat->focused_surface);
+ if (surf && surf->focus_count++ == 0)
+ weston_desktop_surface_set_activated(surf->dsurface, true);
+ }
+}
+
+static void
+ivi_shell_seat_handle_pointer_focus(struct wl_listener *listener, void *data)
+{
+ struct weston_pointer *pointer = data;
+ struct ivi_shell_seat *shseat = get_ivi_shell_seat(pointer->seat);
+ struct wl_resource *resource;
+ int resources = 0;
+
+ /* FIXME: should probably query it and not assume all caps */
+ uint32_t caps = (WL_SEAT_CAPABILITY_POINTER |
+ WL_SEAT_CAPABILITY_TOUCH |
+ WL_SEAT_CAPABILITY_KEYBOARD);
+
+ wl_resource_for_each(resource, &pointer->seat->base_resource_list)
+ resources++;
+
+ /* remove the POINTER capability such that the client will not install
+ * a cursor surface */
+ if (shseat->hide_cursor && !shseat->new_caps_sent && resources) {
+ caps &= ~WL_SEAT_CAPABILITY_POINTER;
+ wl_resource_for_each(resource, &pointer->seat->base_resource_list) {
+ wl_seat_send_capabilities(resource, caps);
+ }
+ shseat->new_caps_sent = true;
+ }
+}
+
+static void
+ivi_shell_seat_handle_caps_changed(struct wl_listener *listener, void *data)
+{
+ struct weston_keyboard *keyboard;
+ struct weston_pointer *pointer;
+ struct ivi_shell_seat *shseat;
+
+ shseat = container_of(listener, struct ivi_shell_seat,
+ caps_changed_listener);
+ keyboard = weston_seat_get_keyboard(shseat->seat);
+ pointer = weston_seat_get_pointer(shseat->seat);
+
+ if (pointer && wl_list_empty(&shseat->pointer_focus_listener.link)) {
+ wl_signal_add(&pointer->focus_signal,
+ &shseat->pointer_focus_listener);
+ } else {
+ wl_list_remove(&shseat->pointer_focus_listener.link);
+ wl_list_init(&shseat->pointer_focus_listener.link);
+ }
+
+ if (keyboard &&
+ wl_list_empty(&shseat->keyboard_focus_listener.link)) {
+ wl_signal_add(&keyboard->focus_signal,
+ &shseat->keyboard_focus_listener);
+ } else if (!keyboard) {
+ wl_list_remove(&shseat->keyboard_focus_listener.link);
+ wl_list_init(&shseat->keyboard_focus_listener.link);
+ }
+}
+
+static struct ivi_shell_seat *
+ivi_shell_seat_create(struct weston_seat *seat, bool hide_cursor)
+{
+ struct ivi_shell_seat *shseat;
+
+ shseat = zalloc(sizeof(*shseat));
+ if (!shseat) {
+ weston_log("no memory to allocate shell seat\n");
+ return NULL;
+ }
+
+ shseat->seat = seat;
+ shseat->hide_cursor = hide_cursor;
+ shseat->new_caps_sent = false;
+
+ shseat->seat_destroy_listener.notify = ivi_shell_seat_handle_destroy;
+ wl_signal_add(&seat->destroy_signal, &shseat->seat_destroy_listener);
+
+ shseat->keyboard_focus_listener.notify =
+ ivi_shell_seat_handle_keyboard_focus;
+ wl_list_init(&shseat->keyboard_focus_listener.link);
+
+ shseat->pointer_focus_listener.notify =
+ ivi_shell_seat_handle_pointer_focus;
+ wl_list_init(&shseat->pointer_focus_listener.link);
+
+ shseat->caps_changed_listener.notify =
+ ivi_shell_seat_handle_caps_changed;
+ wl_signal_add(&seat->updated_caps_signal, &shseat->caps_changed_listener);
+
+ ivi_shell_seat_handle_caps_changed(&shseat->caps_changed_listener, NULL);
+
+ return shseat;
+}
+
+
+static void
+ivi_shell_handle_seat_created(struct wl_listener *listener, void *data)
+{
+ struct weston_seat *seat = data;
+ struct ivi_compositor *ivi =
+ container_of(listener, struct ivi_compositor, seat_created_listener);
+
+ weston_log("Cursor is %s\n", ivi->hide_cursor ? "set" : "not set");
+ ivi_shell_seat_create(seat, ivi->hide_cursor);
+}
+
+/*
+ * useful to reset the fact that 'new' capabilities have seent
+ */
+void
+ivi_seat_reset_caps_sent(struct ivi_compositor *ivi)
+{
+ struct weston_compositor *ec = ivi->compositor;
+ struct weston_seat *seat;
+
+ wl_list_for_each(seat, &ec->seat_list, link) {
+ struct ivi_shell_seat *ivi_seat = get_ivi_shell_seat(seat);
+ ivi_seat->new_caps_sent = false;
+ }
+}
+
+void
+ivi_seat_init(struct ivi_compositor *ivi)
+{
+ struct weston_compositor *ec = ivi->compositor;
+ struct weston_seat *seat;
+
+ wl_list_for_each(seat, &ec->seat_list, link) {
+ weston_log("Seat %p, cursor is %s\n", seat, ivi->hide_cursor ?
+ "set" : "not set");
+ ivi_shell_seat_create(seat, ivi->hide_cursor);
+ }
+
+ ivi->seat_created_listener.notify = ivi_shell_handle_seat_created;
+ wl_signal_add(&ec->seat_created_signal, &ivi->seat_created_listener);
+}
diff --git a/src/ivi-compositor.h b/src/ivi-compositor.h
index 4506a5a..4708b5d 100644
--- a/src/ivi-compositor.h
+++ b/src/ivi-compositor.h
@@ -53,6 +53,7 @@ struct ivi_compositor {
struct wl_listener heads_changed;
bool init_failed;
+ bool hide_cursor;
/*
* Options parsed from command line arugments.
@@ -85,6 +86,7 @@ struct ivi_compositor {
struct wl_list surfaces; /* ivi_surface.link */
struct weston_desktop *desktop;
+ struct wl_listener seat_created_listener;
struct ivi_policy *policy;
struct wl_list pending_surfaces;
@@ -233,6 +235,7 @@ struct ivi_surface {
struct weston_view *view;
struct wl_list link;
+ int focus_count;
struct {
enum ivi_surface_flags flags;
@@ -380,4 +383,10 @@ shell_advertise_app_state(struct ivi_compositor *ivi, const char *app_id,
void
ivi_screenshooter_create(struct ivi_compositor *ivi);
+void
+ivi_seat_init(struct ivi_compositor *ivi);
+
+void
+ivi_seat_reset_caps_sent(struct ivi_compositor *ivi);
+
#endif
diff --git a/src/main.c b/src/main.c
index 164b45b..d77cbc7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1346,7 +1346,7 @@ usage(int error_code)
" --log=FILE\t\tLog to the given file\n"
" -c, --config=FILE\tConfig file to load, defaults to agl-compositor.ini\n"
" --no-config\t\tDo not read agl-compositor.ini\n"
- " --debug\t\tEnable debug extension\n"
+ " --debug\t\tEnable debug extension(s)\n"
" -h, --help\t\tThis help message\n"
"\n");
exit(error_code);
@@ -1366,6 +1366,7 @@ int main(int argc, char *argv[])
int help = 0;
int version = 0;
int no_config = 0;
+ int debug = 0;
char *config_file = NULL;
struct weston_log_context *log_ctx = NULL;
struct weston_log_subscriber *logger;
@@ -1378,6 +1379,7 @@ int main(int argc, char *argv[])
{ WESTON_OPTION_BOOLEAN, "help", 'h', &help },
{ WESTON_OPTION_BOOLEAN, "version", 0, &version },
{ WESTON_OPTION_BOOLEAN, "no-config", 0, &no_config },
+ { WESTON_OPTION_BOOLEAN, "debug", 0, &debug },
{ WESTON_OPTION_STRING, "config", 'c', &config_file },
};
@@ -1390,6 +1392,7 @@ int main(int argc, char *argv[])
wl_list_init(&ivi.remote_pending_apps);
wl_list_init(&ivi.desktop_clients);
+
/* Prevent any clients we spawn getting our stdin */
os_fd_set_cloexec(STDIN_FILENO);
@@ -1403,6 +1406,9 @@ int main(int argc, char *argv[])
return EXIT_SUCCESS;
}
+ if (debug)
+ ivi.hide_cursor = true;
+
log_ctx = weston_log_ctx_compositor_create();
if (!log_ctx) {
fprintf(stderr, "Failed to initialize weston debug framework.\n");
@@ -1469,6 +1475,8 @@ int main(int argc, char *argv[])
if (ivi_desktop_init(&ivi) < 0)
goto error_compositor;
+ ivi_seat_init(&ivi);
+
if (ivi_policy_init(&ivi) < 0)
goto error_compositor;