This patch makes it possible to run wayland-fits without root. This approach also stresses the evdev.c stack. (calling the notify_* api approach would bypass the evdev.c stack) Testing also the evdev.c can help code test coverage. Probably can catch more bugs this way.
How it works. Basically, we make a pipe. Then we create evdev device and connect it to the pipe. Then we play the events via the pipe. In the end we destroy both pipe and the device. What effects does the patch have? This assumes weston sdk exports evdev.h It uses evdev_device_create() and evdev_device_destroy() in the tested compositor. In case the symbols are not available, wfits module will fail to be loaded. --- src/extensions/weston/Makefile.am | 5 +- src/extensions/weston/weston-wfits.cpp | 166 +++++++++++++++++++++++--------- 2 files changed, 122 insertions(+), 49 deletions(-) diff --git a/src/extensions/weston/Makefile.am b/src/extensions/weston/Makefile.am index 4af2f1d..b65a93f 100644 --- a/src/extensions/weston/Makefile.am +++ b/src/extensions/weston/Makefile.am @@ -10,11 +10,14 @@ weston_wfits = weston-wfits.la AM_CXXFLAGS = \ $(GCC_CFLAGS) \ $(WAYLAND_SERVER_CFLAGS) \ - $(WESTON_CFLAGS) + $(WESTON_CFLAGS) \ + -std=gnu++11 + weston_wfits_la_LDFLAGS = -module -avoid-version weston_wfits_la_LIBADD = \ $(WAYLAND_SERVER_LIBS) \ $(WESTON_LIBS) + weston_wfits_la_SOURCES = \ weston-wfits.cpp \ $(top_srcdir)/src/extensions/protocol/wayland-fits-protocol.c diff --git a/src/extensions/weston/weston-wfits.cpp b/src/extensions/weston/weston-wfits.cpp index a54e0fe..96cf617 100644 --- a/src/extensions/weston/weston-wfits.cpp +++ b/src/extensions/weston/weston-wfits.cpp @@ -42,6 +42,10 @@ extern "C" { #undef private } +extern "C" { +#include <weston/evdev.h> +} + #include "config.h" #include "extensions/protocol/wayland-fits-server-protocol.h" #include "common/util.h" @@ -76,8 +80,10 @@ struct x11_output { struct wfits { struct weston_compositor *compositor; struct wl_listener compositor_destroy_listener; - int input_fd; // file descriptor for our uinput device. + int pipe_fd[2]; // file descriptor for the pipe or the uinput fd twice bool is_headless; // whether weston is using a headless backend. + bool is_pipeston; + struct evdev_device *dev; }; /** @@ -153,14 +159,14 @@ global_size(struct wfits *wfits, int32_t *width, int32_t *height) output = get_output(wfits); - if (std::string(output->make) == "xwayland") { - x11_compositor = (struct x11_compositor*) wfits->compositor; - *width = x11_compositor->screen->width_in_pixels; - *height = x11_compositor->screen->height_in_pixels; - } else { +// if (std::string(output->make) == "xwayland") { +// x11_compositor = (struct x11_compositor*) wfits->compositor; +// *width = x11_compositor->screen->width_in_pixels; +// *height = x11_compositor->screen->height_in_pixels; +// } else { *width = output->width; *height = output->height; - } +// } } /** @@ -226,6 +232,8 @@ write_event_to_fd(int fd, struct input_event *event) static void move_pointer(struct wfits *wfits, const int32_t x, const int32_t y) { + wfits->compositor->focus = 1; + if (wfits->is_headless) { /** * Weston is using a headless backend, so originate/trigger @@ -247,24 +255,22 @@ move_pointer(struct wfits *wfits, const int32_t x, const int32_t y) struct input_event event; int32_t gx(x), gy(y); - compositor_to_global(wfits, &gx, &gy); - memset(&event, 0, sizeof(event)); event.type = EV_ABS; event.code = ABS_X; event.value = gx; - write_event_to_fd (wfits->input_fd, &event); + write_event_to_fd (wfits->pipe_fd[1], &event); event.type = EV_ABS; event.code = ABS_Y; event.value = gy; - write_event_to_fd (wfits->input_fd, &event); + write_event_to_fd (wfits->pipe_fd[1], &event); event.type = EV_SYN; event.code = SYN_REPORT; event.value = 0; - write_event_to_fd (wfits->input_fd, &event); + write_event_to_fd (wfits->pipe_fd[1], &event); } /** @@ -285,6 +291,8 @@ input_move_pointer(struct wl_client *client, struct wl_resource *resource, static void key_send(struct wfits *wfits, const uint32_t key, const uint32_t state) { + wfits->compositor->focus = 1; + if (wfits->is_headless) { /** * Weston is using a headless backend, so originate/trigger the @@ -292,8 +300,6 @@ key_send(struct wfits *wfits, const uint32_t key, const uint32_t state) **/ struct weston_seat *seat = get_seat(wfits); - wfits->compositor->focus = 1; - if (key == BTN_LEFT or key == BTN_MIDDLE or key == BTN_RIGHT) { notify_button(seat, 100, key, static_cast<wl_pointer_button_state>(state)); @@ -317,12 +323,12 @@ key_send(struct wfits *wfits, const uint32_t key, const uint32_t state) event.type = EV_KEY; event.code = key; event.value = state; - write_event_to_fd(wfits->input_fd, &event); + write_event_to_fd(wfits->pipe_fd[1], &event); event.type = EV_SYN; event.code = SYN_REPORT; event.value = 0; - write_event_to_fd(wfits->input_fd, &event); + write_event_to_fd(wfits->pipe_fd[1], &event); } /** @@ -384,56 +390,96 @@ bind_input(struct wl_client *client, void *data, uint32_t version, uint32_t id) resource->destroy = unbind_input_client; } -static void -create_input(struct wfits* wfits) +static int +create_input_pipeston(struct wfits* wfits) +{ + int32_t width; + int32_t height; + + if (pipe(wfits->pipe_fd) < 0) { + return -1; + } + + fcntl(wfits->pipe_fd[0], F_SETFD, fcntl(wfits->pipe_fd[0], F_GETFD) | FD_CLOEXEC); + fcntl(wfits->pipe_fd[0], F_SETFL, fcntl(wfits->pipe_fd[0], F_GETFL) | O_NONBLOCK); + fcntl(wfits->pipe_fd[1], F_SETFD, fcntl(wfits->pipe_fd[1], F_GETFD) | FD_CLOEXEC); + + /* + create only 1 device on 1 seat for now. + */ + + wfits->dev = evdev_device_create(get_seat(wfits), "<mock-dev-path>", wfits->pipe_fd[0]); + + + if ((wfits->dev == NULL) || (wfits->dev == EVDEV_UNHANDLED_DEVICE)) { + weston_log("ERROR creating device\n"); + wfits->dev = NULL; + return -2; + } + + wfits->dev->output = get_output(wfits); + global_size(wfits, &width, &height); + weston_log("%dx%d\n", width, height); + wfits->dev->abs.max_x = width - 1; + wfits->dev->abs.max_y = height - 1; + wfits->dev->abs.min_x = 0; + wfits->dev->abs.min_y = 0; + + wl_list_init(&wfits->dev->link); + + wfits->is_pipeston = true; + + return 0; +} + +static int +create_input_uinput(struct wfits* wfits) { struct uinput_user_dev device; struct weston_output *output = get_output(wfits); int32_t width; int32_t height; - - weston_log("weston-wfits: creating uinput device\n"); - wfits->input_fd = open("/dev/uinput", O_WRONLY | O_NDELAY); - if (wfits->input_fd < 0) { - weston_log("weston-wfits: failed to create uinput device\n"); - exit(EXIT_FAILURE); + wfits->pipe_fd[0] = wfits->pipe_fd[1] = open("/dev/uinput", O_WRONLY | O_NDELAY); + if (wfits->pipe_fd[1] < 0) { + return -1; } - if (ioctl(wfits->input_fd, UI_SET_EVBIT, EV_KEY) < 0) { - exit(EXIT_FAILURE); + if (ioctl(wfits->pipe_fd[1], UI_SET_EVBIT, EV_KEY) < 0) { + return -2; } for (int32_t i(0); i < 255; ++i) { - if (ioctl(wfits->input_fd, UI_SET_KEYBIT, i) < 0) { - exit(EXIT_FAILURE); + if (ioctl(wfits->pipe_fd[1], UI_SET_KEYBIT, i) < 0) { + return -3; } } - if (ioctl(wfits->input_fd, UI_SET_KEYBIT, BTN_LEFT) < 0) { - exit(EXIT_FAILURE); + if (ioctl(wfits->pipe_fd[1], UI_SET_KEYBIT, BTN_LEFT) < 0) { + return -4; } - if (ioctl(wfits->input_fd, UI_SET_KEYBIT, BTN_RIGHT) < 0) { - exit(EXIT_FAILURE); + if (ioctl(wfits->pipe_fd[1], UI_SET_KEYBIT, BTN_RIGHT) < 0) { + return -5; } - if (ioctl(wfits->input_fd, UI_SET_KEYBIT, BTN_MIDDLE) < 0) { - exit(EXIT_FAILURE); + if (ioctl(wfits->pipe_fd[1], UI_SET_KEYBIT, BTN_MIDDLE) < 0) { + return -6; } - if (ioctl(wfits->input_fd, UI_SET_EVBIT, EV_ABS) < 0) { - exit(EXIT_FAILURE); + if (ioctl(wfits->pipe_fd[1], UI_SET_EVBIT, EV_ABS) < 0) { + return -7; } - if (ioctl(wfits->input_fd, UI_SET_ABSBIT, ABS_X) < 0) { - exit(EXIT_FAILURE); + if (ioctl(wfits->pipe_fd[1], UI_SET_ABSBIT, ABS_X) < 0) { + return -8; } - if (ioctl(wfits->input_fd, UI_SET_ABSBIT, ABS_Y) < 0) { - exit(EXIT_FAILURE); + if (ioctl(wfits->pipe_fd[1], UI_SET_ABSBIT, ABS_Y) < 0) { + return -9; } + memset(&device, 0, sizeof(device)); snprintf(device.name, UINPUT_MAX_NAME_SIZE, "WFITS INPUT"); device.id.bustype = BUS_USB; @@ -450,13 +496,17 @@ create_input(struct wfits* wfits) device.absmin[ABS_Y] = 0; device.absmax[ABS_Y] = height - 1; - if (write(wfits->input_fd, &device, sizeof(device)) < 0) { - exit(EXIT_FAILURE); + if (write(wfits->pipe_fd[1], &device, sizeof(device)) < 0) { + return -10; } - if (ioctl(wfits->input_fd, UI_DEV_CREATE) < 0) { - exit(EXIT_FAILURE); + if (ioctl(wfits->pipe_fd[1], UI_DEV_CREATE) < 0) { + return -11; } + + wfits->is_pipeston = false; + + return 0; } static void @@ -534,8 +584,15 @@ compositor_destroy(struct wl_listener *listener, void *data) if (not wfits->is_headless) { weston_log("weston-wfits: destroying uinput device\n"); - if (ioctl(wfits->input_fd, UI_DEV_DESTROY) < 0) { - weston_log("weston-wfits: failed to destroy uinput device\n"); + if (not wfits->is_pipeston) { + if (ioctl(wfits->pipe_fd[1], UI_DEV_DESTROY) < 0) { + weston_log("weston-wfits: failed to destroy uinput device\n"); + } + } else { + if (wfits->dev != NULL) + evdev_device_destroy(wfits->dev); + close(wfits->pipe_fd[1]); + close(wfits->pipe_fd[0]); } } } @@ -546,8 +603,21 @@ init_input(void *data) struct wfits *wfits = static_cast<struct wfits*>(data); if (not wfits->is_headless) { - create_input(wfits); - /* sync our input pointer device with weston */ + int err1 = 0, err2 = 0; + + if (err1 = create_input_uinput(wfits)) { + weston_log("weston-wfits: creating pipeston device\n"); + err2 = create_input_pipeston(wfits); + } else { + weston_log("weston-wfits: created uinput device\n"); + } + + if (err1 && err2) { + weston_log("weston-wfits: create uinput failed: %i, " + "pipeston failed: %i\n", err1, err2); + exit(EXIT_FAILURE); + } + /* sync our single input pointer device with weston */ wl_fixed_t cx, cy; get_pointer_xy(wfits, &cx, &cy); move_pointer(wfits, wl_fixed_to_int(cx), wl_fixed_to_int(cy)); -- 1.7.10.4 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel