diff --git a/README.md b/README.md index 0f221e3c..06ef8dcb 100644 --- a/README.md +++ b/README.md @@ -33,3 +33,17 @@ Run these commands: ninja -C build (On FreeBSD, you need to pass an extra flag to prevent a linking error: `meson build -D b_lundef=false`) + +## Running the Reference Compositor + +wlroots comes with a reference compositor called rootston that demonstrates the +features of the library. + +After building, run rootston from a terminal or VT with: + + ./build/rootston/rootston + +Now you can run windows in the compositor from the command line or by +configuring bindings in your +[`rootston.ini`](https://github.com/swaywm/wlroots/blob/master/rootston/rootston.ini.example) +file. diff --git a/backend/drm/util.c b/backend/drm/util.c index 656c070a..c27d7b67 100644 --- a/backend/drm/util.c +++ b/backend/drm/util.c @@ -106,8 +106,15 @@ void parse_edid(struct wlr_output *restrict output, size_t len, const uint8_t *d if (nl) { *nl = '\0'; } + } else if (flag == 0 && data[i + 3] == 0xFF) { + sprintf(output->serial, "%.13s", &data[i + 5]); - break; + // Monitor serial numbers are terminated by newline if they're too + // short + char *nl = strchr(output->serial, '\n'); + if (nl) { + *nl = '\0'; + } } } } diff --git a/backend/libinput/events.c b/backend/libinput/events.c index 5da45c67..3ca41124 100644 --- a/backend/libinput/events.c +++ b/backend/libinput/events.c @@ -66,10 +66,11 @@ static void handle_device_added(struct wlr_libinput_backend *backend, int product = libinput_device_get_id_product(libinput_dev); const char *name = libinput_device_get_name(libinput_dev); struct wl_list *wlr_devices = calloc(1, sizeof(struct wl_list)); - wl_list_init(wlr_devices); if (!wlr_devices) { - goto fail; + wlr_log(L_ERROR, "Allocation failed"); + return; } + wl_list_init(wlr_devices); wlr_log(L_DEBUG, "Added %s [%d:%d]", name, vendor, product); if (libinput_device_has_capability(libinput_dev, LIBINPUT_DEVICE_CAP_KEYBOARD)) { diff --git a/backend/libinput/tablet_tool.c b/backend/libinput/tablet_tool.c index 3caaf3f7..3d5fafc3 100644 --- a/backend/libinput/tablet_tool.c +++ b/backend/libinput/tablet_tool.c @@ -70,6 +70,8 @@ void handle_tablet_tool_axis(struct libinput_event *event, wlr_event.updated_axes |= WLR_TABLET_TOOL_AXIS_WHEEL; wlr_event.wheel_delta = libinput_event_tablet_tool_get_wheel_delta(tevent); } + wlr_log(L_DEBUG, "Tablet tool axis event %d @ %f,%f", + wlr_event.updated_axes, wlr_event.x_mm, wlr_event.y_mm); wl_signal_emit(&wlr_dev->tablet_tool->events.axis, &wlr_event); } diff --git a/backend/session/logind.c b/backend/session/logind.c index 42b48e94..daff75b6 100644 --- a/backend/session/logind.c +++ b/backend/session/logind.c @@ -123,7 +123,7 @@ static bool logind_change_vt(struct wlr_session *base, unsigned vt) { return ret >= 0; } -static bool find_sesion_path(struct logind_session *session) { +static bool find_session_path(struct logind_session *session) { int ret; sd_bus_message *msg = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; @@ -303,7 +303,7 @@ static bool add_signal_matches(struct logind_session *session) { "member='%s'," "path='%s'"; - snprintf(str, sizeof(str), fmt, "Manager", "SesssionRemoved", "/org/freedesktop/login1"); + snprintf(str, sizeof(str), fmt, "Manager", "SessionRemoved", "/org/freedesktop/login1"); ret = sd_bus_add_match(session->bus, NULL, str, session_removed, session); if (ret < 0) { wlr_log(L_ERROR, "Failed to add D-Bus match: %s", strerror(-ret)); @@ -368,7 +368,7 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) { goto error; } - if (!find_sesion_path(session)) { + if (!find_session_path(session)) { sd_bus_unref(session->bus); goto error; } diff --git a/backend/session/session.c b/backend/session/session.c index b14ca4d0..657558fd 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -249,7 +249,7 @@ static size_t explicit_find_gpus(struct wlr_session *session, } } while ((ptr = strtok_r(NULL, ":", &save))); - free(ptr); + free(gpus); return i; } @@ -257,7 +257,7 @@ static size_t explicit_find_gpus(struct wlr_session *session, * If it's not found, it returns the first valid GPU it finds. */ size_t wlr_session_find_gpus(struct wlr_session *session, - size_t ret_len, int ret[static ret_len]) { + size_t ret_len, int *ret) { const char *explicit = getenv("WLR_DRM_DEVICES"); if (explicit) { return explicit_find_gpus(session, ret_len, ret, explicit); diff --git a/backend/wayland/backend.c b/backend/wayland/backend.c index 532935b8..1801f3e0 100644 --- a/backend/wayland/backend.c +++ b/backend/wayland/backend.c @@ -12,10 +12,15 @@ #include "backend/wayland.h" #include "xdg-shell-unstable-v6-client-protocol.h" - static int dispatch_events(int fd, uint32_t mask, void *data) { struct wlr_wl_backend *backend = data; int count = 0; + + if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) { + wl_display_terminate(backend->local_display); + return 0; + } + if (mask & WL_EVENT_READABLE) { count = wl_display_dispatch(backend->remote_display); } @@ -36,7 +41,7 @@ static bool wlr_wl_backend_start(struct wlr_backend *_backend) { wlr_log(L_INFO, "Initializating wayland backend"); wlr_wl_registry_poll(backend); - if (!(backend->compositor) || (!(backend->shell))) { + if (!backend->compositor || !backend->shell) { wlr_log_errno(L_ERROR, "Could not obtain retrieve required globals"); return false; } @@ -49,10 +54,9 @@ static bool wlr_wl_backend_start(struct wlr_backend *_backend) { struct wl_event_loop *loop = wl_display_get_event_loop(backend->local_display); int fd = wl_display_get_fd(backend->remote_display); - int events = WL_EVENT_READABLE | WL_EVENT_ERROR | - WL_EVENT_HANGUP; + int events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP; backend->remote_display_src = wl_event_loop_add_fd(loop, fd, events, - dispatch_events, backend); + dispatch_events, backend); wl_event_source_check(backend->remote_display_src); return true; diff --git a/backend/wayland/output.c b/backend/wayland/output.c index 90f8b39a..c4301617 100644 --- a/backend/wayland/output.c +++ b/backend/wayland/output.c @@ -249,7 +249,7 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *_backend) { wlr_output_init(&output->wlr_output, &backend->backend, &output_impl); struct wlr_output *wlr_output = &output->wlr_output; - wlr_output_update_size(wlr_output, 640, 480); + wlr_output_update_size(wlr_output, 1280, 720); strncpy(wlr_output->make, "wayland", sizeof(wlr_output->make)); strncpy(wlr_output->model, "wayland", sizeof(wlr_output->model)); snprintf(wlr_output->name, sizeof(wlr_output->name), "WL-%d", diff --git a/backend/wayland/wl_seat.c b/backend/wayland/wl_seat.c index deed215e..a2da8df5 100644 --- a/backend/wayland/wl_seat.c +++ b/backend/wayland/wl_seat.c @@ -90,7 +90,7 @@ static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer, struct wlr_event_pointer_axis wlr_event; wlr_event.device = dev; - wlr_event.delta = value; + wlr_event.delta = wl_fixed_to_double(value); wlr_event.orientation = axis; wlr_event.time_msec = time; wlr_event.source = wlr_wl_pointer->axis_source; diff --git a/backend/x11/backend.c b/backend/x11/backend.c index 97b0dd8c..b798daf6 100644 --- a/backend/x11/backend.c +++ b/backend/x11/backend.c @@ -155,9 +155,14 @@ static bool handle_x11_event(struct wlr_x11_backend *x11, xcb_generic_event_t *e static int x11_event(int fd, uint32_t mask, void *data) { struct wlr_x11_backend *x11 = data; + + if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) { + wl_display_terminate(x11->wl_display); + return 0; + } + xcb_generic_event_t *e; bool quit = false; - while (!quit && (e = xcb_poll_for_event(x11->xcb_conn))) { quit = handle_x11_event(x11, e); free(e); @@ -205,7 +210,8 @@ struct wlr_backend *wlr_x11_backend_create(struct wl_display *display, int fd = xcb_get_file_descriptor(x11->xcb_conn); struct wl_event_loop *ev = wl_display_get_event_loop(display); - x11->event_source = wl_event_loop_add_fd(ev, fd, WL_EVENT_READABLE, x11_event, x11); + int events = WL_EVENT_READABLE | WL_EVENT_ERROR | WL_EVENT_HANGUP; + x11->event_source = wl_event_loop_add_fd(ev, fd, events, x11_event, x11); if (!x11->event_source) { wlr_log(L_ERROR, "Could not create event source"); goto error_x11; diff --git a/examples/multi-pointer.c b/examples/multi-pointer.c index e29a69db..f1bcebc7 100644 --- a/examples/multi-pointer.c +++ b/examples/multi-pointer.c @@ -86,7 +86,7 @@ static void handle_output_add(struct output_state *ostate) { struct wlr_xcursor_image *image = sample->xcursor->images[0]; wlr_cursor_set_image(cursor->cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y); + image->width, image->height, image->hotspot_x, image->hotspot_y, 0); wlr_cursor_warp(cursor->cursor, NULL, cursor->cursor->x, cursor->cursor->y); @@ -150,7 +150,7 @@ static void handle_input_add(struct compositor_state *state, struct wlr_xcursor_image *image = sample->xcursor->images[0]; wlr_cursor_set_image(cursor->cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y); + image->width, image->height, image->hotspot_x, image->hotspot_y, 0); wl_list_insert(&sample->cursors, &cursor->link); } diff --git a/examples/pointer.c b/examples/pointer.c index 1bcd7349..476cc617 100644 --- a/examples/pointer.c +++ b/examples/pointer.c @@ -110,7 +110,7 @@ static void handle_output_add(struct output_state *ostate) { struct wlr_xcursor_image *image = sample->xcursor->images[0]; wlr_cursor_set_image(sample->cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y); + image->width, image->height, image->hotspot_x, image->hotspot_y, 0); wlr_cursor_warp(sample->cursor, NULL, sample->cursor->x, sample->cursor->y); } @@ -321,7 +321,7 @@ int main(int argc, char *argv[]) { struct wlr_xcursor_image *image = state.xcursor->images[0]; wlr_cursor_set_image(state.cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y); + image->width, image->height, image->hotspot_x, image->hotspot_y, 0); compositor_init(&compositor); if (!wlr_backend_start(compositor.backend)) { diff --git a/examples/screenshot.c b/examples/screenshot.c index 2a3b74aa..fc7f3cb3 100644 --- a/examples/screenshot.c +++ b/examples/screenshot.c @@ -187,7 +187,10 @@ static void write_image(const char *filename, int width, int height) { sprintf(size, "%dx%d+0", width, height); int fd[2]; - pipe(fd); + if (pipe(fd) != 0) { + fprintf(stderr, "cannot create pipe: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } pid_t child = fork(); if (child < 0) { @@ -195,7 +198,10 @@ static void write_image(const char *filename, int width, int height) { exit(EXIT_FAILURE); } else if (child != 0) { close(fd[0]); - write(fd[1], data, buffer_stride * height); + if (write(fd[1], data, buffer_stride * height) < 0) { + fprintf(stderr, "write() failed: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } close(fd[1]); free(data); waitpid(child, NULL, 0); diff --git a/include/rootston/config.h b/include/rootston/config.h index 75c04619..71ee61c7 100644 --- a/include/rootston/config.h +++ b/include/rootston/config.h @@ -2,12 +2,12 @@ #define _ROOTSTON_CONFIG_H #include #include -#include -struct output_config { +struct roots_output_config { char *name; enum wl_output_transform transform; int x, y; + int scale; struct wl_list link; struct { int width, height; @@ -15,14 +15,15 @@ struct output_config { } mode; }; -struct device_config { +struct roots_device_config { char *name; char *mapped_output; struct wlr_box *mapped_box; + char *seat; struct wl_list link; }; -struct binding_config { +struct roots_binding_config { uint32_t modifiers; xkb_keysym_t *keysyms; size_t keysyms_len; @@ -30,7 +31,7 @@ struct binding_config { struct wl_list link; }; -struct keyboard_config { +struct roots_keyboard_config { char *name; uint32_t meta_key; char *rules; @@ -43,7 +44,7 @@ struct keyboard_config { struct roots_config { bool xwayland; - // TODO: Multiple cursors, multiseat + struct { char *mapped_output; struct wlr_box *mapped_box; @@ -57,29 +58,37 @@ struct roots_config { char *startup_cmd; }; -struct roots_config *parse_args(int argc, char *argv[]); +/** + * Create a roots config from the given command line arguments. Command line + * arguments can specify the location of the config file. If it is not + * specified, the default location will be used. + */ +struct roots_config *roots_config_create_from_args(int argc, char *argv[]); +/** + * Destroy the config and free its resources. + */ void roots_config_destroy(struct roots_config *config); /** * Get configuration for the output. If the output is not configured, returns * NULL. */ -struct output_config *config_get_output(struct roots_config *config, +struct roots_output_config *roots_config_get_output(struct roots_config *config, struct wlr_output *output); /** * Get configuration for the device. If the device is not configured, returns * NULL. */ -struct device_config *config_get_device(struct roots_config *config, +struct roots_device_config *roots_config_get_device(struct roots_config *config, struct wlr_input_device *device); /** * Get configuration for the keyboard. If the keyboard is not configured, * returns NULL. A NULL device returns the default config for keyboards. */ -struct keyboard_config *config_get_keyboard(struct roots_config *config, - struct wlr_input_device *device); +struct roots_keyboard_config *roots_config_get_keyboard( + struct roots_config *config, struct wlr_input_device *device); #endif diff --git a/include/rootston/cursor.h b/include/rootston/cursor.h new file mode 100644 index 00000000..f49b6439 --- /dev/null +++ b/include/rootston/cursor.h @@ -0,0 +1,103 @@ +#ifndef _ROOTSTON_CURSOR_H +#define _ROOTSTON_CURSOR_H + +#include "rootston/seat.h" + +enum roots_cursor_mode { + ROOTS_CURSOR_PASSTHROUGH = 0, + ROOTS_CURSOR_MOVE = 1, + ROOTS_CURSOR_RESIZE = 2, + ROOTS_CURSOR_ROTATE = 3, +}; + +enum roots_cursor_resize_edge { + ROOTS_CURSOR_RESIZE_EDGE_TOP = 1, + ROOTS_CURSOR_RESIZE_EDGE_BOTTOM = 2, + ROOTS_CURSOR_RESIZE_EDGE_LEFT = 4, + ROOTS_CURSOR_RESIZE_EDGE_RIGHT = 8, +}; + +struct roots_input_event { + uint32_t serial; + struct wlr_cursor *cursor; + struct wlr_input_device *device; +}; + +struct roots_cursor { + struct roots_seat *seat; + struct wlr_cursor *cursor; + + enum roots_cursor_mode mode; + + // state from input (review if this is necessary) + struct wlr_xcursor_manager *xcursor_manager; + struct wlr_seat *wl_seat; + struct wl_client *cursor_client; + int offs_x, offs_y; + int view_x, view_y, view_width, view_height; + float view_rotation; + uint32_t resize_edges; + // Ring buffer of input events that could trigger move/resize/rotate + int input_events_idx; + struct wl_list touch_points; + struct roots_input_event input_events[16]; + + struct wl_listener motion; + struct wl_listener motion_absolute; + struct wl_listener button; + struct wl_listener axis; + + struct wl_listener touch_down; + struct wl_listener touch_up; + struct wl_listener touch_motion; + + struct wl_listener tool_axis; + struct wl_listener tool_tip; + + struct wl_listener pointer_grab_begin; + struct wl_listener pointer_grab_end; + + struct wl_listener request_set_cursor; +}; + +struct roots_cursor *roots_cursor_create(struct roots_seat *seat); + +void roots_cursor_destroy(struct roots_cursor *cursor); + +void roots_cursor_handle_motion(struct roots_cursor *cursor, + struct wlr_event_pointer_motion *event); + +void roots_cursor_handle_motion_absolute(struct roots_cursor *cursor, + struct wlr_event_pointer_motion_absolute *event); + +void roots_cursor_handle_button(struct roots_cursor *cursor, + struct wlr_event_pointer_button *event); + +void roots_cursor_handle_axis(struct roots_cursor *cursor, + struct wlr_event_pointer_axis *event); + +void roots_cursor_handle_touch_down(struct roots_cursor *cursor, + struct wlr_event_touch_down *event); + +void roots_cursor_handle_touch_up(struct roots_cursor *cursor, + struct wlr_event_touch_up *event); + +void roots_cursor_handle_touch_motion(struct roots_cursor *cursor, + struct wlr_event_touch_motion *event); + +void roots_cursor_handle_tool_axis(struct roots_cursor *cursor, + struct wlr_event_tablet_tool_axis *event); + +void roots_cursor_handle_tool_tip(struct roots_cursor *cursor, + struct wlr_event_tablet_tool_tip *event); + +void roots_cursor_handle_request_set_cursor(struct roots_cursor *cursor, + struct wlr_seat_pointer_request_set_cursor_event *event); + +void roots_cursor_handle_pointer_grab_begin(struct roots_cursor *cursor, + struct wlr_seat_pointer_grab *grab); + +void roots_cursor_handle_pointer_grab_end(struct roots_cursor *cursor, + struct wlr_seat_pointer_grab *grab); + +#endif diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index 376412fb..b809db43 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -31,6 +32,7 @@ struct roots_desktop { struct roots_config *config; struct wlr_output_layout *layout; + struct wlr_xcursor_manager *xcursor_manager; struct wlr_compositor *compositor; struct wlr_wl_shell *wl_shell; diff --git a/include/rootston/input.h b/include/rootston/input.h index 20b73c8a..0af48577 100644 --- a/include/rootston/input.h +++ b/include/rootston/input.h @@ -1,171 +1,31 @@ #ifndef _ROOTSTON_INPUT_H #define _ROOTSTON_INPUT_H -#include #include #include #include #include -#include +#include "rootston/cursor.h" #include "rootston/config.h" #include "rootston/view.h" #include "rootston/server.h" -#define ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP 32 - -struct roots_keyboard { - struct roots_input *input; - struct wlr_input_device *device; - struct wl_listener key; - struct wl_listener modifiers; - struct wl_list link; - - xkb_keysym_t pressed_keysyms[ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP]; -}; - -struct roots_pointer { - struct roots_input *input; - struct wlr_input_device *device; - struct wl_list link; -}; - -struct roots_touch { - struct roots_input *input; - struct wlr_input_device *device; - struct wl_list link; -}; - -// TODO: tablet pad -struct roots_tablet_tool { - struct roots_input *input; - struct wlr_input_device *device; - struct wl_listener axis; - struct wl_listener proximity; - struct wl_listener tip; - struct wl_listener button; - struct wl_list link; -}; - -enum roots_cursor_mode { - ROOTS_CURSOR_PASSTHROUGH = 0, - ROOTS_CURSOR_MOVE = 1, - ROOTS_CURSOR_RESIZE = 2, - ROOTS_CURSOR_ROTATE = 3, -}; - -enum roots_cursor_resize_edge { - ROOTS_CURSOR_RESIZE_EDGE_TOP = 1, - ROOTS_CURSOR_RESIZE_EDGE_BOTTOM = 2, - ROOTS_CURSOR_RESIZE_EDGE_LEFT = 4, - ROOTS_CURSOR_RESIZE_EDGE_RIGHT = 8, -}; - -struct roots_input_event { - uint32_t serial; - struct wlr_cursor *cursor; - struct wlr_input_device *device; -}; - -struct roots_drag_icon { - struct wlr_surface *surface; - struct wl_list link; // roots_input::drag_icons - bool mapped; - - int32_t sx; - int32_t sy; - - struct wl_listener surface_destroy; - struct wl_listener surface_commit; -}; - -struct roots_touch_point { - struct roots_touch *device; - int32_t slot; - double x, y; - struct wl_list link; -}; - struct roots_input { struct roots_config *config; struct roots_server *server; - // TODO: multiseat, multicursor - struct wlr_cursor *cursor; - struct wlr_xcursor_theme *xcursor_theme; - struct wlr_seat *wl_seat; - struct wl_list drag_icons; - struct wl_client *cursor_client; - - enum roots_cursor_mode mode; - struct roots_view *active_view; - int offs_x, offs_y; - int view_x, view_y, view_width, view_height; - float view_rotation; - uint32_t resize_edges; - - // Ring buffer of input events that could trigger move/resize/rotate - int input_events_idx; - struct roots_input_event input_events[16]; - - struct wl_list keyboards; - struct wl_list pointers; - struct wl_list touch; - struct wl_list tablet_tools; - struct wl_listener input_add; struct wl_listener input_remove; - struct wl_listener cursor_motion; - struct wl_listener cursor_motion_absolute; - struct wl_listener cursor_button; - struct wl_listener cursor_axis; - - struct wl_listener cursor_touch_down; - struct wl_listener cursor_touch_up; - struct wl_listener cursor_touch_motion; - - struct wl_listener cursor_tool_axis; - struct wl_listener cursor_tool_tip; - - struct wl_listener pointer_grab_begin; - struct wl_list touch_points; - - struct wl_listener pointer_grab_end; - - struct wl_listener request_set_cursor; + struct wl_list seats; }; struct roots_input *input_create(struct roots_server *server, struct roots_config *config); void input_destroy(struct roots_input *input); -void pointer_add(struct wlr_input_device *device, struct roots_input *input); -void pointer_remove(struct wlr_input_device *device, struct roots_input *input); -void keyboard_add(struct wlr_input_device *device, struct roots_input *input); -void keyboard_remove(struct wlr_input_device *device, struct roots_input *input); -void touch_add(struct wlr_input_device *device, struct roots_input *input); -void touch_remove(struct wlr_input_device *device, struct roots_input *input); -void tablet_tool_add(struct wlr_input_device *device, struct roots_input *input); -void tablet_tool_remove(struct wlr_input_device *device, struct roots_input *input); +struct roots_seat *input_seat_from_wlr_seat(struct roots_input *input, + struct wlr_seat *seat); -void cursor_initialize(struct roots_input *input); -void cursor_load_config(struct roots_config *config, - struct wlr_cursor *cursor, - struct roots_input *input, - struct roots_desktop *desktop); -const struct roots_input_event *get_input_event(struct roots_input *input, - uint32_t serial); -void view_begin_move(struct roots_input *input, struct wlr_cursor *cursor, - struct roots_view *view); -void view_begin_resize(struct roots_input *input, struct wlr_cursor *cursor, - struct roots_view *view, uint32_t edges); - -struct wlr_xcursor *get_default_xcursor(struct wlr_xcursor_theme *theme); -struct wlr_xcursor *get_move_xcursor(struct wlr_xcursor_theme *theme); -struct wlr_xcursor *get_resize_xcursor(struct wlr_xcursor_theme *theme, - uint32_t edges); -struct wlr_xcursor *get_rotate_xcursor(struct wlr_xcursor_theme *theme); - -void set_view_focus(struct roots_input *input, struct roots_desktop *desktop, - struct roots_view *view); +bool input_view_has_focus(struct roots_input *input, struct roots_view *view); #endif diff --git a/include/rootston/keyboard.h b/include/rootston/keyboard.h new file mode 100644 index 00000000..39650d7c --- /dev/null +++ b/include/rootston/keyboard.h @@ -0,0 +1,33 @@ +#ifndef _ROOTSTON_KEYBOARD_H +#define _ROOTSTON_KEYBOARD_H + +#include +#include "rootston/input.h" + +#define ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP 32 + +struct roots_keyboard { + struct roots_input *input; + struct roots_seat *seat; + struct wlr_input_device *device; + struct roots_keyboard_config *config; + struct wl_list link; + + struct wl_listener keyboard_key; + struct wl_listener keyboard_modifiers; + + xkb_keysym_t pressed_keysyms_translated[ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP]; + xkb_keysym_t pressed_keysyms_raw[ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP]; +}; + +struct roots_keyboard *roots_keyboard_create(struct wlr_input_device *device, + struct roots_input *input); + +void roots_keyboard_destroy(struct roots_keyboard *keyboard); + +void roots_keyboard_handle_key(struct roots_keyboard *keyboard, + struct wlr_event_keyboard_key *event); + +void roots_keyboard_handle_modifiers(struct roots_keyboard *r_keyboard); + +#endif diff --git a/include/rootston/seat.h b/include/rootston/seat.h new file mode 100644 index 00000000..bef515a4 --- /dev/null +++ b/include/rootston/seat.h @@ -0,0 +1,88 @@ +#ifndef _ROOTSTON_SEAT_H +#define _ROOTSTON_SEAT_H +#include +#include "rootston/input.h" +#include "rootston/keyboard.h" + +struct roots_drag_icon { + struct wlr_surface *surface; + struct wl_list link; // roots_seat::drag_icons + bool mapped; + + int32_t sx; + int32_t sy; + + struct wl_listener surface_destroy; + struct wl_listener surface_commit; +}; + +struct roots_seat { + struct roots_input *input; + struct wlr_seat *seat; + struct roots_cursor *cursor; + struct wl_list link; + struct wl_list drag_icons; + + struct roots_view *focus; + + struct wl_list keyboards; + struct wl_list pointers; + struct wl_list touch; + struct wl_list tablet_tools; +}; + +struct roots_pointer { + struct roots_seat *seat; + struct wlr_input_device *device; + struct wl_list link; +}; + +struct roots_touch { + struct roots_seat *seat; + struct wlr_input_device *device; + struct wl_list link; +}; + +struct roots_touch_point { + struct roots_touch *device; + int32_t slot; + double x, y; + struct wl_list link; +}; + +struct roots_tablet_tool { + struct roots_seat *seat; + struct wlr_input_device *device; + struct wl_listener axis; + struct wl_listener proximity; + struct wl_listener tip; + struct wl_listener button; + struct wl_list link; +}; + +struct roots_seat *roots_seat_create(struct roots_input *input, char *name); + +void roots_seat_destroy(struct roots_seat *seat); + +void roots_seat_add_device(struct roots_seat *seat, + struct wlr_input_device *device); + +void roots_seat_remove_device(struct roots_seat *seat, + struct wlr_input_device *device); + +void roots_seat_configure_cursor(struct roots_seat *seat); + +void roots_seat_configure_xcursor(struct roots_seat *seat); + +bool roots_seat_has_meta_pressed(struct roots_seat *seat); + +void roots_seat_focus_view(struct roots_seat *seat, struct roots_view *view); + +void roots_seat_begin_move(struct roots_seat *seat, struct roots_view *view); + +void roots_seat_begin_resize(struct roots_seat *seat, struct roots_view *view, + uint32_t edges); + +void roots_seat_begin_rotate(struct roots_seat *seat, struct roots_view *view); + +#endif diff --git a/include/rootston/view.h b/include/rootston/view.h index adfbe6e0..9df2ee08 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -11,9 +11,10 @@ struct roots_wl_shell_surface { // TODO: Maybe destroy listener should go in roots_view struct wl_listener destroy; - struct wl_listener ping_timeout; struct wl_listener request_move; struct wl_listener request_resize; + struct wl_listener request_set_maximized; + struct wl_listener set_state; struct wl_listener surface_commit; }; @@ -26,6 +27,7 @@ struct roots_xdg_surface_v6 { struct wl_listener destroy; struct wl_listener request_move; struct wl_listener request_resize; + struct wl_listener request_maximize; struct { bool needs_move; @@ -42,6 +44,7 @@ struct roots_xwayland_surface { struct wl_listener request_configure; struct wl_listener request_move; struct wl_listener request_resize; + struct wl_listener request_maximize; struct wl_listener map_notify; struct wl_listener unmap_notify; }; @@ -54,8 +57,17 @@ enum roots_view_type { struct roots_view { struct roots_desktop *desktop; + double x, y; float rotation; + + bool maximized; + struct { + double x, y; + uint32_t width, height; + float rotation; + } saved; + // TODO: Something for roots-enforced width/height enum roots_view_type type; union { @@ -73,25 +85,28 @@ struct roots_view { #endif }; struct wlr_surface *wlr_surface; + // TODO: This would probably be better as a field that's updated on a // configure event from the xdg_shell // If not then this should follow the typical type/impl pattern we use // elsewhere - void (*get_size)(struct roots_view *view, struct wlr_box *box); + void (*get_size)(const struct roots_view *view, struct wlr_box *box); void (*activate)(struct roots_view *view, bool active); void (*move)(struct roots_view *view, double x, double y); void (*resize)(struct roots_view *view, uint32_t width, uint32_t height); void (*move_resize)(struct roots_view *view, double x, double y, uint32_t width, uint32_t height); + void (*maximize)(struct roots_view *view, bool maximized); void (*close)(struct roots_view *view); }; -void view_get_size(struct roots_view *view, struct wlr_box *box); +void view_get_box(const struct roots_view *view, struct wlr_box *box); void view_activate(struct roots_view *view, bool active); void view_move(struct roots_view *view, double x, double y); void view_resize(struct roots_view *view, uint32_t width, uint32_t height); void view_move_resize(struct roots_view *view, double x, double y, uint32_t width, uint32_t height); +void view_maximize(struct roots_view *view, bool maximized); void view_close(struct roots_view *view); bool view_center(struct roots_view *view); void view_setup(struct roots_view *view); diff --git a/include/rootston/xcursor.h b/include/rootston/xcursor.h new file mode 100644 index 00000000..bc00f79c --- /dev/null +++ b/include/rootston/xcursor.h @@ -0,0 +1,14 @@ +#ifndef _ROOTSTON_XCURSOR_H +#define _ROOTSTON_XCURSOR_H + +#include + +#define ROOTS_XCURSOR_SIZE 16 + +#define ROOTS_XCURSOR_DEFAULT "left_ptr" +#define ROOTS_XCURSOR_MOVE "grabbing" +#define ROOTS_XCURSOR_ROTATE "grabbing" + +const char *roots_xcursor_get_resize_name(uint32_t edges); + +#endif diff --git a/include/wlr/backend/session.h b/include/wlr/backend/session.h index 94002bc5..5c822ea9 100644 --- a/include/wlr/backend/session.h +++ b/include/wlr/backend/session.h @@ -79,6 +79,6 @@ void wlr_session_signal_add(struct wlr_session *session, int fd, bool wlr_session_change_vt(struct wlr_session *session, unsigned vt); size_t wlr_session_find_gpus(struct wlr_session *session, - size_t ret_len, int ret[static ret_len]); + size_t ret_len, int *ret); #endif diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 1aac2b94..0db32eb2 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -6,7 +6,6 @@ #include #include #include -#include struct wlr_cursor_state; @@ -60,9 +59,22 @@ void wlr_cursor_warp_absolute(struct wlr_cursor *cur, void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, double delta_x, double delta_y); +/** + * Set the cursor image. stride is given in bytes. If pixels is NULL, hides the + * cursor. + * + * If scale isn't zero, the image is only set on outputs having the provided + * scale. + */ void wlr_cursor_set_image(struct wlr_cursor *cur, const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, - int32_t hotspot_y); + int32_t hotspot_y, uint32_t scale); + +/** + * Set the cursor surface. The surface can be committed to update the cursor + * image. The surface position is substracted from the hotspot. A NULL surface + * commit hides the cursor. + */ void wlr_cursor_set_surface(struct wlr_cursor *cur, struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y); diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index 691e2df8..f45c15a2 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -74,6 +74,11 @@ struct wlr_drag { struct wlr_data_device_manager *wlr_data_device_manager_create( struct wl_display *display); +/** + * Destroys a wlr_data_device_manager and removes its wl_data_device_manager global. + */ +void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager); + /** * Creates a new wl_data_offer if there is a wl_data_source currently set as * the seat selection and sends it to the seat client, followed by the diff --git a/include/wlr/types/wlr_keyboard.h b/include/wlr/types/wlr_keyboard.h index af837ff5..e2d50b03 100644 --- a/include/wlr/types/wlr_keyboard.h +++ b/include/wlr/types/wlr_keyboard.h @@ -28,6 +28,8 @@ enum wlr_keyboard_modifier { WLR_MODIFIER_MOD5 = 128, }; +#define WLR_KEYBOARD_KEYS_CAP 32 + struct wlr_keyboard_impl; struct wlr_keyboard { @@ -41,6 +43,7 @@ struct wlr_keyboard { xkb_led_index_t led_indexes[WLR_LED_COUNT]; xkb_mod_index_t mod_indexes[WLR_MODIFIER_COUNT]; + uint32_t keycodes[WLR_KEYBOARD_KEYS_CAP]; struct { xkb_mod_mask_t depressed; xkb_mod_mask_t latched; diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index e6323f9c..cf000019 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -14,7 +14,7 @@ struct wlr_output_mode { struct wlr_output_cursor { struct wlr_output *output; - int32_t x, y; + double x, y; bool enabled; uint32_t width, height; int32_t hotspot_x, hotspot_y; @@ -43,6 +43,7 @@ struct wlr_output { char name[16]; char make[48]; char model[16]; + char serial[16]; uint32_t scale; int32_t width, height; int32_t phys_width, phys_height; // mm @@ -95,7 +96,8 @@ bool wlr_output_cursor_set_image(struct wlr_output_cursor *cursor, int32_t hotspot_x, int32_t hotspot_y); void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, struct wlr_surface *surface, int32_t hotspot_x, int32_t hotspot_y); -bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, int x, int y); +bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, + double x, double y); void wlr_output_cursor_destroy(struct wlr_output_cursor *cursor); #endif diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index b8b467d2..a5f00402 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -1,6 +1,6 @@ #ifndef WLR_TYPES_WLR_SEAT_H #define WLR_TYPES_WLR_SEAT_H - +#include #include #include #include @@ -45,9 +45,7 @@ struct wlr_keyboard_grab_interface { struct wlr_surface *surface); void (*key)(struct wlr_seat_keyboard_grab *grab, uint32_t time, uint32_t key, uint32_t state); - void (*modifiers)(struct wlr_seat_keyboard_grab *grab, - uint32_t mods_depressed, uint32_t mods_latched, - uint32_t mods_locked, uint32_t group); + void (*modifiers)(struct wlr_seat_keyboard_grab *grab); void (*cancel)(struct wlr_seat_keyboard_grab *grab); }; @@ -111,6 +109,7 @@ struct wlr_seat { struct wl_list clients; char *name; uint32_t capabilities; + struct timespec last_event; struct wlr_data_device *data_device; // TODO needed? struct wlr_data_source *selection_source; @@ -296,17 +295,13 @@ void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time, * Send the modifier state to focused keyboard resources. Compositors should use * `wlr_seat_keyboard_notify_modifiers()` to respect any keyboard grabs. */ -void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat, - uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, - uint32_t group); +void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat); /** * Notify the seat that the modifiers for the keyboard have changed. Defers to * any keyboard grabs. */ -void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat, - uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, - uint32_t group); +void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat); /** * Notify the seat that the keyboard focus has changed and request it to be the diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h index ea4184aa..cea53109 100644 --- a/include/wlr/types/wlr_surface.h +++ b/include/wlr/types/wlr_surface.h @@ -1,10 +1,10 @@ #ifndef WLR_TYPES_WLR_SURFACE_H #define WLR_TYPES_WLR_SURFACE_H - #include #include #include #include +#include struct wlr_frame_callback { struct wl_resource *resource; @@ -135,4 +135,11 @@ struct wlr_surface *wlr_surface_get_main_surface(struct wlr_surface *surface); */ struct wlr_subsurface *wlr_surface_subsurface_at(struct wlr_surface *surface, double sx, double sy, double *sub_x, double *sub_y); + +void wlr_surface_send_enter(struct wlr_surface *surface, + struct wlr_output *output); + +void wlr_surface_send_leave(struct wlr_surface *surface, + struct wlr_output *output); + #endif diff --git a/include/wlr/types/wlr_wl_shell.h b/include/wlr/types/wlr_wl_shell.h index 4e814817..24936a34 100644 --- a/include/wlr/types/wlr_wl_shell.h +++ b/include/wlr/types/wlr_wl_shell.h @@ -42,6 +42,8 @@ struct wlr_wl_shell_popup_grab { enum wlr_wl_shell_surface_state { WLR_WL_SHELL_SURFACE_STATE_NONE, WLR_WL_SHELL_SURFACE_STATE_TOPLEVEL, + WLR_WL_SHELL_SURFACE_STATE_MAXIMIZED, + WLR_WL_SHELL_SURFACE_STATE_FULLSCREEN, WLR_WL_SHELL_SURFACE_STATE_TRANSIENT, WLR_WL_SHELL_SURFACE_STATE_POPUP, }; @@ -93,14 +95,14 @@ struct wlr_wl_shell_surface { struct wlr_wl_shell_surface_move_event { struct wl_client *client; struct wlr_wl_shell_surface *surface; - struct wlr_seat_handle *seat_handle; + struct wlr_seat_client *seat; uint32_t serial; }; struct wlr_wl_shell_surface_resize_event { struct wl_client *client; struct wlr_wl_shell_surface *surface; - struct wlr_seat_handle *seat_handle; + struct wlr_seat_client *seat; uint32_t serial; enum wl_shell_surface_resize edges; }; diff --git a/include/wlr/types/wlr_xcursor_manager.h b/include/wlr/types/wlr_xcursor_manager.h new file mode 100644 index 00000000..c78a6e8d --- /dev/null +++ b/include/wlr/types/wlr_xcursor_manager.h @@ -0,0 +1,53 @@ +#ifndef WLR_TYPES_WLR_XCURSOR_MANAGER_H +#define WLR_TYPES_WLR_XCURSOR_MANAGER_H + +#include +#include +#include + +/** + * A scaled XCursor theme. + */ +struct wlr_xcursor_manager_theme { + uint32_t scale; + struct wlr_xcursor_theme *theme; + struct wl_list link; +}; + +/** + * Manage multiple XCursor themes with different scales and set `wlr_cursor` + * images. + * + * This manager can be used to display cursor images on multiple outputs having + * different scale factors. + */ +struct wlr_xcursor_manager { + char *name; + uint32_t size; + struct wl_list scaled_themes; // wlr_xcursor_manager_theme::link +}; + +/** + * Create a new XCursor manager. After initialization, scaled themes need to be + * loaded with `wlr_xcursor_manager_load`. `size` is the unscaled cursor theme + * size. + */ +struct wlr_xcursor_manager *wlr_xcursor_manager_create(const char *name, + uint32_t size); + +void wlr_xcursor_manager_destroy(struct wlr_xcursor_manager *manager); + +int wlr_xcursor_manager_load(struct wlr_xcursor_manager *manager, + uint32_t scale); + +struct wlr_xcursor *wlr_xcursor_manager_get_xcursor( + struct wlr_xcursor_manager *manager, const char *name, uint32_t scale); + +/** + * Set a `wlr_cursor` image. The manager uses all currently loaded scaled + * themes. + */ +void wlr_xcursor_manager_set_cursor_image(struct wlr_xcursor_manager *manager, + const char *name, struct wlr_cursor *cursor); + +#endif diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index b0de41e2..e3982003 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -126,6 +126,8 @@ struct wlr_xdg_surface_v6 { struct wl_signal ack_configure; struct wl_signal ping_timeout; + struct wl_signal request_maximize; + struct wl_signal request_fullscreen; struct wl_signal request_minimize; struct wl_signal request_move; struct wl_signal request_resize; @@ -138,14 +140,14 @@ struct wlr_xdg_surface_v6 { struct wlr_xdg_toplevel_v6_move_event { struct wl_client *client; struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_handle *seat_handle; + struct wlr_seat_client *seat; uint32_t serial; }; struct wlr_xdg_toplevel_v6_resize_event { struct wl_client *client; struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_handle *seat_handle; + struct wlr_seat_client *seat; uint32_t serial; uint32_t edges; }; @@ -153,7 +155,7 @@ struct wlr_xdg_toplevel_v6_resize_event { struct wlr_xdg_toplevel_v6_show_window_menu_event { struct wl_client *client; struct wlr_xdg_surface_v6 *surface; - struct wlr_seat_handle *seat_handle; + struct wlr_seat_client *seat; uint32_t serial; uint32_t x; uint32_t y; @@ -207,6 +209,12 @@ void wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface, */ void wlr_xdg_toplevel_v6_send_close(struct wlr_xdg_surface_v6 *surface); +/** + * Compute the popup position in surface-local coordinates. + */ +void wlr_xdg_surface_v6_popup_get_position(struct wlr_xdg_surface_v6 *surface, + double *popup_sx, double *popup_sy); + /** * Find a popup within this surface at the surface-local coordinates. Returns * the popup and coordinates in the topmost surface coordinate system or NULL if diff --git a/include/wlr/xcursor.h b/include/wlr/xcursor.h index c12d5405..b6362b06 100644 --- a/include/wlr/xcursor.h +++ b/include/wlr/xcursor.h @@ -61,7 +61,7 @@ struct wlr_xcursor_theme *wlr_xcursor_theme_load(const char *name, int size); void wlr_xcursor_theme_destroy(struct wlr_xcursor_theme *theme); struct wlr_xcursor *wlr_xcursor_theme_get_cursor( - struct wlr_xcursor_theme *theme, const char *name); + struct wlr_xcursor_theme *theme, const char *name); int wlr_xcursor_frame(struct wlr_xcursor *cursor, uint32_t time); diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index bea97394..6518b703 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -29,6 +29,7 @@ struct wlr_xwayland { struct wlr_xwayland_cursor *cursor; struct { + struct wl_signal ready; struct wl_signal new_surface; } events; diff --git a/rootston/config.c b/rootston/config.c index dc7a4b1d..727b52d0 100644 --- a/rootston/config.c +++ b/rootston/config.c @@ -13,6 +13,7 @@ #include #include "rootston/config.h" #include "rootston/input.h" +#include "rootston/keyboard.h" #include "rootston/ini.h" static void usage(const char *name, int ret) { @@ -114,7 +115,8 @@ static uint32_t parse_modifier(const char *symname) { void add_binding_config(struct wl_list *bindings, const char* combination, const char* command) { - struct binding_config *bc = calloc(1, sizeof(struct binding_config)); + struct roots_binding_config *bc = + calloc(1, sizeof(struct roots_binding_config)); xkb_keysym_t keysyms[ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP]; char *symnames = strdup(combination); @@ -150,7 +152,7 @@ void add_binding_config(struct wl_list *bindings, const char* combination, static void config_handle_keyboard(struct roots_config *config, const char *device_name, const char *name, const char *value) { - struct keyboard_config *kc; + struct roots_keyboard_config *kc; bool found = false; wl_list_for_each(kc, &config->keyboards, link) { if (strcmp(kc->name, device_name) == 0) { @@ -160,7 +162,7 @@ static void config_handle_keyboard(struct roots_config *config, } if (!found) { - kc = calloc(1, sizeof(struct keyboard_config)); + kc = calloc(1, sizeof(struct roots_keyboard_config)); kc->name = strdup(device_name); wl_list_insert(&config->keyboards, &kc->link); } @@ -193,20 +195,20 @@ static int config_ini_handler(void *user, const char *section, const char *name, const char *value) { struct roots_config *config = user; if (strcmp(section, "core") == 0) { - if (strcmp(name, "xwayland") == 0) { - if (strcasecmp(value, "true") == 0) { - config->xwayland = true; - } else if (strcasecmp(value, "false") == 0) { - config->xwayland = false; - } else { - wlr_log(L_ERROR, "got unknown xwayland value: %s", value); - } - } else { - wlr_log(L_ERROR, "got unknown core config: %s", name); - } + if (strcmp(name, "xwayland") == 0) { + if (strcasecmp(value, "true") == 0) { + config->xwayland = true; + } else if (strcasecmp(value, "false") == 0) { + config->xwayland = false; + } else { + wlr_log(L_ERROR, "got unknown xwayland value: %s", value); + } + } else { + wlr_log(L_ERROR, "got unknown core config: %s", name); + } } else if (strncmp(output_prefix, section, strlen(output_prefix)) == 0) { const char *output_name = section + strlen(output_prefix); - struct output_config *oc; + struct roots_output_config *oc; bool found = false; wl_list_for_each(oc, &config->outputs, link) { @@ -217,9 +219,10 @@ static int config_ini_handler(void *user, const char *section, const char *name, } if (!found) { - oc = calloc(1, sizeof(struct output_config)); + oc = calloc(1, sizeof(struct roots_output_config)); oc->name = strdup(output_name); oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; + oc->scale = 1; wl_list_insert(&config->outputs, &oc->link); } @@ -227,6 +230,9 @@ static int config_ini_handler(void *user, const char *section, const char *name, oc->x = strtol(value, NULL, 10); } else if (strcmp(name, "y") == 0) { oc->y = strtol(value, NULL, 10); + } else if (strcmp(name, "scale") == 0) { + oc->scale = strtol(value, NULL, 10); + assert(oc->scale >= 1); } else if (strcmp(name, "rotate") == 0) { if (strcmp(value, "normal") == 0) { oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; @@ -276,7 +282,7 @@ static int config_ini_handler(void *user, const char *section, const char *name, } else if (strncmp(device_prefix, section, strlen(device_prefix)) == 0) { const char *device_name = section + strlen(device_prefix); - struct device_config *dc; + struct roots_device_config *dc; bool found = false; wl_list_for_each(dc, &config->devices, link) { if (strcmp(dc->name, device_name) == 0) { @@ -286,8 +292,9 @@ static int config_ini_handler(void *user, const char *section, const char *name, } if (!found) { - dc = calloc(1, sizeof(struct device_config)); + dc = calloc(1, sizeof(struct roots_device_config)); dc->name = strdup(device_name); + dc->seat = strdup("seat0"); wl_list_insert(&config->devices, &dc->link); } @@ -297,12 +304,16 @@ static int config_ini_handler(void *user, const char *section, const char *name, } else if (strcmp(name, "geometry") == 0) { free(dc->mapped_box); dc->mapped_box = parse_geometry(value); + } else if (strcmp(name, "seat") == 0) { + free(dc->seat); + dc->seat = strdup(value); } else { wlr_log(L_ERROR, "got unknown device config: %s", name); } } else if (strcmp(section, "keyboard") == 0) { config_handle_keyboard(config, "", name, value); - } else if (strncmp(keyboard_prefix, section, strlen(keyboard_prefix)) == 0) { + } else if (strncmp(keyboard_prefix, + section, strlen(keyboard_prefix)) == 0) { const char *device_name = section + strlen(keyboard_prefix); config_handle_keyboard(config, device_name, name, value); } else if (strcmp(section, "bindings") == 0) { @@ -314,7 +325,7 @@ static int config_ini_handler(void *user, const char *section, const char *name, return 1; } -struct roots_config *parse_args(int argc, char *argv[]) { +struct roots_config *roots_config_create_from_args(int argc, char *argv[]) { struct roots_config *config = calloc(1, sizeof(struct roots_config)); if (config == NULL) { return NULL; @@ -361,7 +372,8 @@ struct roots_config *parse_args(int argc, char *argv[]) { add_binding_config(&config->bindings, "Logo+Shift+E", "exit"); add_binding_config(&config->bindings, "Ctrl+q", "close"); add_binding_config(&config->bindings, "Alt+Tab", "next_window"); - struct keyboard_config *kc = calloc(1, sizeof(struct keyboard_config)); + struct roots_keyboard_config *kc = + calloc(1, sizeof(struct roots_keyboard_config)); kc->meta_key = WLR_MODIFIER_LOGO; kc->name = strdup(""); wl_list_insert(&config->keyboards, &kc->link); @@ -377,22 +389,23 @@ struct roots_config *parse_args(int argc, char *argv[]) { } void roots_config_destroy(struct roots_config *config) { - struct output_config *oc, *otmp = NULL; + struct roots_output_config *oc, *otmp = NULL; wl_list_for_each_safe(oc, otmp, &config->outputs, link) { free(oc->name); free(oc); } - struct device_config *dc, *dtmp = NULL; + struct roots_device_config *dc, *dtmp = NULL; wl_list_for_each_safe(dc, dtmp, &config->devices, link) { free(dc->name); + free(dc->seat); free(dc->mapped_output); free(dc->mapped_box); free(dc); } - struct keyboard_config *kc, *ktmp = NULL; - wl_list_for_each_safe(kc, ktmp, &config->bindings, link) { + struct roots_keyboard_config *kc, *ktmp = NULL; + wl_list_for_each_safe(kc, ktmp, &config->keyboards, link) { free(kc->name); free(kc->rules); free(kc->model); @@ -402,7 +415,7 @@ void roots_config_destroy(struct roots_config *config) { free(kc); } - struct binding_config *bc, *btmp = NULL; + struct roots_binding_config *bc, *btmp = NULL; wl_list_for_each_safe(bc, btmp, &config->bindings, link) { free(bc->keysyms); free(bc->command); @@ -415,9 +428,9 @@ void roots_config_destroy(struct roots_config *config) { free(config); } -struct output_config *config_get_output(struct roots_config *config, +struct roots_output_config *roots_config_get_output(struct roots_config *config, struct wlr_output *output) { - struct output_config *o_config; + struct roots_output_config *o_config; wl_list_for_each(o_config, &config->outputs, link) { if (strcmp(o_config->name, output->name) == 0) { return o_config; @@ -427,9 +440,9 @@ struct output_config *config_get_output(struct roots_config *config, return NULL; } -struct device_config *config_get_device(struct roots_config *config, +struct roots_device_config *roots_config_get_device(struct roots_config *config, struct wlr_input_device *device) { - struct device_config *d_config; + struct roots_device_config *d_config; wl_list_for_each(d_config, &config->devices, link) { if (strcmp(d_config->name, device->name) == 0) { return d_config; @@ -439,9 +452,9 @@ struct device_config *config_get_device(struct roots_config *config, return NULL; } -struct keyboard_config *config_get_keyboard(struct roots_config *config, - struct wlr_input_device *device) { - struct keyboard_config *kc; +struct roots_keyboard_config *roots_config_get_keyboard( + struct roots_config *config, struct wlr_input_device *device) { + struct roots_keyboard_config *kc; wl_list_for_each(kc, &config->keyboards, link) { if ((device != NULL && strcmp(kc->name, device->name) == 0) || (device == NULL && strcmp(kc->name, "") == 0)) { diff --git a/rootston/cursor.c b/rootston/cursor.c index b153e8c8..5949a364 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -1,150 +1,93 @@ #define _XOPEN_SOURCE 700 #include -#include -#include -#include #include -#include #ifdef __linux__ #include #elif __FreeBSD__ #include #endif -#include -#include +#include #include -#include -#include "rootston/config.h" -#include "rootston/input.h" -#include "rootston/desktop.h" -#include "rootston/view.h" +#include "rootston/xcursor.h" +#include "rootston/cursor.h" -const struct roots_input_event *get_input_event(struct roots_input *input, - uint32_t serial) { - size_t len = sizeof(input->input_events) / sizeof(*input->input_events); - for (size_t i = 0; i < len; ++i) { - if (input->input_events[i].cursor - && input->input_events[i].serial == serial) { - return &input->input_events[i]; - } +struct roots_cursor *roots_cursor_create(struct roots_seat *seat) { + struct roots_cursor *cursor = calloc(1, sizeof(struct roots_cursor)); + if (!cursor) { + return NULL; } - return NULL; -} - -static void cursor_set_xcursor_image(struct roots_input *input, - struct wlr_xcursor_image *image) { - wlr_cursor_set_image(input->cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y); -} - -void view_begin_move(struct roots_input *input, struct wlr_cursor *cursor, - struct roots_view *view) { - input->mode = ROOTS_CURSOR_MOVE; - input->offs_x = cursor->x; - input->offs_y = cursor->y; - input->view_x = view->x; - input->view_y = view->y; - wlr_seat_pointer_clear_focus(input->wl_seat); - - struct wlr_xcursor *xcursor = get_move_xcursor(input->xcursor_theme); - if (xcursor != NULL) { - cursor_set_xcursor_image(input, xcursor->images[0]); + cursor->cursor = wlr_cursor_create(); + if (!cursor->cursor) { + free(cursor); + return NULL; } + return cursor; } -void view_begin_resize(struct roots_input *input, struct wlr_cursor *cursor, - struct roots_view *view, uint32_t edges) { - input->mode = ROOTS_CURSOR_RESIZE; - input->offs_x = cursor->x; - input->offs_y = cursor->y; - input->view_x = view->x; - input->view_y = view->y; - struct wlr_box size; - view_get_size(view, &size); - input->view_width = size.width; - input->view_height = size.height; - input->resize_edges = edges; - wlr_seat_pointer_clear_focus(input->wl_seat); - - struct wlr_xcursor *xcursor = get_resize_xcursor(input->xcursor_theme, edges); - if (xcursor != NULL) { - cursor_set_xcursor_image(input, xcursor->images[0]); - } +void roots_cursor_destroy(struct roots_cursor *cursor) { + // TODO } -void view_begin_rotate(struct roots_input *input, struct wlr_cursor *cursor, - struct roots_view *view) { - input->mode = ROOTS_CURSOR_ROTATE; - input->offs_x = cursor->x; - input->offs_y = cursor->y; - input->view_rotation = view->rotation; - wlr_seat_pointer_clear_focus(input->wl_seat); - - struct wlr_xcursor *xcursor = get_rotate_xcursor(input->xcursor_theme); - if (xcursor != NULL) { - cursor_set_xcursor_image(input, xcursor->images[0]); - } -} - -void cursor_update_position(struct roots_input *input, uint32_t time) { - struct roots_desktop *desktop = input->server->desktop; +static void roots_cursor_update_position(struct roots_cursor *cursor, uint32_t time) { + struct roots_desktop *desktop = cursor->seat->input->server->desktop; + struct roots_seat *seat = cursor->seat; struct roots_view *view; struct wlr_surface *surface; double sx, sy; - switch (input->mode) { + switch (cursor->mode) { case ROOTS_CURSOR_PASSTHROUGH: - view = view_at(desktop, input->cursor->x, input->cursor->y, + view = view_at(desktop, cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - bool set_compositor_cursor = !view && input->cursor_client; + bool set_compositor_cursor = !view && cursor->cursor_client; if (view) { struct wl_client *view_client = wl_resource_get_client(view->wlr_surface->resource); - set_compositor_cursor = view_client != input->cursor_client; + set_compositor_cursor = view_client != cursor->cursor_client; } if (set_compositor_cursor) { - struct wlr_xcursor *xcursor = get_default_xcursor(input->xcursor_theme); - cursor_set_xcursor_image(input, xcursor->images[0]); - input->cursor_client = NULL; + wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, + ROOTS_XCURSOR_DEFAULT, cursor->cursor); + cursor->cursor_client = NULL; } if (view) { - wlr_seat_pointer_notify_enter(input->wl_seat, surface, sx, sy); - wlr_seat_pointer_notify_motion(input->wl_seat, time, sx, sy); + wlr_seat_pointer_notify_enter(seat->seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(seat->seat, time, sx, sy); } else { - wlr_seat_pointer_clear_focus(input->wl_seat); + wlr_seat_pointer_clear_focus(seat->seat); } break; case ROOTS_CURSOR_MOVE: - if (input->active_view) { - double dx = input->cursor->x - input->offs_x; - double dy = input->cursor->y - input->offs_y; - view_move(input->active_view, input->view_x + dx, - input->view_y + dy); + if (seat->focus) { + double dx = cursor->cursor->x - cursor->offs_x; + double dy = cursor->cursor->y - cursor->offs_y; + view_move(seat->focus, cursor->view_x + dx, + cursor->view_y + dy); } break; case ROOTS_CURSOR_RESIZE: - if (input->active_view) { - double dx = input->cursor->x - input->offs_x; - double dy = input->cursor->y - input->offs_y; - double active_x = input->active_view->x; - double active_y = input->active_view->y; - int width = input->view_width; - int height = input->view_height; - if (input->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_TOP) { - active_y = input->view_y + dy; + if (seat->focus) { + double dx = cursor->cursor->x - cursor->offs_x; + double dy = cursor->cursor->y - cursor->offs_y; + double active_x = seat->focus->x; + double active_y = seat->focus->y; + int width = cursor->view_width; + int height = cursor->view_height; + if (cursor->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_TOP) { + active_y = cursor->view_y + dy; height -= dy; if (height < 0) { active_y += height; } - } else if (input->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_BOTTOM) { + } else if (cursor->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_BOTTOM) { height += dy; } - if (input->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_LEFT) { - active_x = input->view_x + dx; + if (cursor->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_LEFT) { + active_x = cursor->view_x + dx; width -= dx; if (width < 0) { active_x += width; } - } else if (input->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) { + } else if (cursor->resize_edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) { width += dx; } @@ -155,132 +98,51 @@ void cursor_update_position(struct roots_input *input, uint32_t time) { height = 0; } - if (active_x != input->active_view->x || - active_y != input->active_view->y) { - view_move_resize(input->active_view, active_x, active_y, + if (active_x != seat->focus->x || + active_y != seat->focus->y) { + view_move_resize(seat->focus, active_x, active_y, width, height); } else { - view_resize(input->active_view, width, height); + view_resize(seat->focus, width, height); } } break; case ROOTS_CURSOR_ROTATE: - if (input->active_view) { - struct roots_view *view = input->active_view; + if (seat->focus) { + struct roots_view *view = seat->focus; int ox = view->x + view->wlr_surface->current->width/2, oy = view->y + view->wlr_surface->current->height/2; - int ux = input->offs_x - ox, - uy = input->offs_y - oy; - int vx = input->cursor->x - ox, - vy = input->cursor->y - oy; + int ux = cursor->offs_x - ox, + uy = cursor->offs_y - oy; + int vx = cursor->cursor->x - ox, + vy = cursor->cursor->y - oy; float angle = atan2(vx*uy - vy*ux, vx*ux + vy*uy); int steps = 12; angle = round(angle/M_PI*steps) / (steps/M_PI); - view->rotation = input->view_rotation + angle; + view->rotation = cursor->view_rotation + angle; } break; } + } -void set_view_focus(struct roots_input *input, struct roots_desktop *desktop, - struct roots_view *view) { - if (input->active_view == view) { - return; - } - input->active_view = view; - input->mode = ROOTS_CURSOR_PASSTHROUGH; - if (!view) { - return; - } - - if (view->type == ROOTS_XWAYLAND_VIEW && - view->xwayland_surface->override_redirect) { - return; - } - - size_t index = 0; - for (size_t i = 0; i < desktop->views->length; ++i) { - struct roots_view *_view = desktop->views->items[i]; - if (_view != view) { - view_activate(_view, false); - } else { - index = i; - } - } - view_activate(view, true); - // TODO: list_swap - wlr_list_del(desktop->views, index); - wlr_list_add(desktop->views, view); - wlr_seat_keyboard_notify_enter(input->wl_seat, view->wlr_surface); -} - -static void handle_cursor_motion(struct wl_listener *listener, void *data) { - struct roots_input *input = wl_container_of(listener, input, cursor_motion); - struct wlr_event_pointer_motion *event = data; - wlr_cursor_move(input->cursor, event->device, - event->delta_x, event->delta_y); - cursor_update_position(input, event->time_msec); -} - -static void handle_cursor_motion_absolute(struct wl_listener *listener, - void *data) { - struct roots_input *input = wl_container_of(listener, - input, cursor_motion_absolute); - struct wlr_event_pointer_motion_absolute *event = data; - wlr_cursor_warp_absolute(input->cursor, event->device, - event->x_mm / event->width_mm, event->y_mm / event->height_mm); - cursor_update_position(input, event->time_msec); -} - -static void handle_cursor_axis(struct wl_listener *listener, void *data) { - struct roots_input *input = - wl_container_of(listener, input, cursor_axis); - struct wlr_event_pointer_axis *event = data; - wlr_seat_pointer_notify_axis(input->wl_seat, event->time_msec, - event->orientation, event->delta); -} - -static bool is_meta_pressed(struct roots_input *input, - struct wlr_input_device *device) { - uint32_t meta_key = 0; - struct keyboard_config *config; - if ((config = config_get_keyboard(input->server->config, device))) { - meta_key = config->meta_key; - } else if (!meta_key && (config = config_get_keyboard(input->server->config, - NULL))) { - meta_key = config->meta_key; - } - if (meta_key == 0) { - return false; - } - - struct roots_keyboard *keyboard; - wl_list_for_each(keyboard, &input->keyboards, link) { - uint32_t modifiers = - wlr_keyboard_get_modifiers(keyboard->device->keyboard); - if ((modifiers ^ meta_key) == 0) { - return true; - } - } - return false; -} - -static void do_cursor_button_press(struct roots_input *input, - struct wlr_cursor *cursor, struct wlr_input_device *device, - uint32_t time, uint32_t button, uint32_t state) { - struct roots_desktop *desktop = input->server->desktop; +static void roots_cursor_press_button(struct roots_cursor *cursor, + struct wlr_input_device *device, uint32_t time, uint32_t button, + uint32_t state) { + struct roots_seat *seat = cursor->seat; + struct roots_desktop *desktop = seat->input->server->desktop; struct wlr_surface *surface; double sx, sy; struct roots_view *view = view_at(desktop, - input->cursor->x, input->cursor->y, &surface, &sx, &sy); + cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); - if (state == WLR_BUTTON_PRESSED && view && is_meta_pressed(input, device)) { - set_view_focus(input, desktop, view); + if (state == WLR_BUTTON_PRESSED && view && roots_seat_has_meta_pressed(seat)) { + roots_seat_focus_view(seat, view); uint32_t edges; switch (button) { case BTN_LEFT: - view_begin_move(input, cursor, view); + roots_seat_begin_move(seat, view); break; case BTN_RIGHT: edges = 0; @@ -294,110 +156,163 @@ static void do_cursor_button_press(struct roots_input *input, } else { edges |= ROOTS_CURSOR_RESIZE_EDGE_BOTTOM; } - view_begin_resize(input, cursor, view, edges); + roots_seat_begin_resize(seat, view, edges); break; case BTN_MIDDLE: - view_begin_rotate(input, cursor, view); + roots_seat_begin_rotate(seat, view); break; } return; } - uint32_t serial = wlr_seat_pointer_notify_button(input->wl_seat, time, button, - state); + uint32_t serial = + wlr_seat_pointer_notify_button(seat->seat, time, button, state); int i; switch (state) { case WLR_BUTTON_RELEASED: - set_view_focus(input, desktop, NULL); - cursor_update_position(input, time); + seat->cursor->mode = ROOTS_CURSOR_PASSTHROUGH; + roots_cursor_update_position(cursor, time); break; case WLR_BUTTON_PRESSED: - i = input->input_events_idx; - input->input_events[i].serial = serial; - input->input_events[i].cursor = cursor; - input->input_events[i].device = device; - input->input_events_idx = (i + 1) - % (sizeof(input->input_events) / sizeof(input->input_events[0])); - set_view_focus(input, desktop, view); + i = cursor->input_events_idx; + cursor->input_events[i].serial = serial; + cursor->input_events[i].cursor = cursor->cursor; + cursor->input_events[i].device = device; + cursor->input_events_idx = (i + 1) + % (sizeof(cursor->input_events) / sizeof(cursor->input_events[0])); + roots_seat_focus_view(seat, view); break; } } -static void handle_cursor_button(struct wl_listener *listener, void *data) { - struct roots_input *input = wl_container_of(listener, input, cursor_button); - struct wlr_event_pointer_button *event = data; - do_cursor_button_press(input, input->cursor, event->device, - event->time_msec, event->button, event->state); +void roots_cursor_handle_motion(struct roots_cursor *cursor, + struct wlr_event_pointer_motion *event) { + wlr_cursor_move(cursor->cursor, event->device, + event->delta_x, event->delta_y); + roots_cursor_update_position(cursor, event->time_msec); } -static void handle_touch_down(struct wl_listener *listener, void *data) { - struct wlr_event_touch_down *event = data; - struct roots_input *input = - wl_container_of(listener, input, cursor_touch_down); +void roots_cursor_handle_motion_absolute(struct roots_cursor *cursor, + struct wlr_event_pointer_motion_absolute *event) { + wlr_cursor_warp_absolute(cursor->cursor, event->device, + event->x_mm / event->width_mm, event->y_mm / event->height_mm); + roots_cursor_update_position(cursor, event->time_msec); +} + +void roots_cursor_handle_button(struct roots_cursor *cursor, + struct wlr_event_pointer_button *event) { + roots_cursor_press_button(cursor, event->device, event->time_msec, + event->button, event->state); +} + +void roots_cursor_handle_axis(struct roots_cursor *cursor, + struct wlr_event_pointer_axis *event) { + wlr_seat_pointer_notify_axis(cursor->seat->seat, event->time_msec, + event->orientation, event->delta); +} + +void roots_cursor_handle_touch_down(struct roots_cursor *cursor, + struct wlr_event_touch_down *event) { struct roots_touch_point *point = calloc(1, sizeof(struct roots_touch_point)); + if (!point) { + wlr_log(L_ERROR, "could not allocate memory for touch point"); + return; + } + point->device = event->device->data; point->slot = event->slot; point->x = event->x_mm / event->width_mm; point->y = event->y_mm / event->height_mm; - wlr_cursor_warp_absolute(input->cursor, event->device, point->x, point->y); - cursor_update_position(input, event->time_msec); - wl_list_insert(&input->touch_points, &point->link); - do_cursor_button_press(input, input->cursor, event->device, + wlr_cursor_warp_absolute(cursor->cursor, event->device, point->x, point->y); + roots_cursor_update_position(cursor, event->time_msec); + wl_list_insert(&cursor->touch_points, &point->link); + roots_cursor_press_button(cursor, event->device, event->time_msec, BTN_LEFT, 1); } -static void handle_touch_up(struct wl_listener *listener, void *data) { - struct wlr_event_touch_up *event = data; - struct roots_input *input = - wl_container_of(listener, input, cursor_touch_up); +void roots_cursor_handle_touch_up(struct roots_cursor *cursor, + struct wlr_event_touch_up *event) { struct roots_touch_point *point; - wl_list_for_each(point, &input->touch_points, link) { + wl_list_for_each(point, &cursor->touch_points, link) { if (point->slot == event->slot) { wl_list_remove(&point->link); + free(point); break; } } - do_cursor_button_press(input, input->cursor, event->device, + roots_cursor_press_button(cursor, event->device, event->time_msec, BTN_LEFT, 0); } -static void handle_touch_motion(struct wl_listener *listener, void *data) { - struct wlr_event_touch_motion *event = data; - struct roots_input *input = - wl_container_of(listener, input, cursor_touch_motion); +void roots_cursor_handle_touch_motion(struct roots_cursor *cursor, + struct wlr_event_touch_motion *event) { struct roots_touch_point *point; - wl_list_for_each(point, &input->touch_points, link) { + wl_list_for_each(point, &cursor->touch_points, link) { if (point->slot == event->slot) { point->x = event->x_mm / event->width_mm; point->y = event->y_mm / event->height_mm; - wlr_cursor_warp_absolute(input->cursor, event->device, + wlr_cursor_warp_absolute(cursor->cursor, event->device, point->x, point->y); - cursor_update_position(input, event->time_msec); + roots_cursor_update_position(cursor, event->time_msec); break; } } } -static void handle_tool_axis(struct wl_listener *listener, void *data) { - struct roots_input *input = wl_container_of(listener, input, cursor_tool_axis); - struct wlr_event_tablet_tool_axis *event = data; +void roots_cursor_handle_tool_axis(struct roots_cursor *cursor, + struct wlr_event_tablet_tool_axis *event) { if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) && (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { - wlr_cursor_warp_absolute(input->cursor, event->device, + wlr_cursor_warp_absolute(cursor->cursor, event->device, event->x_mm / event->width_mm, event->y_mm / event->height_mm); - cursor_update_position(input, event->time_msec); + roots_cursor_update_position(cursor, event->time_msec); + } else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { + wlr_cursor_warp_absolute(cursor->cursor, event->device, + event->x_mm / event->width_mm, -1); + roots_cursor_update_position(cursor, event->time_msec); + } else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { + wlr_cursor_warp_absolute(cursor->cursor, event->device, + -1, event->y_mm / event->height_mm); + roots_cursor_update_position(cursor, event->time_msec); } } -static void handle_tool_tip(struct wl_listener *listener, void *data) { - struct roots_input *input = wl_container_of(listener, input, cursor_tool_tip); - struct wlr_event_tablet_tool_tip *event = data; - do_cursor_button_press(input, input->cursor, event->device, +void roots_cursor_handle_tool_tip(struct roots_cursor *cursor, + struct wlr_event_tablet_tool_tip *event) { + roots_cursor_press_button(cursor, event->device, event->time_msec, BTN_LEFT, event->state); } +void roots_cursor_handle_request_set_cursor(struct roots_cursor *cursor, + struct wlr_seat_pointer_request_set_cursor_event *event) { + struct wlr_surface *focused_surface = + event->seat_client->seat->pointer_state.focused_surface; + bool has_focused = focused_surface != NULL && focused_surface->resource != NULL; + struct wl_client *focused_client = NULL; + if (has_focused) { + focused_client = wl_resource_get_client(focused_surface->resource); + } + if (event->seat_client->client != focused_client || + cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { + wlr_log(L_DEBUG, "Denying request to set cursor from unfocused client"); + return; + } + + wlr_log(L_DEBUG, "Setting client cursor"); + wlr_cursor_set_surface(cursor->cursor, event->surface, event->hotspot_x, + event->hotspot_y); + cursor->cursor_client = event->seat_client->client; +} + +static void handle_drag_icon_commit(struct wl_listener *listener, void *data) { + struct roots_drag_icon *drag_icon = + wl_container_of(listener, drag_icon, surface_commit); + drag_icon->sx += drag_icon->surface->current->sx; + drag_icon->sy += drag_icon->surface->current->sy; +} + static void handle_drag_icon_destroy(struct wl_listener *listener, void *data) { struct roots_drag_icon *drag_icon = wl_container_of(listener, drag_icon, surface_destroy); @@ -407,24 +322,14 @@ static void handle_drag_icon_destroy(struct wl_listener *listener, void *data) { free(drag_icon); } -static void handle_drag_icon_commit(struct wl_listener *listener, void *data) { - struct roots_drag_icon *drag_icon = - wl_container_of(listener, drag_icon, surface_commit); - drag_icon->sx += drag_icon->surface->current->sx; - drag_icon->sy += drag_icon->surface->current->sy; -} - -static void handle_pointer_grab_begin(struct wl_listener *listener, - void *data) { - struct roots_input *input = - wl_container_of(listener, input, pointer_grab_begin); - struct wlr_seat_pointer_grab *grab = data; - +void roots_cursor_handle_pointer_grab_begin(struct roots_cursor *cursor, + struct wlr_seat_pointer_grab *grab) { + struct roots_seat *seat = cursor->seat; if (grab->interface == &wlr_data_device_pointer_drag_interface) { struct wlr_drag *drag = grab->data; if (drag->icon) { struct roots_drag_icon *iter_icon; - wl_list_for_each(iter_icon, &input->drag_icons, link) { + wl_list_for_each(iter_icon, &seat->drag_icons, link) { if (iter_icon->surface == drag->icon) { // already in the list return; @@ -435,7 +340,7 @@ static void handle_pointer_grab_begin(struct wl_listener *listener, calloc(1, sizeof(struct roots_drag_icon)); drag_icon->mapped = true; drag_icon->surface = drag->icon; - wl_list_insert(&input->drag_icons, &drag_icon->link); + wl_list_insert(&seat->drag_icons, &drag_icon->link); wl_signal_add(&drag->icon->events.destroy, &drag_icon->surface_destroy); @@ -448,155 +353,17 @@ static void handle_pointer_grab_begin(struct wl_listener *listener, } } -static void handle_pointer_grab_end(struct wl_listener *listener, void *data) { - struct roots_input *input = - wl_container_of(listener, input, pointer_grab_end); - struct wlr_seat_pointer_grab *grab = data; - +void roots_cursor_handle_pointer_grab_end(struct roots_cursor *cursor, + struct wlr_seat_pointer_grab *grab) { if (grab->interface == &wlr_data_device_pointer_drag_interface) { struct wlr_drag *drag = grab->data; struct roots_drag_icon *icon; - wl_list_for_each(icon, &input->drag_icons, link) { + wl_list_for_each(icon, &cursor->seat->drag_icons, link) { if (icon->surface == drag->icon) { icon->mapped = false; } } } - cursor_update_position(input, 0); -} - -static void handle_request_set_cursor(struct wl_listener *listener, - void *data) { - struct roots_input *input = wl_container_of(listener, input, - request_set_cursor); - struct wlr_seat_pointer_request_set_cursor_event *event = data; - - struct wlr_surface *focused_surface = - event->seat_client->seat->pointer_state.focused_surface; - bool ok = focused_surface != NULL && focused_surface->resource != NULL; - if (ok) { - struct wl_client *focused_client = - wl_resource_get_client(focused_surface->resource); - ok = event->seat_client->client == focused_client; - } - if (!ok || input->mode != ROOTS_CURSOR_PASSTHROUGH) { - wlr_log(L_DEBUG, "Denying request to set cursor from unfocused client"); - return; - } - - wlr_log(L_DEBUG, "Setting client cursor"); - wlr_cursor_set_surface(input->cursor, event->surface, event->hotspot_x, - event->hotspot_y); - input->cursor_client = event->seat_client->client; -} - -void cursor_initialize(struct roots_input *input) { - struct wlr_cursor *cursor = input->cursor; - - // TODO: Does this belong here - wl_list_init(&input->touch_points); - - wl_signal_add(&cursor->events.motion, &input->cursor_motion); - input->cursor_motion.notify = handle_cursor_motion; - - wl_signal_add(&cursor->events.motion_absolute, - &input->cursor_motion_absolute); - input->cursor_motion_absolute.notify = handle_cursor_motion_absolute; - - wl_signal_add(&cursor->events.button, &input->cursor_button); - input->cursor_button.notify = handle_cursor_button; - - wl_signal_add(&cursor->events.axis, &input->cursor_axis); - input->cursor_axis.notify = handle_cursor_axis; - - wl_signal_add(&cursor->events.touch_down, &input->cursor_touch_down); - input->cursor_touch_down.notify = handle_touch_down; - - wl_signal_add(&cursor->events.touch_up, &input->cursor_touch_up); - input->cursor_touch_up.notify = handle_touch_up; - - wl_signal_add(&cursor->events.touch_motion, &input->cursor_touch_motion); - input->cursor_touch_motion.notify = handle_touch_motion; - - wl_signal_add(&cursor->events.tablet_tool_axis, &input->cursor_tool_axis); - input->cursor_tool_axis.notify = handle_tool_axis; - - wl_signal_add(&cursor->events.tablet_tool_tip, &input->cursor_tool_tip); - input->cursor_tool_tip.notify = handle_tool_tip; - - wl_signal_add(&input->wl_seat->events.pointer_grab_end, &input->pointer_grab_end); - input->pointer_grab_end.notify = handle_pointer_grab_end; - - wl_signal_add(&input->wl_seat->events.pointer_grab_begin, &input->pointer_grab_begin); - input->pointer_grab_begin.notify = handle_pointer_grab_begin; - - wl_list_init(&input->request_set_cursor.link); - - wl_signal_add(&input->wl_seat->events.request_set_cursor, - &input->request_set_cursor); - input->request_set_cursor.notify = handle_request_set_cursor; -} - -static void reset_device_mappings(struct roots_config *config, - struct wlr_cursor *cursor, struct wlr_input_device *device) { - wlr_cursor_map_input_to_output(cursor, device, NULL); - struct device_config *dconfig; - if ((dconfig = config_get_device(config, device))) { - wlr_cursor_map_input_to_region(cursor, device, dconfig->mapped_box); - } -} - -static void set_device_output_mappings(struct roots_config *config, - struct wlr_cursor *cursor, struct wlr_output *output, - struct wlr_input_device *device) { - struct device_config *dconfig; - dconfig = config_get_device(config, device); - if (dconfig && dconfig->mapped_output && - strcmp(dconfig->mapped_output, output->name) == 0) { - wlr_cursor_map_input_to_output(cursor, device, output); - } -} - -void cursor_load_config(struct roots_config *config, - struct wlr_cursor *cursor, - struct roots_input *input, - struct roots_desktop *desktop) { - struct roots_pointer *pointer; - struct roots_touch *touch; - struct roots_tablet_tool *tablet_tool; - struct roots_output *output; - - // reset mappings - wlr_cursor_map_to_output(cursor, NULL); - wl_list_for_each(pointer, &input->pointers, link) { - reset_device_mappings(config, cursor, pointer->device); - } - wl_list_for_each(touch, &input->touch, link) { - reset_device_mappings(config, cursor, touch->device); - } - wl_list_for_each(tablet_tool, &input->tablet_tools, link) { - reset_device_mappings(config, cursor, tablet_tool->device); - } - - // configure device to output mappings - const char *mapped_output = config->cursor.mapped_output; - wl_list_for_each(output, &desktop->outputs, link) { - if (mapped_output && strcmp(mapped_output, output->wlr_output->name) == 0) { - wlr_cursor_map_to_output(cursor, output->wlr_output); - } - - wl_list_for_each(pointer, &input->pointers, link) { - set_device_output_mappings(config, cursor, output->wlr_output, - pointer->device); - } - wl_list_for_each(tablet_tool, &input->tablet_tools, link) { - set_device_output_mappings(config, cursor, output->wlr_output, - tablet_tool->device); - } - wl_list_for_each(touch, &input->touch, link) { - set_device_output_mappings(config, cursor, output->wlr_output, - touch->device); - } - } + roots_cursor_update_position(cursor, 0); } diff --git a/rootston/desktop.c b/rootston/desktop.c index 29f78ac7..1695d007 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -10,19 +10,25 @@ #include #include #include +#include #include #include #include #include "rootston/server.h" -#include "rootston/server.h" +#include "rootston/seat.h" +#include "rootston/xcursor.h" +// TODO replace me with a signal void view_destroy(struct roots_view *view) { struct roots_desktop *desktop = view->desktop; struct roots_input *input = desktop->server->input; - if (input->active_view == view) { - input->active_view = NULL; - input->mode = ROOTS_CURSOR_PASSTHROUGH; + struct roots_seat *seat; + wl_list_for_each(seat, &input->seats, link) { + if (seat->focus == view) { + seat->focus = NULL; + seat->cursor->mode = ROOTS_CURSOR_PASSTHROUGH; + } } for (size_t i = 0; i < desktop->views->length; ++i) { @@ -35,14 +41,49 @@ void view_destroy(struct roots_view *view) { free(view); } -void view_get_size(struct roots_view *view, struct wlr_box *box) { +void view_get_box(const struct roots_view *view, struct wlr_box *box) { + box->x = view->x; + box->y = view->y; if (view->get_size) { view->get_size(view, box); - return; + } else { + box->width = view->wlr_surface->current->width; + box->height = view->wlr_surface->current->height; + } +} + +static void view_update_output(const struct roots_view *view, + const struct wlr_box *before) { + struct roots_desktop *desktop = view->desktop; + struct roots_output *output; + struct wlr_box box; + view_get_box(view, &box); + wl_list_for_each(output, &desktop->outputs, link) { + bool intersected = before->x != -1 && wlr_output_layout_intersects( + desktop->layout, output->wlr_output, + before->x, before->y, before->x + before->width, + before->y + before->height); + bool intersects = wlr_output_layout_intersects( + desktop->layout, output->wlr_output, + view->x, view->y, view->x + box.width, view->y + box.height); + if (intersected && !intersects) { + wlr_surface_send_leave(view->wlr_surface, output->wlr_output); + } + if (!intersected && intersects) { + wlr_surface_send_enter(view->wlr_surface, output->wlr_output); + } + } +} + +void view_move(struct roots_view *view, double x, double y) { + struct wlr_box before; + view_get_box(view, &before); + if (view->move) { + view->move(view, x, y); + } else { + view->x = x; + view->y = y; } - box->x = box->y = 0; - box->width = view->wlr_surface->current->width; - box->height = view->wlr_surface->current->height; } void view_activate(struct roots_view *view, bool activate) { @@ -51,20 +92,13 @@ void view_activate(struct roots_view *view, bool activate) { } } -void view_move(struct roots_view *view, double x, double y) { - if (view->move) { - view->move(view, x, y); - return; - } - - view->x = x; - view->y = y; -} - void view_resize(struct roots_view *view, uint32_t width, uint32_t height) { + struct wlr_box before; + view_get_box(view, &before); if (view->resize) { view->resize(view, width, height); } + view_update_output(view, &before); } void view_move_resize(struct roots_view *view, double x, double y, @@ -78,6 +112,50 @@ void view_move_resize(struct roots_view *view, double x, double y, view_resize(view, width, height); } +void view_maximize(struct roots_view *view, bool maximized) { + if (view->maximized == maximized) { + return; + } + + if (view->maximize) { + view->maximize(view, maximized); + } + + if (!view->maximized && maximized) { + struct wlr_box view_box; + view_get_box(view, &view_box); + + view->maximized = true; + view->saved.x = view->x; + view->saved.y = view->y; + view->saved.rotation = view->rotation; + view->saved.width = view_box.width; + view->saved.height = view_box.height; + + double output_x, output_y; + wlr_output_layout_closest_point(view->desktop->layout, NULL, + view->x + (double)view_box.width/2, + view->y + (double)view_box.height/2, + &output_x, &output_y); + struct wlr_output *output = wlr_output_layout_output_at( + view->desktop->layout, output_x, output_y); + struct wlr_box *output_box = + wlr_output_layout_get_box(view->desktop->layout, output); + + view_move_resize(view, output_box->x, output_box->y, output_box->width, + output_box->height); + view->rotation = 0; + } + + if (view->maximized && !maximized) { + view->maximized = false; + + view_move_resize(view, view->saved.x, view->saved.y, view->saved.width, + view->saved.height); + view->rotation = view->saved.rotation; + } +} + void view_close(struct roots_view *view) { if (view->close) { view->close(view); @@ -85,19 +163,26 @@ void view_close(struct roots_view *view) { } bool view_center(struct roots_view *view) { - struct wlr_box size; - view_get_size(view, &size); + struct wlr_box box; + view_get_box(view, &box); struct roots_desktop *desktop = view->desktop; - struct wlr_cursor *cursor = desktop->server->input->cursor; - - struct wlr_output *output = - wlr_output_layout_output_at(desktop->layout, cursor->x, cursor->y); - - if (!output) { - output = wlr_output_layout_get_center_output(desktop->layout); + struct roots_input *input = desktop->server->input; + struct roots_seat *seat = NULL, *_seat; + wl_list_for_each(_seat, &input->seats, link) { + if (!seat || (seat->seat->last_event.tv_sec > _seat->seat->last_event.tv_sec && + seat->seat->last_event.tv_nsec > _seat->seat->last_event.tv_nsec)) { + seat = _seat; + } + } + if (!seat) { + return false; } + struct wlr_output *output = + wlr_output_layout_output_at(desktop->layout, + seat->cursor->cursor->x, + seat->cursor->cursor->y); if (!output) { // empty layout return false; @@ -109,22 +194,30 @@ bool view_center(struct roots_view *view) { int width, height; wlr_output_effective_resolution(output, &width, &height); - double view_x = (double)(width - size.width) / 2 + l_output->x; - double view_y = (double)(height - size.height) / 2 + l_output->y; - + double view_x = (double)(width - box.width) / 2 + l_output->x; + double view_y = (double)(height - box.height) / 2 + l_output->y; view_move(view, view_x, view_y); return true; } void view_setup(struct roots_view *view) { - view_center(view); - struct roots_input *input = view->desktop->server->input; - set_view_focus(input, view->desktop, view); + // TODO what seat gets focus? the one with the last input event? + struct roots_seat *seat; + wl_list_for_each(seat, &input->seats, link) { + roots_seat_focus_view(seat, view); + } + + view_center(view); + struct wlr_box before; + view_get_box(view, &before); + view_update_output(view, &before); } void view_teardown(struct roots_view *view) { + // TODO replace me with a signal + /* struct wlr_list *views = view->desktop->views; if (views->length < 2 || views->items[views->length-1] != view) { return; @@ -133,12 +226,12 @@ void view_teardown(struct roots_view *view) { struct roots_view *prev_view = views->items[views->length-2]; struct roots_input *input = prev_view->desktop->server->input; set_view_focus(input, prev_view->desktop, prev_view); - wlr_seat_keyboard_notify_enter(input->wl_seat, prev_view->wlr_surface); + */ } struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - for (int i = desktop->views->length - 1; i >= 0; --i) { + for (ssize_t i = desktop->views->length - 1; i >= 0; --i) { struct roots_view *view = desktop->views->items[i]; if (view->type == ROOTS_WL_SHELL_VIEW && @@ -150,11 +243,12 @@ struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly, double view_sx = lx - view->x; double view_sy = ly - view->y; + struct wlr_surface_state *state = view->wlr_surface->current; struct wlr_box box = { .x = 0, .y = 0, - .width = view->wlr_surface->current->buffer_width, - .height = view->wlr_surface->current->buffer_height, + .width = state->buffer_width / state->scale, + .height = state->buffer_height / state->scale, }; if (view->rotation != 0.0) { // Coordinates relative to the center of the view @@ -168,7 +262,6 @@ struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly, } if (view->type == ROOTS_XDG_SHELL_V6_VIEW) { - // TODO: test if this works with rotated views double popup_sx, popup_sy; struct wlr_xdg_surface_v6 *popup = wlr_xdg_surface_v6_popup_at(view->xdg_surface_v6, @@ -183,7 +276,6 @@ struct roots_view *view_at(struct roots_desktop *desktop, double lx, double ly, } if (view->type == ROOTS_WL_SHELL_VIEW) { - // TODO: test if this works with rotated views double popup_sx, popup_sy; struct wlr_wl_shell_surface *popup = wlr_wl_shell_surface_popup_at(view->wl_shell_surface, @@ -245,6 +337,16 @@ struct roots_desktop *desktop_create(struct roots_server *server, desktop->server = server; desktop->config = config; + + desktop->xcursor_manager = wlr_xcursor_manager_create(NULL, + ROOTS_XCURSOR_SIZE); + if (desktop->xcursor_manager == NULL) { + wlr_log(L_ERROR, "Cannot create XCursor manager"); + wlr_list_free(desktop->views); + free(desktop); + return NULL; + } + desktop->layout = wlr_output_layout_create(); desktop->compositor = wlr_compositor_create(server->wl_display, server->renderer); @@ -266,6 +368,18 @@ struct roots_desktop *desktop_create(struct roots_server *server, wl_signal_add(&desktop->xwayland->events.new_surface, &desktop->xwayland_surface); desktop->xwayland_surface.notify = handle_xwayland_surface; + + if (wlr_xcursor_manager_load(desktop->xcursor_manager, 1)) { + wlr_log(L_ERROR, "Cannot load XWayland XCursor theme"); + } + struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor( + desktop->xcursor_manager, ROOTS_XCURSOR_DEFAULT, 1); + if (xcursor != NULL) { + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_xwayland_set_cursor(desktop->xwayland, image->buffer, + image->width, image->width, image->height, image->hotspot_x, + image->hotspot_y); + } } #endif diff --git a/rootston/input.c b/rootston/input.c index 5d367a5e..35a5af97 100644 --- a/rootston/input.c +++ b/rootston/input.c @@ -8,6 +8,8 @@ #include "rootston/server.h" #include "rootston/config.h" #include "rootston/input.h" +#include "rootston/keyboard.h" +#include "rootston/seat.h" static const char *device_type(enum wlr_input_device_type type) { switch (type) { @@ -25,47 +27,48 @@ static const char *device_type(enum wlr_input_device_type type) { return NULL; } +static struct roots_seat *input_get_seat(struct roots_input *input, char *name) { + struct roots_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + if (strcmp(seat->seat->name, name) == 0) { + return seat; + } + } + + seat = roots_seat_create(input, name); + return seat; +} + static void input_add_notify(struct wl_listener *listener, void *data) { struct wlr_input_device *device = data; struct roots_input *input = wl_container_of(listener, input, input_add); - wlr_log(L_DEBUG, "New input device: %s (%d:%d) %s", device->name, - device->vendor, device->product, device_type(device->type)); - switch (device->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - keyboard_add(device, input); - break; - case WLR_INPUT_DEVICE_POINTER: - pointer_add(device, input); - break; - case WLR_INPUT_DEVICE_TOUCH: - touch_add(device, input); - break; - case WLR_INPUT_DEVICE_TABLET_TOOL: - tablet_tool_add(device, input); - break; - default: - break; + + char *seat_name = "seat0"; + struct roots_device_config *dc = + roots_config_get_device(input->config, device); + if (dc) { + seat_name = dc->seat; } + + struct roots_seat *seat = input_get_seat(input, seat_name); + if (!seat) { + wlr_log(L_ERROR, "could not create roots seat"); + return; + } + + wlr_log(L_DEBUG, "New input device: %s (%d:%d) %s seat:%s", device->name, + device->vendor, device->product, device_type(device->type), seat_name); + + roots_seat_add_device(seat, device); } static void input_remove_notify(struct wl_listener *listener, void *data) { struct wlr_input_device *device = data; struct roots_input *input = wl_container_of(listener, input, input_remove); - switch (device->type) { - case WLR_INPUT_DEVICE_KEYBOARD: - keyboard_remove(device, input); - break; - case WLR_INPUT_DEVICE_POINTER: - pointer_remove(device, input); - break; - case WLR_INPUT_DEVICE_TOUCH: - touch_remove(device, input); - break; - case WLR_INPUT_DEVICE_TABLET_TOOL: - tablet_tool_remove(device, input); - break; - default: - break; + + struct roots_seat *seat; + wl_list_for_each(seat, &input->seats, link) { + roots_seat_remove_device(seat, device); } } @@ -82,66 +85,41 @@ struct roots_input *input_create(struct roots_server *server, input->config = config; input->server = server; - input->xcursor_theme = wlr_xcursor_theme_load("default", 16); - if (input->xcursor_theme == NULL) { - wlr_log(L_ERROR, "Cannot load xcursor theme"); - free(input); - return NULL; - } - - struct wlr_xcursor *xcursor = get_default_xcursor(input->xcursor_theme); - if (xcursor == NULL) { - wlr_log(L_ERROR, "Cannot load xcursor from theme"); - wlr_xcursor_theme_destroy(input->xcursor_theme); - free(input); - return NULL; - } - - if (server->desktop->xwayland != NULL) { - struct wlr_xcursor_image *xcursor_image = xcursor->images[0]; - wlr_xwayland_set_cursor(server->desktop->xwayland, - xcursor_image->buffer, xcursor_image->width, xcursor_image->width, - xcursor_image->height, xcursor_image->hotspot_x, - xcursor_image->hotspot_y); - } - - input->wl_seat = wlr_seat_create(server->wl_display, "seat0"); - if (input->wl_seat == NULL) { - wlr_log(L_ERROR, "Cannot create seat"); - wlr_xcursor_theme_destroy(input->xcursor_theme); - free(input); - return NULL; - } - wlr_seat_set_capabilities(input->wl_seat, WL_SEAT_CAPABILITY_KEYBOARD - | WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_TOUCH); - - wl_list_init(&input->keyboards); - wl_list_init(&input->pointers); - wl_list_init(&input->touch); - wl_list_init(&input->tablet_tools); + wl_list_init(&input->seats); input->input_add.notify = input_add_notify; wl_signal_add(&server->backend->events.input_add, &input->input_add); input->input_remove.notify = input_remove_notify; wl_signal_add(&server->backend->events.input_remove, &input->input_remove); - input->cursor = wlr_cursor_create(); - cursor_initialize(input); - - struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_cursor_set_image(input->cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y); - - wlr_cursor_attach_output_layout(input->cursor, server->desktop->layout); - wlr_cursor_map_to_region(input->cursor, config->cursor.mapped_box); - cursor_load_config(config, input->cursor, - input, server->desktop); - - wl_list_init(&input->drag_icons); - return input; } void input_destroy(struct roots_input *input) { // TODO } + +struct roots_seat *input_seat_from_wlr_seat(struct roots_input *input, + struct wlr_seat *wlr_seat) { + struct roots_seat *seat = NULL; + wl_list_for_each(seat, &input->seats, link) { + if (seat->seat == wlr_seat) { + return seat; + } + } + return seat; +} + +bool input_view_has_focus(struct roots_input *input, struct roots_view *view) { + if (!view) { + return false; + } + struct roots_seat *seat; + wl_list_for_each(seat, &input->seats, link) { + if (seat->focus == view) { + return true; + } + } + + return false; +} diff --git a/rootston/keyboard.c b/rootston/keyboard.c index e174b731..39f46a32 100644 --- a/rootston/keyboard.c +++ b/rootston/keyboard.c @@ -10,17 +10,79 @@ #include #include #include "rootston/input.h" +#include "rootston/seat.h" +#include "rootston/keyboard.h" -static ssize_t keyboard_pressed_keysym_index(struct roots_keyboard *keyboard, +static ssize_t pressed_keysyms_index(xkb_keysym_t *pressed_keysyms, xkb_keysym_t keysym) { - for (size_t i = 0; i < ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP; i++) { - if (keyboard->pressed_keysyms[i] == keysym) { + for (size_t i = 0; i < ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) { + if (pressed_keysyms[i] == keysym) { return i; } } return -1; } +static size_t pressed_keysyms_length(xkb_keysym_t *pressed_keysyms) { + size_t n = 0; + for (size_t i = 0; i < ROOTS_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) { + if (pressed_keysyms[i] != XKB_KEY_NoSymbol) { + ++n; + } + } + return n; +} + +static void pressed_keysyms_add(xkb_keysym_t *pressed_keysyms, + xkb_keysym_t keysym) { + ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym); + if (i < 0) { + i = pressed_keysyms_index(pressed_keysyms, XKB_KEY_NoSymbol); + if (i >= 0) { + pressed_keysyms[i] = keysym; + } + } +} + +static void pressed_keysyms_remove(xkb_keysym_t *pressed_keysyms, + xkb_keysym_t keysym) { + ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym); + if (i >= 0) { + pressed_keysyms[i] = XKB_KEY_NoSymbol; + } +} + +static bool keysym_is_modifier(xkb_keysym_t keysym) { + switch (keysym) { + case XKB_KEY_Shift_L: case XKB_KEY_Shift_R: + case XKB_KEY_Control_L: case XKB_KEY_Control_R: + case XKB_KEY_Caps_Lock: + case XKB_KEY_Shift_Lock: + case XKB_KEY_Meta_L: case XKB_KEY_Meta_R: + case XKB_KEY_Alt_L: case XKB_KEY_Alt_R: + case XKB_KEY_Super_L: case XKB_KEY_Super_R: + case XKB_KEY_Hyper_L: case XKB_KEY_Hyper_R: + return true; + default: + return false; + } +} + +static void pressed_keysyms_update(xkb_keysym_t *pressed_keysyms, + const xkb_keysym_t *keysyms, size_t keysyms_len, + enum wlr_key_state state) { + for (size_t i = 0; i < keysyms_len; ++i) { + if (keysym_is_modifier(keysyms[i])) { + continue; + } + if (state == WLR_KEY_PRESSED) { + pressed_keysyms_add(pressed_keysyms, keysyms[i]); + } else { // WLR_KEY_RELEASED + pressed_keysyms_remove(pressed_keysyms, keysyms[i]); + } + } +} + static const char *exec_prefix = "exec "; static void keyboard_binding_execute(struct roots_keyboard *keyboard, @@ -37,7 +99,7 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard, } else if (strcmp(command, "next_window") == 0) { if (server->desktop->views->length > 0) { struct roots_view *view = server->desktop->views->items[0]; - set_view_focus(keyboard->input, server->desktop, view); + roots_seat_focus_view(keyboard->seat, view); } } else if (strncmp(exec_prefix, command, strlen(exec_prefix)) == 0) { const char *shell_cmd = command + strlen(exec_prefix); @@ -54,21 +116,14 @@ static void keyboard_binding_execute(struct roots_keyboard *keyboard, } /** - * Process a keypress from the keyboard. + * Execute a built-in, hardcoded compositor binding. These are triggered from a + * single keysym. * * Returns true if the keysym was handled by a binding and false if the event * should be propagated to clients. */ -static bool keyboard_keysym_press(struct roots_keyboard *keyboard, +static bool keyboard_execute_compositor_binding(struct roots_keyboard *keyboard, xkb_keysym_t keysym) { - ssize_t i = keyboard_pressed_keysym_index(keyboard, keysym); - if (i < 0) { - i = keyboard_pressed_keysym_index(keyboard, XKB_KEY_NoSymbol); - if (i >= 0) { - keyboard->pressed_keysyms[i] = keysym; - } - } - if (keysym >= XKB_KEY_XF86Switch_VT_1 && keysym <= XKB_KEY_XF86Switch_VT_12) { struct roots_server *server = keyboard->input->server; @@ -84,21 +139,41 @@ static bool keyboard_keysym_press(struct roots_keyboard *keyboard, } if (keysym == XKB_KEY_Escape) { - wlr_seat_pointer_end_grab(keyboard->input->wl_seat); - wlr_seat_keyboard_end_grab(keyboard->input->wl_seat); + wlr_seat_pointer_end_grab(keyboard->seat->seat); + wlr_seat_keyboard_end_grab(keyboard->seat->seat); } - uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); + return false; +} + +/** + * Execute keyboard bindings. These include compositor bindings and user-defined + * bindings. + * + * Returns true if the keysym was handled by a binding and false if the event + * should be propagated to clients. + */ +static bool keyboard_execute_binding(struct roots_keyboard *keyboard, + xkb_keysym_t *pressed_keysyms, uint32_t modifiers, + const xkb_keysym_t *keysyms, size_t keysyms_len) { + for (size_t i = 0; i < keysyms_len; ++i) { + if (keyboard_execute_compositor_binding(keyboard, keysyms[i])) { + return true; + } + } + + // User-defined bindings + size_t n = pressed_keysyms_length(pressed_keysyms); struct wl_list *bindings = &keyboard->input->server->config->bindings; - struct binding_config *bc; + struct roots_binding_config *bc; wl_list_for_each(bc, bindings, link) { - if (modifiers ^ bc->modifiers) { + if (modifiers ^ bc->modifiers || n != bc->keysyms_len) { continue; } bool ok = true; for (size_t i = 0; i < bc->keysyms_len; i++) { - ssize_t j = keyboard_pressed_keysym_index(keyboard, bc->keysyms[i]); + ssize_t j = pressed_keysyms_index(pressed_keysyms, bc->keysyms[i]); if (j < 0) { ok = false; break; @@ -114,56 +189,92 @@ static bool keyboard_keysym_press(struct roots_keyboard *keyboard, return false; } -static void keyboard_keysym_release(struct roots_keyboard *keyboard, - xkb_keysym_t keysym) { - ssize_t i = keyboard_pressed_keysym_index(keyboard, keysym); - if (i >= 0) { - keyboard->pressed_keysyms[i] = XKB_KEY_NoSymbol; - } +/* + * Get keysyms and modifiers from the keyboard as xkb sees them. + * + * This uses the xkb keysyms translation based on pressed modifiers and clears + * the consumed modifiers from the list of modifiers passed to keybind + * detection. + * + * On US layout, pressing Alt+Shift+2 will trigger Alt+@. + */ +static size_t keyboard_keysyms_translated(struct roots_keyboard *keyboard, + xkb_keycode_t keycode, const xkb_keysym_t **keysyms, + uint32_t *modifiers) { + *modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); + xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2( + keyboard->device->keyboard->xkb_state, keycode, XKB_CONSUMED_MODE_XKB); + *modifiers = *modifiers & ~consumed; + + return xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, + keycode, keysyms); } -static void keyboard_key_notify(struct wl_listener *listener, void *data) { - struct wlr_event_keyboard_key *event = data; - struct roots_keyboard *keyboard = wl_container_of(listener, keyboard, key); +/* + * Get keysyms and modifiers from the keyboard as if modifiers didn't change + * keysyms. + * + * This avoids the xkb keysym translation based on modifiers considered pressed + * in the state. + * + * This will trigger keybinds such as Alt+Shift+2. + */ +static size_t keyboard_keysyms_raw(struct roots_keyboard *keyboard, + xkb_keycode_t keycode, const xkb_keysym_t **keysyms, + uint32_t *modifiers) { + *modifiers = wlr_keyboard_get_modifiers(keyboard->device->keyboard); - uint32_t keycode = event->keycode + 8; - const xkb_keysym_t *syms; - int syms_len = xkb_state_key_get_syms(keyboard->device->keyboard->xkb_state, - keycode, &syms); + xkb_layout_index_t layout_index = xkb_state_key_get_layout( + keyboard->device->keyboard->xkb_state, keycode); + return xkb_keymap_key_get_syms_by_level(keyboard->device->keyboard->keymap, + keycode, layout_index, 0, keysyms); +} + +void roots_keyboard_handle_key(struct roots_keyboard *keyboard, + struct wlr_event_keyboard_key *event) { + xkb_keycode_t keycode = event->keycode + 8; bool handled = false; - for (int i = 0; i < syms_len; i++) { - if (event->state == WLR_KEY_PRESSED) { - bool keysym_handled = keyboard_keysym_press(keyboard, syms[i]); - handled = handled || keysym_handled; - } else { // WLR_KEY_RELEASED - keyboard_keysym_release(keyboard, syms[i]); - } + uint32_t modifiers; + const xkb_keysym_t *keysyms; + size_t keysyms_len; + + // Handle translated keysyms + + keysyms_len = keyboard_keysyms_translated(keyboard, keycode, &keysyms, + &modifiers); + pressed_keysyms_update(keyboard->pressed_keysyms_translated, keysyms, + keysyms_len, event->state); + if (event->state == WLR_KEY_PRESSED) { + handled = keyboard_execute_binding(keyboard, + keyboard->pressed_keysyms_translated, modifiers, keysyms, + keysyms_len); + } + + // Handle raw keysyms + keysyms_len = keyboard_keysyms_raw(keyboard, keycode, &keysyms, &modifiers); + pressed_keysyms_update(keyboard->pressed_keysyms_raw, keysyms, keysyms_len, + event->state); + if (event->state == WLR_KEY_PRESSED && !handled) { + handled = keyboard_execute_binding(keyboard, + keyboard->pressed_keysyms_raw, modifiers, keysyms, keysyms_len); } if (!handled) { - wlr_seat_set_keyboard(keyboard->input->wl_seat, keyboard->device); - wlr_seat_keyboard_notify_key(keyboard->input->wl_seat, event->time_msec, + wlr_seat_set_keyboard(keyboard->seat->seat, keyboard->device); + wlr_seat_keyboard_notify_key(keyboard->seat->seat, event->time_msec, event->keycode, event->state); } } -static void keyboard_modifiers_notify(struct wl_listener *listener, void *data) { - struct roots_keyboard *r_keyboard = - wl_container_of(listener, r_keyboard, modifiers); - struct wlr_seat *seat = r_keyboard->input->wl_seat; - struct wlr_keyboard *keyboard = r_keyboard->device->keyboard; +void roots_keyboard_handle_modifiers(struct roots_keyboard *r_keyboard) { + struct wlr_seat *seat = r_keyboard->seat->seat; wlr_seat_set_keyboard(seat, r_keyboard->device); - wlr_seat_keyboard_notify_modifiers(seat, - keyboard->modifiers.depressed, - keyboard->modifiers.latched, - keyboard->modifiers.locked, - keyboard->modifiers.group); - + wlr_seat_keyboard_notify_modifiers(seat); } -static void keyboard_config_merge(struct keyboard_config *config, - struct keyboard_config *fallback) { +static void keyboard_config_merge(struct roots_keyboard_config *config, + struct roots_keyboard_config *fallback) { if (fallback == NULL) { return; } @@ -182,60 +293,64 @@ static void keyboard_config_merge(struct keyboard_config *config, if (config->options == NULL) { config->options = fallback->options; } + if (config->meta_key == 0) { + config->meta_key = fallback->meta_key; + } + if (config->name == NULL) { + config->name = fallback->name; + } } -void keyboard_add(struct wlr_input_device *device, struct roots_input *input) { +struct roots_keyboard *roots_keyboard_create(struct wlr_input_device *device, + struct roots_input *input) { struct roots_keyboard *keyboard = calloc(sizeof(struct roots_keyboard), 1); if (keyboard == NULL) { - return; + return NULL; } device->data = keyboard; keyboard->device = device; keyboard->input = input; - keyboard->key.notify = keyboard_key_notify; - wl_signal_add(&device->keyboard->events.key, &keyboard->key); + struct roots_keyboard_config *config = + calloc(1, sizeof(struct roots_keyboard_config)); + if (config == NULL) { + free(keyboard); + return NULL; + } + keyboard_config_merge(config, roots_config_get_keyboard(input->config, device)); + keyboard_config_merge(config, roots_config_get_keyboard(input->config, NULL)); - keyboard->modifiers.notify = keyboard_modifiers_notify; - wl_signal_add(&device->keyboard->events.modifiers, &keyboard->modifiers); - - wl_list_insert(&input->keyboards, &keyboard->link); - - struct keyboard_config config; - memset(&config, 0, sizeof(config)); - keyboard_config_merge(&config, config_get_keyboard(input->config, device)); - keyboard_config_merge(&config, config_get_keyboard(input->config, NULL)); - - struct keyboard_config env_config = { + struct roots_keyboard_config env_config = { .rules = getenv("XKB_DEFAULT_RULES"), .model = getenv("XKB_DEFAULT_MODEL"), .layout = getenv("XKB_DEFAULT_LAYOUT"), .variant = getenv("XKB_DEFAULT_VARIANT"), .options = getenv("XKB_DEFAULT_OPTIONS"), }; - keyboard_config_merge(&config, &env_config); + keyboard_config_merge(config, &env_config); + keyboard->config = config; struct xkb_rule_names rules; memset(&rules, 0, sizeof(rules)); - rules.rules = config.rules; - rules.model = config.model; - rules.layout = config.layout; - rules.variant = config.variant; - rules.options = config.options; + rules.rules = config->rules; + rules.model = config->model; + rules.layout = config->layout; + rules.variant = config->variant; + rules.options = config->options; struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (context == NULL) { wlr_log(L_ERROR, "Cannot create XKB context"); - return; + return NULL; } wlr_keyboard_set_keymap(device->keyboard, xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS)); xkb_context_unref(context); + + return keyboard; } -void keyboard_remove(struct wlr_input_device *device, struct roots_input *input) { - struct roots_keyboard *keyboard = device->data; - wl_list_remove(&keyboard->key.link); - wl_list_remove(&keyboard->modifiers.link); +void roots_keyboard_destroy(struct roots_keyboard *keyboard) { wl_list_remove(&keyboard->link); + free(keyboard->config); free(keyboard); } diff --git a/rootston/main.c b/rootston/main.c index 2a054e6c..814d3aef 100644 --- a/rootston/main.c +++ b/rootston/main.c @@ -12,8 +12,20 @@ struct roots_server server = { 0 }; +static void ready(struct wl_listener *listener, void *data) { + if (server.config->startup_cmd != NULL) { + const char *cmd = server.config->startup_cmd; + pid_t pid = fork(); + if (pid < 0) { + wlr_log(L_ERROR, "cannot execute binding command: fork() failed"); + } else if (pid == 0) { + execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL); + } + } +} + int main(int argc, char **argv) { - assert(server.config = parse_args(argc, argv)); + assert(server.config = roots_config_create_from_args(argc, argv)); assert(server.wl_display = wl_display_create()); assert(server.wl_event_loop = wl_display_get_event_loop(server.wl_display)); @@ -43,17 +55,16 @@ int main(int argc, char **argv) { } setenv("WAYLAND_DISPLAY", socket, true); - - if (server.config->startup_cmd != NULL) { - const char *cmd = server.config->startup_cmd; - pid_t pid = fork(); - if (pid < 0) { - wlr_log(L_ERROR, "cannot execute binding command: fork() failed"); - return 1; - } else if (pid == 0) { - execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL); - } +#ifndef HAS_XWAYLAND + ready(NULL, NULL); +#else + if (server.desktop->xwayland != NULL) { + struct wl_listener xwayland_ready = { .notify = ready }; + wl_signal_add(&server.desktop->xwayland->events.ready, &xwayland_ready); + } else { + ready(NULL, NULL); } +#endif wl_display_run(server.wl_display); wlr_backend_destroy(server.backend); diff --git a/rootston/meson.build b/rootston/meson.build index d84422d8..9c543c4f 100644 --- a/rootston/meson.build +++ b/rootston/meson.build @@ -7,9 +7,7 @@ sources = [ 'keyboard.c', 'main.c', 'output.c', - 'pointer.c', - 'tablet_tool.c', - 'touch.c', + 'seat.c', 'xcursor.c', 'xdg_shell_v6.c', 'wl_shell.c', diff --git a/rootston/output.c b/rootston/output.c index baa7b6cc..28312c2c 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -16,37 +17,67 @@ static inline int64_t timespec_to_msec(const struct timespec *a) { return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; } +/** + * Rotate a child's position relative to a parent. The parent size is (pw, ph), + * the child position is (*sx, *sy) and its size is (sw, sh). + */ +static void rotate_child_position(double *sx, double *sy, double sw, double sh, + double pw, double ph, float rotation) { + if (rotation != 0.0) { + // Coordinates relative to the center of the subsurface + double ox = *sx - pw/2 + sw/2, + oy = *sy - ph/2 + sh/2; + // Rotated coordinates + double rx = cos(-rotation)*ox - sin(-rotation)*oy, + ry = cos(-rotation)*oy + sin(-rotation)*ox; + *sx = rx + pw/2 - sw/2; + *sy = ry + ph/2 - sh/2; + } +} + static void render_surface(struct wlr_surface *surface, struct roots_desktop *desktop, struct wlr_output *wlr_output, struct timespec *when, double lx, double ly, float rotation) { if (surface->texture->valid) { - int width = surface->current->buffer_width; - int height = surface->current->buffer_height; + int width = surface->current->width; + int height = surface->current->height; + int render_width = width * wlr_output->scale; + int render_height = height * wlr_output->scale; double ox = lx, oy = ly; wlr_output_layout_output_coords(desktop->layout, wlr_output, &ox, &oy); + ox *= wlr_output->scale; + oy *= wlr_output->scale; if (wlr_output_layout_intersects(desktop->layout, wlr_output, - lx, ly, lx + width, ly + height)) { + lx, ly, lx + render_width, ly + render_height)) { float matrix[16]; float translate_origin[16]; wlr_matrix_translate(&translate_origin, - (int)ox + width / 2, (int)oy + height / 2, 0); + (int)ox + render_width / 2, (int)oy + render_height / 2, 0); + float rotate[16]; wlr_matrix_rotate(&rotate, rotation); + float translate_center[16]; - wlr_matrix_translate(&translate_center, -width / 2, -height / 2, 0); + wlr_matrix_translate(&translate_center, -render_width / 2, + -render_height / 2, 0); + + float scale[16]; + wlr_matrix_scale(&scale, render_width, render_height, 1); + float transform[16]; wlr_matrix_mul(&translate_origin, &rotate, &transform); wlr_matrix_mul(&transform, &translate_center, &transform); - wlr_surface_get_matrix(surface, &matrix, - &wlr_output->transform_matrix, &transform); - wlr_render_with_matrix(desktop->server->renderer, - surface->texture, &matrix); + wlr_matrix_mul(&transform, &scale, &transform); + wlr_matrix_mul(&wlr_output->transform_matrix, &transform, &matrix); + + wlr_render_with_matrix(desktop->server->renderer, surface->texture, + &matrix); struct wlr_frame_callback *cb, *cnext; wl_list_for_each_safe(cb, cnext, - &surface->current->frame_callback_list, link) { + &surface->current->frame_callback_list, link) { wl_callback_send_done(cb->resource, timespec_to_msec(when)); wl_resource_destroy(cb->resource); } @@ -54,20 +85,12 @@ static void render_surface(struct wlr_surface *surface, struct wlr_subsurface *subsurface; wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) { - double sx = subsurface->surface->current->subsurface_position.x, - sy = subsurface->surface->current->subsurface_position.y; - double sw = subsurface->surface->current->buffer_width, - sh = subsurface->surface->current->buffer_height; - if (rotation != 0.0) { - // Coordinates relative to the center of the subsurface - double ox = sx - (double)width/2 + sw/2, - oy = sy - (double)height/2 + sh/2; - // Rotated coordinates - double rx = cos(-rotation)*ox - sin(-rotation)*oy, - ry = cos(-rotation)*oy + sin(-rotation)*ox; - sx = rx + (double)width/2 - sw/2; - sy = ry + (double)height/2 - sh/2; - } + struct wlr_surface_state *state = subsurface->surface->current; + double sx = state->subsurface_position.x; + double sy = state->subsurface_position.y; + double sw = state->buffer_width / state->scale; + double sh = state->buffer_height / state->scale; + rotate_child_position(&sx, &sy, sw, sh, width, height, rotation); render_surface(subsurface->surface, desktop, wlr_output, when, lx + sx, @@ -80,35 +103,53 @@ static void render_surface(struct wlr_surface *surface, static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, struct roots_desktop *desktop, struct wlr_output *wlr_output, struct timespec *when, double base_x, double base_y, float rotation) { - // TODO: make sure this works with view rotation + double width = surface->surface->current->width; + double height = surface->surface->current->height; + struct wlr_xdg_surface_v6 *popup; wl_list_for_each(popup, &surface->popups, popup_link) { if (!popup->configured) { continue; } - double popup_x = base_x + surface->geometry->x + - popup->popup_state->geometry.x - popup->geometry->x; - double popup_y = base_y + surface->geometry->y + - popup->popup_state->geometry.y - popup->geometry->y; - render_surface(popup->surface, desktop, wlr_output, when, popup_x, - popup_y, rotation); - render_xdg_v6_popups(popup, desktop, wlr_output, when, popup_x, popup_y, rotation); + double popup_width = popup->surface->current->width; + double popup_height = popup->surface->current->height; + + double popup_sx, popup_sy; + wlr_xdg_surface_v6_popup_get_position(popup, &popup_sx, &popup_sy); + rotate_child_position(&popup_sx, &popup_sy, popup_width, popup_height, + width, height, rotation); + + render_surface(popup->surface, desktop, wlr_output, when, + base_x + popup_sx, base_y + popup_sy, rotation); + render_xdg_v6_popups(popup, desktop, wlr_output, when, + base_x + popup_sx, base_y + popup_sy, rotation); } } -static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, struct roots_desktop *desktop, - struct wlr_output *wlr_output, struct timespec *when, double lx, - double ly, float rotation, bool is_child) { +static void render_wl_shell_surface(struct wlr_wl_shell_surface *surface, + struct roots_desktop *desktop, struct wlr_output *wlr_output, + struct timespec *when, double lx, double ly, float rotation, + bool is_child) { if (is_child || surface->state != WLR_WL_SHELL_SURFACE_STATE_POPUP) { render_surface(surface->surface, desktop, wlr_output, when, lx, ly, rotation); + + double width = surface->surface->current->width; + double height = surface->surface->current->height; + struct wlr_wl_shell_surface *popup; wl_list_for_each(popup, &surface->popups, popup_link) { + double popup_width = popup->surface->current->width; + double popup_height = popup->surface->current->height; + + double popup_x = popup->transient_state->x; + double popup_y = popup->transient_state->y; + rotate_child_position(&popup_x, &popup_y, popup_width, popup_height, + width, height, rotation); + render_wl_shell_surface(popup, desktop, wlr_output, when, - lx + popup->transient_state->x, - ly + popup->transient_state->y, - rotation, true); + lx + popup_x, ly + popup_y, rotation, true); } } } @@ -151,15 +192,18 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { } struct roots_drag_icon *drag_icon = NULL; - wl_list_for_each(drag_icon, &server->input->drag_icons, link) { - if (!drag_icon->mapped) { - continue; + struct roots_seat *seat = NULL; + wl_list_for_each(seat, &server->input->seats, link) { + wl_list_for_each(drag_icon, &seat->drag_icons, link) { + if (!drag_icon->mapped) { + continue; + } + struct wlr_surface *icon = drag_icon->surface; + struct wlr_cursor *cursor = seat->cursor->cursor; + double icon_x = cursor->x + drag_icon->sx; + double icon_y = cursor->y + drag_icon->sy; + render_surface(icon, desktop, wlr_output, &now, icon_x, icon_y, 0); } - struct wlr_surface *icon = drag_icon->surface; - struct wlr_cursor *cursor = server->input->cursor; - double icon_x = cursor->x + drag_icon->sx; - double icon_y = cursor->y + drag_icon->sy; - render_surface(icon, desktop, wlr_output, &now, icon_x, icon_y, 0); } wlr_renderer_end(server->renderer); @@ -168,7 +212,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) { output->last_frame = desktop->last_frame = now; } -static void set_mode(struct wlr_output *output, struct output_config *oc) { +static void set_mode(struct wlr_output *output, + struct roots_output_config *oc) { struct wlr_output_mode *mode, *best = NULL; int mhz = (int)(oc->mode.refresh_rate * 1000); wl_list_for_each(mode, &output->modes, link) { @@ -196,8 +241,9 @@ void output_add_notify(struct wl_listener *listener, void *data) { struct roots_config *config = desktop->config; wlr_log(L_DEBUG, "Output '%s' added", wlr_output->name); - wlr_log(L_DEBUG, "%s %s %"PRId32"mm x %"PRId32"mm", wlr_output->make, - wlr_output->model, wlr_output->phys_width, wlr_output->phys_height); + wlr_log(L_DEBUG, "%s %s %s %"PRId32"mm x %"PRId32"mm", wlr_output->make, + wlr_output->model, wlr_output->serial, wlr_output->phys_width, + wlr_output->phys_height); if (wl_list_length(&wlr_output->modes) > 0) { struct wlr_output_mode *mode = NULL; mode = wl_container_of((&wlr_output->modes)->prev, mode, link); @@ -212,11 +258,13 @@ void output_add_notify(struct wl_listener *listener, void *data) { wl_signal_add(&wlr_output->events.frame, &output->frame); wl_list_insert(&desktop->outputs, &output->link); - struct output_config *output_config = config_get_output(config, wlr_output); + struct roots_output_config *output_config = + roots_config_get_output(config, wlr_output); if (output_config) { if (output_config->mode.width) { set_mode(wlr_output, output_config); } + wlr_output->scale = output_config->scale; wlr_output_transform(wlr_output, output_config->transform); wlr_output_layout_add(desktop->layout, wlr_output, output_config->x, output_config->y); @@ -224,14 +272,17 @@ void output_add_notify(struct wl_listener *listener, void *data) { wlr_output_layout_add_auto(desktop->layout, wlr_output); } - cursor_load_config(config, input->cursor, input, desktop); + struct roots_seat *seat; + wl_list_for_each(seat, &input->seats, link) { + if (wlr_xcursor_manager_load(seat->cursor->xcursor_manager, + wlr_output->scale)) { + wlr_log(L_ERROR, "Cannot load xcursor theme for output '%s' " + "with scale %d", wlr_output->name, wlr_output->scale); + } - struct wlr_xcursor *xcursor = get_default_xcursor(input->xcursor_theme); - struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_cursor_set_image(input->cursor, image->buffer, image->width, - image->width, image->height, image->hotspot_x, image->hotspot_y); - - wlr_cursor_warp(input->cursor, NULL, input->cursor->x, input->cursor->y); + roots_seat_configure_cursor(seat); + roots_seat_configure_xcursor(seat); + } } void output_remove_notify(struct wl_listener *listener, void *data) { diff --git a/rootston/pointer.c b/rootston/pointer.c deleted file mode 100644 index 299ecdfc..00000000 --- a/rootston/pointer.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include -#include -#include "rootston/input.h" - -void pointer_add(struct wlr_input_device *device, struct roots_input *input) { - struct roots_pointer *pointer = calloc(sizeof(struct roots_pointer), 1); - device->data = pointer; - pointer->device = device; - pointer->input = input; - wl_list_insert(&input->pointers, &pointer->link); - wlr_cursor_attach_input_device(input->cursor, device); - cursor_load_config(input->server->config, input->cursor, - input, input->server->desktop); -} - -void pointer_remove(struct wlr_input_device *device, struct roots_input *input) { - struct roots_pointer *pointer = device->data; - wlr_cursor_detach_input_device(input->cursor, device); - wl_list_remove(&pointer->link); - free(pointer); -} diff --git a/rootston/rootston.ini.example b/rootston/rootston.ini.example index 433dc78f..c33b0f04 100644 --- a/rootston/rootston.ini.example +++ b/rootston/rootston.ini.example @@ -40,6 +40,6 @@ meta-key = Logo # - "close" to close the current view # - "next_window" to cycle through windows [bindings] -Logo+Shift+E = exit +Logo+Shift+e = exit Logo+q = close Alt+Tab = next_window diff --git a/rootston/seat.c b/rootston/seat.c new file mode 100644 index 00000000..1fa37c44 --- /dev/null +++ b/rootston/seat.c @@ -0,0 +1,579 @@ +#include +#include +#include +#include +#include +#include +#include "rootston/xcursor.h" +#include "rootston/input.h" +#include "rootston/seat.h" +#include "rootston/keyboard.h" +#include "rootston/cursor.h" + +static void handle_keyboard_key(struct wl_listener *listener, void *data) { + struct roots_keyboard *keyboard = + wl_container_of(listener, keyboard, keyboard_key); + struct wlr_event_keyboard_key *event = data; + roots_keyboard_handle_key(keyboard, event); +} + +static void handle_keyboard_modifiers(struct wl_listener *listener, + void *data) { + struct roots_keyboard *keyboard = + wl_container_of(listener, keyboard, keyboard_modifiers); + roots_keyboard_handle_modifiers(keyboard); +} + +static void handle_cursor_motion(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, motion); + struct wlr_event_pointer_motion *event = data; + roots_cursor_handle_motion(cursor, event); +} + +static void handle_cursor_motion_absolute(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, motion_absolute); + struct wlr_event_pointer_motion_absolute *event = data; + roots_cursor_handle_motion_absolute(cursor, event); +} + +static void handle_cursor_button(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, button); + struct wlr_event_pointer_button *event = data; + roots_cursor_handle_button(cursor, event); +} + +static void handle_cursor_axis(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, axis); + struct wlr_event_pointer_axis *event = data; + roots_cursor_handle_axis(cursor, event); +} + +static void handle_touch_down(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, touch_down); + struct wlr_event_touch_down *event = data; + roots_cursor_handle_touch_down(cursor, event); +} + +static void handle_touch_up(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, touch_up); + struct wlr_event_touch_up *event = data; + roots_cursor_handle_touch_up(cursor, event); +} + +static void handle_touch_motion(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, touch_motion); + struct wlr_event_touch_motion *event = data; + roots_cursor_handle_touch_motion(cursor, event); +} + +static void handle_tool_axis(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, tool_axis); + struct wlr_event_tablet_tool_axis *event = data; + roots_cursor_handle_tool_axis(cursor, event); +} + +static void handle_tool_tip(struct wl_listener *listener, void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, tool_tip); + struct wlr_event_tablet_tool_tip *event = data; + roots_cursor_handle_tool_tip(cursor, event); +} + +static void handle_request_set_cursor(struct wl_listener *listener, + void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, request_set_cursor); + struct wlr_seat_pointer_request_set_cursor_event *event = data; + roots_cursor_handle_request_set_cursor(cursor, event); +} + +static void handle_pointer_grab_begin(struct wl_listener *listener, + void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, pointer_grab_begin); + struct wlr_seat_pointer_grab *grab = data; + roots_cursor_handle_pointer_grab_begin(cursor, grab); +} + +static void handle_pointer_grab_end(struct wl_listener *listener, + void *data) { + struct roots_cursor *cursor = + wl_container_of(listener, cursor, pointer_grab_end); + struct wlr_seat_pointer_grab *grab = data; + roots_cursor_handle_pointer_grab_end(cursor, grab); +} + +static void seat_reset_device_mappings(struct roots_seat *seat, struct wlr_input_device *device) { + struct wlr_cursor *cursor = seat->cursor->cursor; + struct roots_config *config = seat->input->config; + + wlr_cursor_map_input_to_output(cursor, device, NULL); + struct roots_device_config *dconfig; + if ((dconfig = roots_config_get_device(config, device))) { + wlr_cursor_map_input_to_region(cursor, device, dconfig->mapped_box); + } +} + +static void seat_set_device_output_mappings(struct roots_seat *seat, + struct wlr_input_device *device, struct wlr_output *output) { + struct wlr_cursor *cursor = seat->cursor->cursor; + struct roots_config *config = seat->input->config; + struct roots_device_config *dconfig; + dconfig = roots_config_get_device(config, device); + if (dconfig && dconfig->mapped_output && + strcmp(dconfig->mapped_output, output->name) == 0) { + wlr_cursor_map_input_to_output(cursor, device, output); + } +} + +void roots_seat_configure_cursor(struct roots_seat *seat) { + struct roots_config *config = seat->input->config; + struct roots_desktop *desktop = seat->input->server->desktop; + struct wlr_cursor *cursor = seat->cursor->cursor; + + struct roots_pointer *pointer; + struct roots_touch *touch; + struct roots_tablet_tool *tablet_tool; + struct roots_output *output; + + // reset mappings + wlr_cursor_map_to_output(cursor, NULL); + wl_list_for_each(pointer, &seat->pointers, link) { + seat_reset_device_mappings(seat, pointer->device); + } + wl_list_for_each(touch, &seat->touch, link) { + seat_reset_device_mappings(seat, touch->device); + } + wl_list_for_each(tablet_tool, &seat->tablet_tools, link) { + seat_reset_device_mappings(seat, tablet_tool->device); + } + + // configure device to output mappings + const char *mapped_output = config->cursor.mapped_output; + wl_list_for_each(output, &desktop->outputs, link) { + if (mapped_output && strcmp(mapped_output, output->wlr_output->name) == 0) { + wlr_cursor_map_to_output(cursor, output->wlr_output); + } + + wl_list_for_each(pointer, &seat->pointers, link) { + seat_set_device_output_mappings(seat, pointer->device, output->wlr_output); + } + wl_list_for_each(tablet_tool, &seat->tablet_tools, link) { + seat_set_device_output_mappings(seat, tablet_tool->device, output->wlr_output); + } + wl_list_for_each(touch, &seat->touch, link) { + seat_set_device_output_mappings(seat, touch->device, output->wlr_output); + } + } +} + +static void roots_seat_init_cursor(struct roots_seat *seat) { + seat->cursor = roots_cursor_create(seat); + if (!seat->cursor) { + return; + } + seat->cursor->seat = seat; + struct wlr_cursor *wlr_cursor = seat->cursor->cursor; + struct roots_desktop *desktop = seat->input->server->desktop; + wlr_cursor_attach_output_layout(wlr_cursor, desktop->layout); + + // TODO: be able to configure per-seat cursor themes + seat->cursor->xcursor_manager = desktop->xcursor_manager; + + wl_list_init(&seat->cursor->touch_points); + + roots_seat_configure_cursor(seat); + roots_seat_configure_xcursor(seat); + + // add input signals + wl_signal_add(&wlr_cursor->events.motion, &seat->cursor->motion); + seat->cursor->motion.notify = handle_cursor_motion; + + wl_signal_add(&wlr_cursor->events.motion_absolute, + &seat->cursor->motion_absolute); + seat->cursor->motion_absolute.notify = handle_cursor_motion_absolute; + + wl_signal_add(&wlr_cursor->events.button, &seat->cursor->button); + seat->cursor->button.notify = handle_cursor_button; + + wl_signal_add(&wlr_cursor->events.axis, &seat->cursor->axis); + seat->cursor->axis.notify = handle_cursor_axis; + + wl_signal_add(&wlr_cursor->events.touch_down, &seat->cursor->touch_down); + seat->cursor->touch_down.notify = handle_touch_down; + + wl_signal_add(&wlr_cursor->events.touch_up, &seat->cursor->touch_up); + seat->cursor->touch_up.notify = handle_touch_up; + + wl_signal_add(&wlr_cursor->events.touch_motion, &seat->cursor->touch_motion); + seat->cursor->touch_motion.notify = handle_touch_motion; + + wl_signal_add(&wlr_cursor->events.tablet_tool_axis, &seat->cursor->tool_axis); + seat->cursor->tool_axis.notify = handle_tool_axis; + + wl_signal_add(&wlr_cursor->events.tablet_tool_tip, &seat->cursor->tool_tip); + seat->cursor->tool_tip.notify = handle_tool_tip; + + wl_signal_add(&seat->seat->events.request_set_cursor, + &seat->cursor->request_set_cursor); + seat->cursor->request_set_cursor.notify = handle_request_set_cursor; + + wl_signal_add(&seat->seat->events.pointer_grab_begin, + &seat->cursor->pointer_grab_begin); + seat->cursor->pointer_grab_begin.notify = handle_pointer_grab_begin; + + wl_signal_add(&seat->seat->events.pointer_grab_end, + &seat->cursor->pointer_grab_end); + seat->cursor->pointer_grab_end.notify = handle_pointer_grab_end; +} + +struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { + struct roots_seat *seat = calloc(1, sizeof(struct roots_seat)); + if (!seat) { + return NULL; + } + + wl_list_init(&seat->keyboards); + wl_list_init(&seat->pointers); + wl_list_init(&seat->touch); + wl_list_init(&seat->tablet_tools); + wl_list_init(&seat->drag_icons); + + seat->input = input; + + seat->seat = wlr_seat_create(input->server->wl_display, name); + if (!seat->seat) { + free(seat); + return NULL; + } + + roots_seat_init_cursor(seat); + if (!seat->cursor) { + wlr_seat_destroy(seat->seat); + free(seat); + return NULL; + } + + wlr_seat_set_capabilities(seat->seat, + WL_SEAT_CAPABILITY_KEYBOARD | + WL_SEAT_CAPABILITY_POINTER | + WL_SEAT_CAPABILITY_TOUCH); + + wl_list_insert(&input->seats, &seat->link); + + return seat; +} + +void roots_seat_destroy(struct roots_seat *seat) { + // TODO +} + +static void seat_add_keyboard(struct roots_seat *seat, struct wlr_input_device *device) { + assert(device->type == WLR_INPUT_DEVICE_KEYBOARD); + struct roots_keyboard *keyboard = roots_keyboard_create(device, seat->input); + if (keyboard == NULL) { + wlr_log(L_ERROR, "could not allocate keyboard for seat"); + return; + } + + keyboard->seat = seat; + + wl_list_insert(&seat->keyboards, &keyboard->link); + + keyboard->keyboard_key.notify = handle_keyboard_key; + wl_signal_add(&keyboard->device->keyboard->events.key, + &keyboard->keyboard_key); + + keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers; + wl_signal_add(&keyboard->device->keyboard->events.modifiers, + &keyboard->keyboard_modifiers); + + wlr_seat_set_keyboard(seat->seat, device); +} + +static void seat_add_pointer(struct roots_seat *seat, struct wlr_input_device *device) { + struct roots_pointer *pointer = calloc(sizeof(struct roots_pointer), 1); + if (!pointer) { + wlr_log(L_ERROR, "could not allocate pointer for seat"); + return; + } + + device->data = pointer; + pointer->device = device; + pointer->seat = seat; + wl_list_insert(&seat->pointers, &pointer->link); + wlr_cursor_attach_input_device(seat->cursor->cursor, device); + roots_seat_configure_cursor(seat); +} + +static void seat_add_touch(struct roots_seat *seat, struct wlr_input_device *device) { + struct roots_touch *touch = calloc(sizeof(struct roots_touch), 1); + if (!touch) { + wlr_log(L_ERROR, "could not allocate touch for seat"); + return; + } + + device->data = touch; + touch->device = device; + touch->seat = seat; + wl_list_insert(&seat->touch, &touch->link); + wlr_cursor_attach_input_device(seat->cursor->cursor, device); + roots_seat_configure_cursor(seat); +} + +static void seat_add_tablet_pad(struct roots_seat *seat, struct wlr_input_device *device) { + // TODO +} + +static void seat_add_tablet_tool(struct roots_seat *seat, struct wlr_input_device *device) { + struct roots_tablet_tool *tablet_tool = calloc(sizeof(struct roots_tablet_tool), 1); + if (!tablet_tool) { + wlr_log(L_ERROR, "could not allocate tablet_tool for seat"); + return; + } + + device->data = tablet_tool; + tablet_tool->device = device; + tablet_tool->seat = seat; + wl_list_insert(&seat->tablet_tools, &tablet_tool->link); + wlr_cursor_attach_input_device(seat->cursor->cursor, device); + roots_seat_configure_cursor(seat); +} + +void roots_seat_add_device(struct roots_seat *seat, + struct wlr_input_device *device) { + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + seat_add_keyboard(seat, device); + break; + case WLR_INPUT_DEVICE_POINTER: + seat_add_pointer(seat, device); + break; + case WLR_INPUT_DEVICE_TOUCH: + seat_add_touch(seat, device); + break; + case WLR_INPUT_DEVICE_TABLET_PAD: + seat_add_tablet_pad(seat, device); + break; + case WLR_INPUT_DEVICE_TABLET_TOOL: + seat_add_tablet_tool(seat, device); + break; + } +} + +static void seat_remove_keyboard(struct roots_seat *seat, + struct wlr_input_device *device) { + struct roots_keyboard *keyboard; + wl_list_for_each(keyboard, &seat->keyboards, link) { + if (keyboard->device == device) { + roots_keyboard_destroy(keyboard); + return; + } + } +} + +static void seat_remove_pointer(struct roots_seat *seat, + struct wlr_input_device *device) { + struct roots_pointer *pointer; + wl_list_for_each(pointer, &seat->pointers, link) { + if (pointer->device == device) { + wl_list_remove(&pointer->link); + wlr_cursor_detach_input_device(seat->cursor->cursor, device); + free(pointer); + return; + } + } +} + +static void seat_remove_touch(struct roots_seat *seat, + struct wlr_input_device *device) { + struct roots_touch *touch; + wl_list_for_each(touch, &seat->touch, link) { + if (touch->device == device) { + wl_list_remove(&touch->link); + wlr_cursor_detach_input_device(seat->cursor->cursor, device); + free(touch); + return; + } + } +} + +static void seat_remove_tablet_pad(struct roots_seat *seat, + struct wlr_input_device *device) { + // TODO +} + +static void seat_remove_tablet_tool(struct roots_seat *seat, + struct wlr_input_device *device) { + struct roots_tablet_tool *tablet_tool; + wl_list_for_each(tablet_tool, &seat->tablet_tools, link) { + if (tablet_tool->device == device) { + wl_list_remove(&tablet_tool->link); + wlr_cursor_detach_input_device(seat->cursor->cursor, device); + free(tablet_tool); + return; + } + } +} + +void roots_seat_remove_device(struct roots_seat *seat, + struct wlr_input_device *device) { + switch (device->type) { + case WLR_INPUT_DEVICE_KEYBOARD: + seat_remove_keyboard(seat, device); + break; + case WLR_INPUT_DEVICE_POINTER: + seat_remove_pointer(seat, device); + break; + case WLR_INPUT_DEVICE_TOUCH: + seat_remove_touch(seat, device); + break; + case WLR_INPUT_DEVICE_TABLET_PAD: + seat_remove_tablet_pad(seat, device); + break; + case WLR_INPUT_DEVICE_TABLET_TOOL: + seat_remove_tablet_tool(seat, device); + break; + } +} + +void roots_seat_configure_xcursor(struct roots_seat *seat) { + struct roots_output *output; + wl_list_for_each(output, &seat->input->server->desktop->outputs, link) { + if (wlr_xcursor_manager_load(seat->cursor->xcursor_manager, + output->wlr_output->scale)) { + wlr_log(L_ERROR, "Cannot load xcursor theme for output '%s' " + "with scale %d", output->wlr_output->name, + output->wlr_output->scale); + } + } + + wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, + ROOTS_XCURSOR_DEFAULT, seat->cursor->cursor); + wlr_cursor_warp(seat->cursor->cursor, NULL, seat->cursor->cursor->x, + seat->cursor->cursor->y); +} + +bool roots_seat_has_meta_pressed(struct roots_seat *seat) { + struct roots_keyboard *keyboard; + wl_list_for_each(keyboard, &seat->keyboards, link) { + if (!keyboard->config->meta_key) { + continue; + } + + uint32_t modifiers = + wlr_keyboard_get_modifiers(keyboard->device->keyboard); + if ((modifiers ^ keyboard->config->meta_key) == 0) { + return true; + } + } + + return false; +} + +void roots_seat_focus_view(struct roots_seat *seat, struct roots_view *view) { + struct roots_desktop *desktop = seat->input->server->desktop; + if (seat->focus == view) { + return; + } + + if (view && view->type == ROOTS_XWAYLAND_VIEW && + view->xwayland_surface->override_redirect) { + return; + } + + struct roots_view *prev_focus = seat->focus; + seat->focus = view; + + // unfocus the old view if it is not focused by some other seat + if (prev_focus && !input_view_has_focus(seat->input, prev_focus)) { + view_activate(prev_focus, false); + } + + if (!seat->focus) { + seat->cursor->mode = ROOTS_CURSOR_PASSTHROUGH; + return; + } + + size_t index = 0; + for (size_t i = 0; i < desktop->views->length; ++i) { + struct roots_view *_view = desktop->views->items[i]; + if (_view == view) { + index = i; + break; + } + } + + view_activate(view, true); + // TODO: list_swap + wlr_list_del(desktop->views, index); + wlr_list_add(desktop->views, view); + wlr_seat_keyboard_notify_enter(seat->seat, view->wlr_surface); +} + +void roots_seat_begin_move(struct roots_seat *seat, struct roots_view *view) { + struct roots_cursor *cursor = seat->cursor; + cursor->mode = ROOTS_CURSOR_MOVE; + cursor->offs_x = cursor->cursor->x; + cursor->offs_y = cursor->cursor->y; + if (view->maximized) { + cursor->view_x = view->saved.x; + cursor->view_y = view->saved.y; + } else { + cursor->view_x = view->x; + cursor->view_y = view->y; + } + view_maximize(view, false); + wlr_seat_pointer_clear_focus(seat->seat); + + wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, + ROOTS_XCURSOR_MOVE, seat->cursor->cursor); +} + +void roots_seat_begin_resize(struct roots_seat *seat, struct roots_view *view, + uint32_t edges) { + struct roots_cursor *cursor = seat->cursor; + cursor->mode = ROOTS_CURSOR_RESIZE; + cursor->offs_x = cursor->cursor->x; + cursor->offs_y = cursor->cursor->y; + if (view->maximized) { + cursor->view_x = view->saved.x; + cursor->view_y = view->saved.y; + cursor->view_width = view->saved.width; + cursor->view_height = view->saved.height; + } else { + cursor->view_x = view->x; + cursor->view_y = view->y; + struct wlr_box box; + view_get_box(view, &box); + cursor->view_width = box.width; + cursor->view_height = box.height; + } + cursor->resize_edges = edges; + view_maximize(view, false); + wlr_seat_pointer_clear_focus(seat->seat); + + wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, + roots_xcursor_get_resize_name(edges), seat->cursor->cursor); +} + +void roots_seat_begin_rotate(struct roots_seat *seat, struct roots_view *view) { + struct roots_cursor *cursor = seat->cursor; + cursor->mode = ROOTS_CURSOR_ROTATE; + cursor->offs_x = cursor->cursor->x; + cursor->offs_y = cursor->cursor->y; + cursor->view_rotation = view->rotation; + view_maximize(view, false); + wlr_seat_pointer_clear_focus(seat->seat); + + wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, + ROOTS_XCURSOR_ROTATE, seat->cursor->cursor); +} diff --git a/rootston/tablet_tool.c b/rootston/tablet_tool.c deleted file mode 100644 index a612e683..00000000 --- a/rootston/tablet_tool.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include -#include -#include -#include "rootston/input.h" - -void tablet_tool_add(struct wlr_input_device *device, struct roots_input *input) { - struct roots_tablet_tool *tool = calloc(sizeof(struct roots_tablet_tool), 1); - device->data = tool; - tool->device = device; - tool->input = input; - wl_list_insert(&input->tablet_tools, &tool->link); - wlr_cursor_attach_input_device(input->cursor, device); - cursor_load_config(input->server->config, input->cursor, - input, input->server->desktop); -} - -void tablet_tool_remove(struct wlr_input_device *device, struct roots_input *input) { - struct roots_tablet_tool *tablet_tool = device->data; - wlr_cursor_detach_input_device(input->cursor, device); - wl_list_remove(&tablet_tool->link); - free(tablet_tool); -} diff --git a/rootston/touch.c b/rootston/touch.c deleted file mode 100644 index f6d9b11a..00000000 --- a/rootston/touch.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include -#include -#include "rootston/input.h" - -// TODO: we'll likely want touch events to both control the cursor *and* be -// submitted directly to the seat. - -void touch_add(struct wlr_input_device *device, struct roots_input *input) { - struct roots_touch *touch = calloc(sizeof(struct roots_touch), 1); - device->data = touch; - touch->device = device; - touch->input = input; - wl_list_insert(&input->touch, &touch->link); - wlr_cursor_attach_input_device(input->cursor, device); - cursor_load_config(input->server->config, input->cursor, - input, input->server->desktop); -} - -void touch_remove(struct wlr_input_device *device, struct roots_input *input) { - struct roots_touch *touch = device->data; - wlr_cursor_detach_input_device(input->cursor, device); - wl_list_remove(&touch->link); - free(touch); -} diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index e38eb697..96f461fe 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -29,11 +29,11 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_view *view = roots_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_wl_shell_surface_move_event *e = data; - const struct roots_input_event *event = get_input_event(input, e->serial); - if (!event || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_move(input, event->cursor, view); + roots_seat_begin_move(seat, view); } static void handle_request_resize(struct wl_listener *listener, void *data) { @@ -42,11 +42,32 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct roots_view *view = roots_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_wl_shell_surface_resize_event *e = data; - const struct roots_input_event *event = get_input_event(input, e->serial); - if (!event || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + // TODO verify input event + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_resize(input, event->cursor, view, e->edges); + roots_seat_begin_resize(seat, view, e->edges); +} + +static void handle_request_set_maximized(struct wl_listener *listener, + void *data) { + struct roots_wl_shell_surface *roots_surface = + wl_container_of(listener, roots_surface, request_set_maximized); + struct roots_view *view = roots_surface->view; + //struct wlr_wl_shell_surface_set_maximized_event *e = data; + view_maximize(view, true); +} + +static void handle_set_state(struct wl_listener *listener, void *data) { + struct roots_wl_shell_surface *roots_surface = + wl_container_of(listener, roots_surface, set_state); + struct roots_view *view = roots_surface->view; + struct wlr_wl_shell_surface *surface = view->wl_shell_surface; + if (view->maximized && + surface->state != WLR_WL_SHELL_SURFACE_STATE_MAXIMIZED) { + view_maximize(view, false); + } } static void handle_surface_commit(struct wl_listener *listener, void *data) { @@ -60,6 +81,9 @@ static void handle_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&roots_surface->destroy.link); wl_list_remove(&roots_surface->request_move.link); wl_list_remove(&roots_surface->request_resize.link); + wl_list_remove(&roots_surface->request_set_maximized.link); + wl_list_remove(&roots_surface->set_state.link); + wl_list_remove(&roots_surface->surface_commit.link); view_destroy(roots_surface->view); free(roots_surface); } @@ -93,6 +117,11 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { roots_surface->request_resize.notify = handle_request_resize; wl_signal_add(&surface->events.request_resize, &roots_surface->request_resize); + roots_surface->request_set_maximized.notify = handle_request_set_maximized; + wl_signal_add(&surface->events.request_set_maximized, + &roots_surface->request_set_maximized); + roots_surface->set_state.notify = handle_set_state; + wl_signal_add(&surface->events.set_state, &roots_surface->set_state); roots_surface->surface_commit.notify = handle_surface_commit; wl_signal_add(&surface->surface->events.commit, &roots_surface->surface_commit); diff --git a/rootston/xcursor.c b/rootston/xcursor.c index 43cbfc51..74e732c9 100644 --- a/rootston/xcursor.c +++ b/rootston/xcursor.c @@ -1,15 +1,10 @@ -#include +#define _POSIX_C_SOURCE 200809L +#include +#include +#include "rootston/xcursor.h" #include "rootston/input.h" -struct wlr_xcursor *get_default_xcursor(struct wlr_xcursor_theme *theme) { - return wlr_xcursor_theme_get_cursor(theme, "left_ptr"); -} - -struct wlr_xcursor *get_move_xcursor(struct wlr_xcursor_theme *theme) { - return wlr_xcursor_theme_get_cursor(theme, "grabbing"); -} - -static const char *get_resize_xcursor_name(uint32_t edges) { +const char *roots_xcursor_get_resize_name(uint32_t edges) { if (edges & ROOTS_CURSOR_RESIZE_EDGE_TOP) { if (edges & ROOTS_CURSOR_RESIZE_EDGE_RIGHT) { return "ne-resize"; @@ -31,12 +26,3 @@ static const char *get_resize_xcursor_name(uint32_t edges) { } return "se-resize"; // fallback } - -struct wlr_xcursor *get_resize_xcursor(struct wlr_xcursor_theme *theme, - uint32_t edges) { - return wlr_xcursor_theme_get_cursor(theme, get_resize_xcursor_name(edges)); -} - -struct wlr_xcursor *get_rotate_xcursor(struct wlr_xcursor_theme *theme) { - return wlr_xcursor_theme_get_cursor(theme, "grabbing"); -} diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 38341922..f9c905dd 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -10,11 +10,17 @@ #include "rootston/server.h" #include "rootston/input.h" -static void get_size(struct roots_view *view, struct wlr_box *box) { +static void get_size(const struct roots_view *view, struct wlr_box *box) { assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; - // TODO: surface->geometry can be NULL - memcpy(box, surface->geometry, sizeof(struct wlr_box)); + + if (surface->geometry->width > 0 && surface->geometry->height > 0) { + box->width = surface->geometry->width; + box->height = surface->geometry->height; + } else { + box->width = view->wlr_surface->current->width; + box->height = view->wlr_surface->current->height; + } } static void activate(struct roots_view *view, bool active) { @@ -87,6 +93,16 @@ static void move_resize(struct roots_view *view, double x, double y, constrained_height); } +static void maximize(struct roots_view *view, bool maximized) { + assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); + struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + return; + } + + wlr_xdg_toplevel_v6_set_maximized(surface, maximized); +} + static void close(struct roots_view *view) { assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; @@ -101,11 +117,12 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_view *view = roots_xdg_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_xdg_toplevel_v6_move_event *e = data; - const struct roots_input_event *event = get_input_event(input, e->serial); - if (!event || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + // TODO verify event serial + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_move(input, event->cursor, view); + roots_seat_begin_move(seat, view); } static void handle_request_resize(struct wl_listener *listener, void *data) { @@ -114,11 +131,26 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { struct roots_view *view = roots_xdg_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_xdg_toplevel_v6_resize_event *e = data; - const struct roots_input_event *event = get_input_event(input, e->serial); - if (!event || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + // TODO verify event serial + struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); + assert(seat); + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_resize(input, event->cursor, view, e->edges); + roots_seat_begin_resize(seat, view, e->edges); +} + +static void handle_request_maximize(struct wl_listener *listener, void *data) { + struct roots_xdg_surface_v6 *roots_xdg_surface = + wl_container_of(listener, roots_xdg_surface, request_maximize); + struct roots_view *view = roots_xdg_surface->view; + struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + + if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { + return; + } + + view_maximize(view, surface->toplevel_state->next.maximized); } static void handle_commit(struct wl_listener *listener, void *data) { @@ -178,6 +210,9 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { roots_surface->request_resize.notify = handle_request_resize; wl_signal_add(&surface->events.request_resize, &roots_surface->request_resize); + roots_surface->request_maximize.notify = handle_request_maximize; + wl_signal_add(&surface->events.request_maximize, + &roots_surface->request_maximize); struct roots_view *view = calloc(1, sizeof(struct roots_view)); if (!view) { @@ -192,6 +227,7 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { view->activate = activate; view->resize = resize; view->move_resize = move_resize; + view->maximize = maximize; view->close = close; view->desktop = desktop; roots_surface->view = view; diff --git a/rootston/xwayland.c b/rootston/xwayland.c index 76cdf05a..f1093552 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -85,11 +85,22 @@ static void close(struct roots_view *view) { wlr_xwayland_surface_close(view->desktop->xwayland, view->xwayland_surface); } +static void maximize(struct roots_view *view, bool maximized) { + assert(view->type == ROOTS_XWAYLAND_VIEW); + + wlr_xwayland_surface_set_maximized(view->desktop->xwayland, + view->xwayland_surface, maximized); +} + static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, destroy); view_teardown(roots_surface->view); wl_list_remove(&roots_surface->destroy.link); + wl_list_remove(&roots_surface->request_configure.link); + wl_list_remove(&roots_surface->request_move.link); + wl_list_remove(&roots_surface->request_resize.link); + wl_list_remove(&roots_surface->request_maximize.link); wl_list_remove(&roots_surface->map_notify.link); wl_list_remove(&roots_surface->unmap_notify.link); view_destroy(roots_surface->view); @@ -110,26 +121,16 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { xwayland_surface, event->x, event->y, event->width, event->height); } -// XXX Needs deep refactoring to get this better. We need to select the correct -// seat based on seat pointer focus, but interactive moving and resizing is not -// yet seat aware. Even then, we can only guess because X11 events don't give us -// enough wayland info to know for sure. -static struct wlr_cursor *guess_cursor_for_view(struct roots_view *view) { +static struct roots_seat *guess_seat_for_view(struct roots_view *view) { + // the best we can do is to pick the first seat that has the surface focused + // for the pointer struct roots_input *input = view->desktop->server->input; - size_t len = sizeof(input->input_events) / sizeof(*input->input_events); - for (size_t i = 0; i < len; i++) { - struct wlr_cursor *cursor = input->input_events[i].cursor; - if (cursor) { - int width = view->xwayland_surface->surface->current->width; - int height = view->xwayland_surface->surface->current->height; - if (cursor->x > view->x && cursor->y > view->y && - cursor->x < view->x + width && - cursor->y < view->y + height) { - return cursor; - } + struct roots_seat *seat; + wl_list_for_each(seat, &input->seats, link) { + if (seat->seat->pointer_state.focused_surface == view->wlr_surface) { + return seat; } } - return NULL; } @@ -137,28 +138,37 @@ static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, request_move); struct roots_view *view = roots_surface->view; - struct roots_input *input = view->desktop->server->input; - struct wlr_cursor *cursor = guess_cursor_for_view(view); + struct roots_seat *seat = guess_seat_for_view(view); - if (!cursor || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_move(input, cursor, view); + roots_seat_begin_move(seat, view); } static void handle_request_resize(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, request_resize); struct roots_view *view = roots_surface->view; - struct roots_input *input = view->desktop->server->input; - struct wlr_cursor *cursor = guess_cursor_for_view(view); + struct roots_seat *seat = guess_seat_for_view(view); struct wlr_xwayland_resize_event *e = data; - if (!cursor || input->mode != ROOTS_CURSOR_PASSTHROUGH) { + if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { return; } - view_begin_resize(input, cursor, view, e->edges); + roots_seat_begin_resize(seat, view, e->edges); +} + +static void handle_request_maximize(struct wl_listener *listener, void *data) { + struct roots_xwayland_surface *roots_surface = + wl_container_of(listener, roots_surface, request_maximize); + struct roots_view *view = roots_surface->view; + struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; + + bool maximized = xwayland_surface->maximized_vert && + xwayland_surface->maximized_horz; + view_maximize(view, maximized); } static void handle_map_notify(struct wl_listener *listener, void *data) { @@ -202,24 +212,24 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { if (roots_surface == NULL) { return; } + roots_surface->destroy.notify = handle_destroy; wl_signal_add(&surface->events.destroy, &roots_surface->destroy); - roots_surface->request_configure.notify = handle_request_configure; wl_signal_add(&surface->events.request_configure, &roots_surface->request_configure); - roots_surface->map_notify.notify = handle_map_notify; wl_signal_add(&surface->events.map_notify, &roots_surface->map_notify); - roots_surface->unmap_notify.notify = handle_unmap_notify; wl_signal_add(&surface->events.unmap_notify, &roots_surface->unmap_notify); - roots_surface->request_move.notify = handle_request_move; wl_signal_add(&surface->events.request_move, &roots_surface->request_move); - roots_surface->request_resize.notify = handle_request_resize; - wl_signal_add(&surface->events.request_resize, &roots_surface->request_resize); + wl_signal_add(&surface->events.request_resize, + &roots_surface->request_resize); + roots_surface->request_maximize.notify = handle_request_maximize; + wl_signal_add(&surface->events.request_maximize, + &roots_surface->request_maximize); struct roots_view *view = calloc(1, sizeof(struct roots_view)); if (view == NULL) { @@ -237,6 +247,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { view->resize = resize; view->move = move; view->move_resize = move_resize; + view->maximize = maximize; view->close = close; roots_surface->view = view; wlr_list_add(desktop->views, view); diff --git a/types/meson.build b/types/meson.build index 2603ecfd..4669165a 100644 --- a/types/meson.build +++ b/types/meson.build @@ -20,8 +20,9 @@ lib_wlr_types = static_library( 'wlr_tablet_pad.c', 'wlr_tablet_tool.c', 'wlr_touch.c', - 'wlr_xdg_shell_v6.c', 'wlr_wl_shell.c', + 'wlr_xcursor_manager.c', + 'wlr_xdg_shell_v6.c', ), include_directories: wlr_inc, dependencies: [wayland_server, pixman, wlr_protos], diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index 83d36d14..e8965b68 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -261,8 +261,8 @@ void wlr_cursor_warp_absolute(struct wlr_cursor *cur, mapping = wlr_output_layout_get_box(cur->state->layout, NULL); } - double x = mapping->width * x_mm + mapping->x; - double y = mapping->height * y_mm + mapping->y; + double x = x_mm > 0 ? mapping->width * x_mm + mapping->x : cur->x; + double y = y_mm > 0 ? mapping->height * y_mm + mapping->y : cur->y; wlr_cursor_warp_unchecked(cur, x, y); } @@ -299,9 +299,14 @@ void wlr_cursor_move(struct wlr_cursor *cur, struct wlr_input_device *dev, void wlr_cursor_set_image(struct wlr_cursor *cur, const uint8_t *pixels, int32_t stride, uint32_t width, uint32_t height, int32_t hotspot_x, - int32_t hotspot_y) { + int32_t hotspot_y, uint32_t scale) { struct wlr_cursor_output_cursor *output_cursor; wl_list_for_each(output_cursor, &cur->state->output_cursors, link) { + if (scale != 0 && + output_cursor->output_cursor->output->scale != scale) { + continue; + } + wlr_output_cursor_set_image(output_cursor->output_cursor, pixels, stride, width, height, hotspot_x, hotspot_y); } diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index ee83260e..4d926236 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -531,9 +531,8 @@ static void keyboard_drag_key(struct wlr_seat_keyboard_grab *grab, // no keyboard input during drags } -static void keyboard_drag_modifiers(struct wlr_seat_keyboard_grab *grab, - uint32_t mods_depressed, uint32_t mods_latched, - uint32_t mods_locked, uint32_t group) { +static void keyboard_drag_modifiers(struct wlr_seat_keyboard_grab *grab) { + //struct wlr_keyboard *keyboard = grab->seat->keyboard_state.keyboard; // TODO change the dnd action based on what modifier is pressed on the // keyboard } @@ -637,7 +636,10 @@ static void data_device_start_drag(struct wl_client *client, if (!seat_client_start_drag(seat_client, source, icon)) { wl_resource_post_no_memory(device_resource); - } else { + return; + } + + if (source) { source->seat_client = seat_client; } } @@ -816,3 +818,11 @@ struct wlr_data_device_manager *wlr_data_device_manager_create( return manager; } + +void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager) { + if (!manager) { + return; + } + wl_global_destroy(manager->global); + free(manager); +} diff --git a/types/wlr_keyboard.c b/types/wlr_keyboard.c index c27264ef..c4f2ed52 100644 --- a/types/wlr_keyboard.c +++ b/types/wlr_keyboard.c @@ -45,6 +45,30 @@ static void keyboard_modifier_update(struct wlr_keyboard *keyboard) { wl_signal_emit(&keyboard->events.modifiers, keyboard); } +static void keyboard_key_update(struct wlr_keyboard *keyboard, + struct wlr_event_keyboard_key *event) { + bool found = false; + size_t i = 0; + for (; i < WLR_KEYBOARD_KEYS_CAP; ++i) { + if (keyboard->keycodes[i] == event->keycode) { + found = true; + break; + } + } + + if (event->state == WLR_KEY_PRESSED && !found) { + for (size_t i = 0; i < WLR_KEYBOARD_KEYS_CAP; ++i) { + if (keyboard->keycodes[i] == 0) { + keyboard->keycodes[i] = event->keycode; + break; + } + } + } + if (event->state == WLR_KEY_RELEASED && found) { + keyboard->keycodes[i] = 0; + } +} + void wlr_keyboard_notify_modifiers(struct wlr_keyboard *keyboard, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group) { @@ -68,6 +92,7 @@ void wlr_keyboard_notify_key(struct wlr_keyboard *keyboard, } keyboard_led_update(keyboard); keyboard_modifier_update(keyboard); + keyboard_key_update(keyboard, event); wl_signal_emit(&keyboard->events.key, event); } @@ -80,7 +105,10 @@ void wlr_keyboard_init(struct wlr_keyboard *kb, } void wlr_keyboard_destroy(struct wlr_keyboard *kb) { - if (kb && kb->impl && kb->impl->destroy) { + if (kb == NULL) { + return; + } + if (kb->impl && kb->impl->destroy) { kb->impl->destroy(kb); } else { wl_list_remove(&kb->events.key.listener_list); diff --git a/types/wlr_output.c b/types/wlr_output.c index 5456d064..411dd404 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -29,8 +29,7 @@ static void wl_output_send_to_resource(struct wl_resource *resource) { if (version >= WL_OUTPUT_MODE_SINCE_VERSION) { struct wlr_output_mode *mode; wl_list_for_each(mode, &output->modes, link) { - // TODO: mode->flags should just be preferred - uint32_t flags = mode->flags; + uint32_t flags = mode->flags & WL_OUTPUT_MODE_PREFERRED; if (output->current_mode == mode) { flags |= WL_OUTPUT_MODE_CURRENT; } @@ -62,13 +61,17 @@ static void wlr_output_send_current_mode_to_resource( } if (output->current_mode != NULL) { struct wlr_output_mode *mode = output->current_mode; - wl_output_send_mode(resource, mode->flags | WL_OUTPUT_MODE_CURRENT, + uint32_t flags = mode->flags & WL_OUTPUT_MODE_PREFERRED; + wl_output_send_mode(resource, flags | WL_OUTPUT_MODE_CURRENT, mode->width, mode->height, mode->refresh); } else { // Output has no mode, send the current width/height wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT, output->width, output->height, 0); } + if (version >= WL_OUTPUT_DONE_SINCE_VERSION) { + wl_output_send_done(resource); + } } static void wl_output_destroy(struct wl_resource *resource) { @@ -163,6 +166,9 @@ bool wlr_output_set_mode(struct wlr_output *output, void wlr_output_update_size(struct wlr_output *output, int32_t width, int32_t height) { + if (output->width == width && output->height == height) { + return; + } output->width = width; output->height = height; wlr_output_update_matrix(output); @@ -231,7 +237,6 @@ void wlr_output_destroy(struct wlr_output *output) { void wlr_output_effective_resolution(struct wlr_output *output, int *width, int *height) { - // TODO: Scale factor if (output->transform % 2 == 1) { *width = output->height; *height = output->width; @@ -239,6 +244,8 @@ void wlr_output_effective_resolution(struct wlr_output *output, *width = output->width; *height = output->height; } + *width /= output->scale; + *height /= output->scale; } void wlr_output_make_current(struct wlr_output *output) { @@ -269,6 +276,8 @@ static void output_cursor_render(struct wlr_output_cursor *cursor) { output_box.x = output_box.y = 0; wlr_output_effective_resolution(cursor->output, &output_box.width, &output_box.height); + output_box.width *= cursor->output->scale; + output_box.height *= cursor->output->scale; struct wlr_box cursor_box; output_cursor_get_box(cursor, &cursor_box); @@ -471,7 +480,10 @@ void wlr_output_cursor_set_surface(struct wlr_output_cursor *cursor, } } -bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, int x, int y) { +bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, + double x, double y) { + x *= cursor->output->scale; + y *= cursor->output->scale; cursor->x = x; cursor->y = y; @@ -483,7 +495,7 @@ bool wlr_output_cursor_move(struct wlr_output_cursor *cursor, int x, int y) { if (!cursor->output->impl->move_cursor) { return false; } - return cursor->output->impl->move_cursor(cursor->output, x, y); + return cursor->output->impl->move_cursor(cursor->output, (int)x, (int)y); } struct wlr_output_cursor *wlr_output_cursor_create(struct wlr_output *output) { diff --git a/types/wlr_screenshooter.c b/types/wlr_screenshooter.c index a78c7ad7..94b45384 100644 --- a/types/wlr_screenshooter.c +++ b/types/wlr_screenshooter.c @@ -85,6 +85,7 @@ static void screenshooter_shoot(struct wl_client *client, struct wlr_screenshot *screenshot = calloc(1, sizeof(struct wlr_screenshot)); if (!screenshot) { + free(pixels); wl_resource_post_no_memory(screenshooter_resource); return; } @@ -96,6 +97,7 @@ static void screenshooter_shoot(struct wl_client *client, wl_resource_get_version(screenshooter_resource), id); if (screenshot->resource == NULL) { free(screenshot); + free(pixels); wl_resource_post_no_memory(screenshooter_resource); return; } @@ -109,6 +111,7 @@ static void screenshooter_shoot(struct wl_client *client, if (!state) { wl_resource_destroy(screenshot->resource); free(screenshot); + free(pixels); wl_resource_post_no_memory(screenshooter_resource); return; } diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 76b34d31..dad88354 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -284,11 +285,8 @@ static void default_keyboard_key(struct wlr_seat_keyboard_grab *grab, wlr_seat_keyboard_send_key(grab->seat, time, key, state); } -static void default_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab, - uint32_t mods_depressed, uint32_t mods_latched, - uint32_t mods_locked, uint32_t group) { - wlr_seat_keyboard_send_modifiers(grab->seat, mods_depressed, - mods_latched, mods_locked, group); +static void default_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab) { + wlr_seat_keyboard_send_modifiers(grab->seat); } static void default_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) { @@ -577,12 +575,14 @@ void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat, void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, uint32_t time, double sx, double sy) { + clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event); struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab; grab->interface->motion(grab, time, sx, sy); } uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat, uint32_t time, uint32_t button, uint32_t state) { + clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event); if (state == WL_POINTER_BUTTON_STATE_PRESSED) { if (wlr_seat->pointer_state.button_count == 0) { wlr_seat->pointer_state.grab_button = button; @@ -605,6 +605,7 @@ uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat, void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time, enum wlr_axis_orientation orientation, double value) { + clock_gettime(CLOCK_MONOTONIC, &wlr_seat->last_event); struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab; grab->interface->axis(grab, time, orientation, value); } @@ -708,24 +709,26 @@ static void keyboard_resource_destroy_notify(struct wl_listener *listener, wlr_seat_keyboard_clear_focus(state->seat); } -void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat, - uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, - uint32_t group) { +void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat) { struct wlr_seat_client *client = seat->keyboard_state.focused_client; if (!client || !client->keyboard) { return; } - uint32_t serial = wl_display_next_serial(seat->display); + struct wlr_keyboard *keyboard = seat->keyboard_state.keyboard; + if (!keyboard) { + return; + } + uint32_t serial = wl_display_next_serial(seat->display); wl_keyboard_send_modifiers(client->keyboard, serial, - mods_depressed, mods_latched, - mods_locked, group); + keyboard->modifiers.depressed, keyboard->modifiers.latched, + keyboard->modifiers.locked, keyboard->modifiers.group); } -void wlr_seat_keyboard_enter(struct wlr_seat *wlr_seat, +void wlr_seat_keyboard_enter(struct wlr_seat *seat, struct wlr_surface *surface) { - if (wlr_seat->keyboard_state.focused_surface == surface) { + if (seat->keyboard_state.focused_surface == surface) { // this surface already got an enter notify return; } @@ -734,75 +737,85 @@ void wlr_seat_keyboard_enter(struct wlr_seat *wlr_seat, if (surface) { struct wl_client *wl_client = wl_resource_get_client(surface->resource); - client = wlr_seat_client_for_wl_client(wlr_seat, wl_client); + client = wlr_seat_client_for_wl_client(seat, wl_client); } struct wlr_seat_client *focused_client = - wlr_seat->keyboard_state.focused_client; + seat->keyboard_state.focused_client; struct wlr_surface *focused_surface = - wlr_seat->keyboard_state.focused_surface; + seat->keyboard_state.focused_surface; // leave the previously entered surface if (focused_client && focused_client->keyboard && focused_surface) { - uint32_t serial = wl_display_next_serial(wlr_seat->display); + uint32_t serial = wl_display_next_serial(seat->display); wl_keyboard_send_leave(focused_client->keyboard, serial, focused_surface->resource); } // enter the current surface - if (client && client->keyboard) { - // TODO: read the currently pressed keys out of the active keyboard and - // put them in this array + if (client && client->keyboard && seat->keyboard_state.keyboard) { + struct wlr_keyboard *keyboard = seat->keyboard_state.keyboard; + struct wl_array keys; wl_array_init(&keys); - uint32_t serial = wl_display_next_serial(wlr_seat->display); + size_t n = 0; + for (size_t i = 0; i < WLR_KEYBOARD_KEYS_CAP; ++i) { + if (keyboard->keycodes[i] != 0) { + wl_array_add(&keys, sizeof(uint32_t)); + ((uint32_t *)keys.data)[n] = keyboard->keycodes[i]; + n++; + } + } + uint32_t serial = wl_display_next_serial(seat->display); wl_keyboard_send_enter(client->keyboard, serial, surface->resource, &keys); + wl_array_release(&keys); + + wlr_seat_keyboard_send_modifiers(seat); wlr_seat_client_send_selection(client); } // reinitialize the focus destroy events - wl_list_remove(&wlr_seat->keyboard_state.surface_destroy.link); - wl_list_init(&wlr_seat->keyboard_state.surface_destroy.link); - wl_list_remove(&wlr_seat->keyboard_state.resource_destroy.link); - wl_list_init(&wlr_seat->keyboard_state.resource_destroy.link); + wl_list_remove(&seat->keyboard_state.surface_destroy.link); + wl_list_init(&seat->keyboard_state.surface_destroy.link); + wl_list_remove(&seat->keyboard_state.resource_destroy.link); + wl_list_init(&seat->keyboard_state.resource_destroy.link); if (surface) { wl_signal_add(&surface->events.destroy, - &wlr_seat->keyboard_state.surface_destroy); + &seat->keyboard_state.surface_destroy); wl_resource_add_destroy_listener(surface->resource, - &wlr_seat->keyboard_state.resource_destroy); - wlr_seat->keyboard_state.resource_destroy.notify = + &seat->keyboard_state.resource_destroy); + seat->keyboard_state.resource_destroy.notify = keyboard_resource_destroy_notify; - wlr_seat->keyboard_state.surface_destroy.notify = + seat->keyboard_state.surface_destroy.notify = keyboard_surface_destroy_notify; } - wlr_seat->keyboard_state.focused_client = client; - wlr_seat->keyboard_state.focused_surface = surface; + seat->keyboard_state.focused_client = client; + seat->keyboard_state.focused_surface = surface; } -void wlr_seat_keyboard_notify_enter(struct wlr_seat *wlr_seat, struct +void wlr_seat_keyboard_notify_enter(struct wlr_seat *seat, struct wlr_surface *surface) { - struct wlr_seat_keyboard_grab *grab = wlr_seat->keyboard_state.grab; + struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; grab->interface->enter(grab, surface); } -void wlr_seat_keyboard_clear_focus(struct wlr_seat *wlr_seat) { +void wlr_seat_keyboard_clear_focus(struct wlr_seat *seat) { struct wl_array keys; wl_array_init(&keys); - wlr_seat_keyboard_enter(wlr_seat, NULL); + wlr_seat_keyboard_enter(seat, NULL); } -void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat, - uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, - uint32_t group) { +void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat) { + clock_gettime(CLOCK_MONOTONIC, &seat->last_event); struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; - grab->interface->modifiers(grab, - mods_depressed, mods_latched, mods_locked, group); + grab->interface->modifiers(grab); } void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time, uint32_t key, uint32_t state) { + clock_gettime(CLOCK_MONOTONIC, &seat->last_event); struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; grab->interface->key(grab, time, key, state); } diff --git a/types/wlr_surface.c b/types/wlr_surface.c index 48971849..8cc2aa33 100644 --- a/types/wlr_surface.c +++ b/types/wlr_surface.c @@ -649,8 +649,8 @@ void wlr_surface_get_matrix(struct wlr_surface *surface, float (*matrix)[16], const float (*projection)[16], const float (*transform)[16]) { - int width = surface->texture->width / surface->current->scale; - int height = surface->texture->height / surface->current->scale; + int width = surface->texture->width; + int height = surface->texture->height; float scale[16]; wlr_matrix_identity(matrix); if (transform) { @@ -905,3 +905,27 @@ struct wlr_subsurface *wlr_surface_subsurface_at(struct wlr_surface *surface, return NULL; } + +void wlr_surface_send_enter(struct wlr_surface *surface, + struct wlr_output *output) { + struct wl_client *client = wl_resource_get_client(surface->resource); + struct wl_resource *resource; + wl_resource_for_each(resource, &output->wl_resources) { + if (client == wl_resource_get_client(resource)) { + wl_surface_send_enter(surface->resource, resource); + break; + } + } +} + +void wlr_surface_send_leave(struct wlr_surface *surface, + struct wlr_output *output) { + struct wl_client *client = wl_resource_get_client(surface->resource); + struct wl_resource *resource; + wl_resource_for_each(resource, &output->wl_resources) { + if (client == wl_resource_get_client(resource)) { + wl_surface_send_leave(surface->resource, resource); + break; + } + } +} diff --git a/types/wlr_wl_shell.c b/types/wlr_wl_shell.c index fe61075e..abe967d7 100644 --- a/types/wlr_wl_shell.c +++ b/types/wlr_wl_shell.c @@ -110,7 +110,7 @@ static void shell_surface_protocol_move(struct wl_client *client, uint32_t serial) { wlr_log(L_DEBUG, "got shell surface move"); struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); - struct wlr_seat_handle *seat_handle = + struct wlr_seat_client *seat = wl_resource_get_user_data(seat_resource); struct wlr_wl_shell_surface_move_event *event = @@ -121,7 +121,7 @@ static void shell_surface_protocol_move(struct wl_client *client, } event->client = client; event->surface = surface; - event->seat_handle = seat_handle; + event->seat = seat; event->serial = serial; wl_signal_emit(&surface->events.request_move, event); @@ -171,13 +171,12 @@ static void shell_surface_destroy_popup_state( } } - static void shell_surface_protocol_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, enum wl_shell_surface_resize edges) { wlr_log(L_DEBUG, "got shell surface resize"); struct wlr_wl_shell_surface *surface = wl_resource_get_user_data(resource); - struct wlr_seat_handle *seat_handle = + struct wlr_seat_client *seat = wl_resource_get_user_data(seat_resource); struct wlr_wl_shell_surface_resize_event *event = @@ -188,7 +187,7 @@ static void shell_surface_protocol_resize(struct wl_client *client, } event->client = client; event->surface = surface; - event->seat_handle = seat_handle; + event->seat = seat; event->serial = serial; event->edges = edges; @@ -287,9 +286,8 @@ static void shell_surface_protocol_set_fullscreen(struct wl_client *client, output = wl_resource_get_user_data(output_resource); } - if (surface->state == WLR_WL_SHELL_SURFACE_STATE_TOPLEVEL) { - return; - } + shell_surface_set_state(surface, WLR_WL_SHELL_SURFACE_STATE_FULLSCREEN, + NULL, NULL); struct wlr_wl_shell_surface_set_fullscreen_event *event = calloc(1, sizeof(struct wlr_wl_shell_surface_set_fullscreen_event)); @@ -349,7 +347,7 @@ static void shell_surface_protocol_set_popup(struct wl_client *client, transient_state->flags = flags; struct wlr_wl_shell_surface_popup_state *popup_state = - calloc(1, sizeof(struct wlr_wl_shell_surface_transient_state)); + calloc(1, sizeof(struct wlr_wl_shell_surface_popup_state)); if (popup_state == NULL) { free(transient_state); wl_client_post_no_memory(client); @@ -377,9 +375,8 @@ static void shell_surface_protocol_set_maximized(struct wl_client *client, output = wl_resource_get_user_data(output_resource); } - if (surface->state == WLR_WL_SHELL_SURFACE_STATE_TOPLEVEL) { - return; - } + shell_surface_set_state(surface, WLR_WL_SHELL_SURFACE_STATE_MAXIMIZED, + NULL, NULL); struct wlr_wl_shell_surface_set_maximized_event *event = calloc(1, sizeof(struct wlr_wl_shell_surface_set_maximized_event)); diff --git a/types/wlr_xcursor_manager.c b/types/wlr_xcursor_manager.c new file mode 100644 index 00000000..6c12d04b --- /dev/null +++ b/types/wlr_xcursor_manager.c @@ -0,0 +1,84 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include + +struct wlr_xcursor_manager *wlr_xcursor_manager_create(const char *name, + uint32_t size) { + struct wlr_xcursor_manager *manager = + calloc(1, sizeof(struct wlr_xcursor_manager)); + if (manager == NULL) { + return NULL; + } + if (name != NULL) { + manager->name = strdup(name); + } + manager->size = size; + wl_list_init(&manager->scaled_themes); + return manager; +} + +void wlr_xcursor_manager_destroy(struct wlr_xcursor_manager *manager) { + if (manager == NULL) { + return; + } + struct wlr_xcursor_manager_theme *theme, *tmp; + wl_list_for_each_safe(theme, tmp, &manager->scaled_themes, link) { + wl_list_remove(&theme->link); + wlr_xcursor_theme_destroy(theme->theme); + free(theme); + } + free(manager->name); + free(manager); +} + +int wlr_xcursor_manager_load(struct wlr_xcursor_manager *manager, + uint32_t scale) { + struct wlr_xcursor_manager_theme *theme; + wl_list_for_each(theme, &manager->scaled_themes, link) { + if (theme->scale == scale) { + return 0; + } + } + + theme = calloc(1, sizeof(struct wlr_xcursor_manager_theme)); + if (theme == NULL) { + return 1; + } + theme->scale = scale; + theme->theme = wlr_xcursor_theme_load(NULL, manager->size * scale); + if (theme->theme == NULL) { + free(theme); + return 1; + } + wl_list_insert(&manager->scaled_themes, &theme->link); + return 0; +} + +struct wlr_xcursor *wlr_xcursor_manager_get_xcursor( + struct wlr_xcursor_manager *manager, const char *name, uint32_t scale) { + struct wlr_xcursor_manager_theme *theme; + wl_list_for_each(theme, &manager->scaled_themes, link) { + if (theme->scale == scale) { + return wlr_xcursor_theme_get_cursor(theme->theme, name); + } + } + return NULL; +} + +void wlr_xcursor_manager_set_cursor_image(struct wlr_xcursor_manager *manager, + const char *name, struct wlr_cursor *cursor) { + struct wlr_xcursor_manager_theme *theme; + wl_list_for_each(theme, &manager->scaled_themes, link) { + struct wlr_xcursor *xcursor = + wlr_xcursor_theme_get_cursor(theme->theme, name); + if (xcursor == NULL) { + continue; + } + + struct wlr_xcursor_image *image = xcursor->images[0]; + wlr_cursor_set_image(cursor, image->buffer, image->width, + image->width, image->height, image->hotspot_x, image->hotspot_y, + theme->scale); + } +} diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index fc45bc17..429baa70 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -111,11 +111,8 @@ static void xdg_keyboard_grab_key(struct wlr_seat_keyboard_grab *grab, uint32_t wlr_seat_keyboard_send_key(grab->seat, time, key, state); } -static void xdg_keyboard_grab_modifiers(struct wlr_seat_keyboard_grab *grab, - uint32_t mods_depressed, uint32_t mods_latched, - uint32_t mods_locked, uint32_t group) { - wlr_seat_keyboard_send_modifiers(grab->seat, mods_depressed, mods_latched, - mods_locked, group); +static void xdg_keyboard_grab_modifiers(struct wlr_seat_keyboard_grab *grab) { + wlr_seat_keyboard_send_modifiers(grab->seat); } static void xdg_keyboard_grab_cancel(struct wlr_seat_keyboard_grab *grab) { @@ -557,7 +554,7 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, int32_t x, int32_t y) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - struct wlr_seat_handle *seat_handle = + struct wlr_seat_client *seat = wl_resource_get_user_data(seat_resource); if (!surface->configured) { @@ -576,7 +573,7 @@ static void xdg_toplevel_protocol_show_window_menu(struct wl_client *client, event->client = client; event->surface = surface; - event->seat_handle = seat_handle; + event->seat = seat; event->serial = serial; event->x = x; event->y = y; @@ -590,7 +587,7 @@ static void xdg_toplevel_protocol_move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - struct wlr_seat_handle *seat_handle = + struct wlr_seat_client *seat = wl_resource_get_user_data(seat_resource); if (!surface->configured) { @@ -609,7 +606,7 @@ static void xdg_toplevel_protocol_move(struct wl_client *client, event->client = client; event->surface = surface; - event->seat_handle = seat_handle; + event->seat = seat; event->serial = serial; wl_signal_emit(&surface->events.request_move, event); @@ -621,7 +618,7 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial, uint32_t edges) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); - struct wlr_seat_handle *seat_handle = + struct wlr_seat_client *seat = wl_resource_get_user_data(seat_resource); if (!surface->configured) { @@ -640,7 +637,7 @@ static void xdg_toplevel_protocol_resize(struct wl_client *client, event->client = client; event->surface = surface; - event->seat_handle = seat_handle; + event->seat = seat; event->serial = serial; event->edges = edges; @@ -667,24 +664,28 @@ static void xdg_toplevel_protocol_set_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); surface->toplevel_state->next.maximized = true; + wl_signal_emit(&surface->events.request_maximize, surface); } static void xdg_toplevel_protocol_unset_maximized(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); surface->toplevel_state->next.maximized = false; + wl_signal_emit(&surface->events.request_maximize, surface); } static void xdg_toplevel_protocol_set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output_resource) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); surface->toplevel_state->next.fullscreen = true; + wl_signal_emit(&surface->events.request_fullscreen, surface); } static void xdg_toplevel_protocol_unset_fullscreen(struct wl_client *client, struct wl_resource *resource) { struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); surface->toplevel_state->next.fullscreen = false; + wl_signal_emit(&surface->events.request_fullscreen, surface); } static void xdg_toplevel_protocol_set_minimized(struct wl_client *client, @@ -1146,6 +1147,8 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, wl_list_init(&surface->configure_list); wl_list_init(&surface->popups); + wl_signal_init(&surface->events.request_maximize); + wl_signal_init(&surface->events.request_fullscreen); wl_signal_init(&surface->events.request_minimize); wl_signal_init(&surface->events.request_move); wl_signal_init(&surface->events.request_resize); @@ -1347,6 +1350,16 @@ void wlr_xdg_toplevel_v6_send_close(struct wlr_xdg_surface_v6 *surface) { zxdg_toplevel_v6_send_close(surface->toplevel_state->resource); } +void wlr_xdg_surface_v6_popup_get_position(struct wlr_xdg_surface_v6 *surface, + double *popup_sx, double *popup_sy) { + assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP); + struct wlr_xdg_surface_v6 *parent = surface->popup_state->parent; + *popup_sx = parent->geometry->x + surface->popup_state->geometry.x - + surface->geometry->x; + *popup_sy = parent->geometry->y + surface->popup_state->geometry.y - + surface->geometry->y; +} + struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_popup_at( struct wlr_xdg_surface_v6 *surface, double sx, double sy, double *popup_sx, double *popup_sy) { diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index 0452f04c..ecec785c 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -211,6 +211,8 @@ static int xserver_handle_ready(int signal_number, void *data) { snprintf(display_name, sizeof(display_name), ":%d", wlr_xwayland->display); setenv("DISPLAY", display_name, true); + wl_signal_emit(&wlr_xwayland->events.ready, wlr_xwayland); + return 1; /* wayland event loop dispatcher's count */ } @@ -223,6 +225,7 @@ static bool wlr_xwayland_init(struct wlr_xwayland *wlr_xwayland, wlr_xwayland->wl_fd[0] = wlr_xwayland->wl_fd[1] = -1; wlr_xwayland->wm_fd[0] = wlr_xwayland->wm_fd[1] = -1; wl_signal_init(&wlr_xwayland->events.new_surface); + wl_signal_init(&wlr_xwayland->events.ready); wlr_xwayland->display = open_display_sockets(wlr_xwayland->x_fd); if (wlr_xwayland->display < 0) { diff --git a/xwayland/xwm.c b/xwayland/xwm.c index f011587e..dff9fac2 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -823,41 +823,47 @@ static void xwm_handle_net_wm_state_message(struct wlr_xwm *xwm, if (!xsurface) { return; } + if (client_message->format != 32) { + return; + } - int maximized = xsurface_is_maximized(xsurface); + bool fullscreen = xsurface->fullscreen; + bool maximized = xsurface_is_maximized(xsurface); uint32_t action = client_message->data.data32[0]; - uint32_t property = client_message->data.data32[1]; + for (size_t i = 0; i < 2; ++i) { + uint32_t property = client_message->data.data32[1 + i]; - if (property == xwm->atoms[_NET_WM_STATE_FULLSCREEN] && - update_state(action, &xsurface->fullscreen)) { - xsurface_set_net_wm_state(xsurface); + if (property == xwm->atoms[_NET_WM_STATE_FULLSCREEN] && + update_state(action, &xsurface->fullscreen)) { + xsurface_set_net_wm_state(xsurface); + } else if (property == xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT] && + update_state(action, &xsurface->maximized_vert)) { + xsurface_set_net_wm_state(xsurface); + } else if (property == xwm->atoms[_NET_WM_STATE_MAXIMIZED_HORZ] && + update_state(action, &xsurface->maximized_horz)) { + xsurface_set_net_wm_state(xsurface); + } + } + // client_message->data.data32[3] is the source indication + // all other values are set to 0 + if (fullscreen != xsurface->fullscreen) { if (xsurface->fullscreen) { xsurface->saved_width = xsurface->width; xsurface->saved_height = xsurface->height; } wl_signal_emit(&xsurface->events.request_fullscreen, xsurface); - } else { - if (property == xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT] && - update_state(action, &xsurface->maximized_vert)) { - xsurface_set_net_wm_state(xsurface); + } + + if (maximized != xsurface_is_maximized(xsurface)) { + if (xsurface_is_maximized(xsurface)) { + xsurface->saved_width = xsurface->width; + xsurface->saved_height = xsurface->height; } - if (property == xwm->atoms[_NET_WM_STATE_MAXIMIZED_HORZ] && - update_state(action, &xsurface->maximized_horz)) { - xsurface_set_net_wm_state(xsurface); - } - - if (maximized != xsurface_is_maximized(xsurface)) { - if (xsurface_is_maximized(xsurface)) { - xsurface->saved_width = xsurface->width; - xsurface->saved_height = xsurface->height; - } - - wl_signal_emit(&xsurface->events.request_maximize, xsurface); - } + wl_signal_emit(&xsurface->events.request_maximize, xsurface); } } @@ -1310,8 +1316,8 @@ struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland) { xwm->atoms[_NET_ACTIVE_WINDOW], xwm->atoms[_NET_WM_MOVERESIZE], xwm->atoms[_NET_WM_STATE_FULLSCREEN], - xwm->atoms[_NET_WM_STATE_MAXIMIZED_HORZ], xwm->atoms[_NET_WM_STATE_MAXIMIZED_VERT], + xwm->atoms[_NET_WM_STATE_MAXIMIZED_HORZ], }; xcb_change_property(xwm->xcb_conn, XCB_PROP_MODE_REPLACE,