diff --git a/.gitignore b/.gitignore index 516afff1..f635e54f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,3 @@ build/ build-*/ wayland-*-protocol.* wlr-example.ini -rootston.ini diff --git a/include/rootston/bindings.h b/include/rootston/bindings.h deleted file mode 100644 index db38130b..00000000 --- a/include/rootston/bindings.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef ROOTSTON_BINDINGS_H -#define ROOTSTON_BINDINGS_H - -#include "rootston/seat.h" -#include "rootston/input.h" - -void execute_binding_command(struct roots_seat *seat, struct roots_input *input, const char *command); - -#endif //ROOTSTON_BINDINGS_H diff --git a/include/rootston/config.h b/include/rootston/config.h deleted file mode 100644 index f8132269..00000000 --- a/include/rootston/config.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef ROOTSTON_CONFIG_H -#define ROOTSTON_CONFIG_H - -#include -#include -#include -#include - -#define ROOTS_CONFIG_DEFAULT_SEAT_NAME "seat0" - -struct roots_output_mode_config { - drmModeModeInfo info; - struct wl_list link; -}; - -struct roots_output_config { - char *name; - bool enable; - enum wl_output_transform transform; - int x, y; - float scale; - struct wl_list link; - struct { - int width, height; - float refresh_rate; - } mode; - struct wl_list modes; -}; - -struct roots_device_config { - char *name; - char *seat; - char *mapped_output; - bool tap_enabled; - struct wlr_box *mapped_box; - struct wl_list link; -}; - -struct roots_binding_config { - uint32_t modifiers; - xkb_keysym_t *keysyms; - size_t keysyms_len; - char *command; - struct wl_list link; -}; - -struct roots_keyboard_config { - char *name; - char *seat; - uint32_t meta_key; - char *rules; - char *model; - char *layout; - char *variant; - char *options; - int repeat_rate, repeat_delay; - struct wl_list link; -}; - -struct roots_cursor_config { - char *seat; - char *mapped_output; - struct wlr_box *mapped_box; - char *theme; - char *default_image; - struct wl_list link; -}; - -struct roots_switch_config { - char *name; - enum wlr_switch_type switch_type; - enum wlr_switch_state switch_state; - char *command; - struct wl_list link; -}; - -struct roots_config { - bool xwayland; - bool xwayland_lazy; - - struct wl_list outputs; - struct wl_list devices; - struct wl_list bindings; - struct wl_list keyboards; - struct wl_list cursors; - struct wl_list switches; - - char *config_path; - char *startup_cmd; - bool debug_damage_tracking; -}; - -/** - * 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 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 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 roots_keyboard_config *roots_config_get_keyboard( - struct roots_config *config, struct wlr_input_device *device); - -/** - * Get configuration for the cursor. If the cursor is not configured, returns - * NULL. A NULL seat_name returns the default config for cursors. - */ -struct roots_cursor_config *roots_config_get_cursor(struct roots_config *config, - const char *seat_name); - -#endif diff --git a/include/rootston/cursor.h b/include/rootston/cursor.h deleted file mode 100644 index 0d6b6014..00000000 --- a/include/rootston/cursor.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef ROOTSTON_CURSOR_H -#define ROOTSTON_CURSOR_H - -#include -#include "rootston/seat.h" - -enum roots_cursor_mode { - ROOTS_CURSOR_PASSTHROUGH = 0, - ROOTS_CURSOR_MOVE = 1, - ROOTS_CURSOR_RESIZE = 2, - ROOTS_CURSOR_ROTATE = 3, -}; - -struct roots_cursor { - struct roots_seat *seat; - struct wlr_cursor *cursor; - - struct wlr_pointer_constraint_v1 *active_constraint; - pixman_region32_t confine; // invalid if active_constraint == NULL - - const char *default_xcursor; - - 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; - - struct roots_seat_view *pointer_view; - struct wlr_surface *wlr_surface; - - struct wl_listener motion; - struct wl_listener motion_absolute; - struct wl_listener button; - struct wl_listener axis; - struct wl_listener frame; - struct wl_listener swipe_begin; - struct wl_listener swipe_update; - struct wl_listener swipe_end; - struct wl_listener pinch_begin; - struct wl_listener pinch_update; - struct wl_listener pinch_end; - - 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 tool_proximity; - struct wl_listener tool_button; - - struct wl_listener request_set_cursor; - - struct wl_listener focus_change; - - struct wl_listener constraint_commit; -}; - -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_frame(struct roots_cursor *cursor); - -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_focus_change(struct roots_cursor *cursor, - struct wlr_seat_pointer_focus_change_event *event); - -void roots_cursor_handle_constraint_commit(struct roots_cursor *cursor); - -void roots_cursor_update_position(struct roots_cursor *cursor, - uint32_t time); - -void roots_cursor_update_focus(struct roots_cursor *cursor); - -void roots_cursor_constrain(struct roots_cursor *cursor, - struct wlr_pointer_constraint_v1 *constraint, double sx, double sy); - -#endif diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h deleted file mode 100644 index d3d6ec18..00000000 --- a/include/rootston/desktop.h +++ /dev/null @@ -1,106 +0,0 @@ -#ifndef ROOTSTON_DESKTOP_H -#define ROOTSTON_DESKTOP_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/config.h" -#include "rootston/output.h" -#include "rootston/view.h" - -struct roots_desktop { - struct wl_list views; // roots_view::link - - struct wl_list outputs; // roots_output::link - struct timespec last_frame; - - struct roots_server *server; - struct roots_config *config; - - struct wlr_output_layout *layout; - struct wlr_xcursor_manager *xcursor_manager; - - struct wlr_compositor *compositor; - struct wlr_xdg_shell_v6 *xdg_shell_v6; - struct wlr_xdg_shell *xdg_shell; - struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1; - struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1; - struct wlr_server_decoration_manager *server_decoration_manager; - struct wlr_xdg_decoration_manager_v1 *xdg_decoration_manager; - struct wlr_gtk_primary_selection_device_manager *primary_selection_device_manager; - struct wlr_idle *idle; - struct wlr_idle_inhibit_manager_v1 *idle_inhibit; - struct wlr_input_inhibit_manager *input_inhibit; - struct wlr_layer_shell_v1 *layer_shell; - struct wlr_input_method_manager_v2 *input_method; - struct wlr_text_input_manager_v3 *text_input; - struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard; - struct wlr_screencopy_manager_v1 *screencopy; - struct wlr_tablet_manager_v2 *tablet_v2; - struct wlr_pointer_constraints_v1 *pointer_constraints; - struct wlr_presentation *presentation; - struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager_v1; - struct wlr_relative_pointer_manager_v1 *relative_pointer_manager; - struct wlr_pointer_gestures_v1 *pointer_gestures; - struct wlr_output_manager_v1 *output_manager_v1; - - struct wl_listener new_output; - struct wl_listener layout_change; - struct wl_listener xdg_shell_v6_surface; - struct wl_listener xdg_shell_surface; - struct wl_listener layer_shell_surface; - struct wl_listener xdg_toplevel_decoration; - struct wl_listener input_inhibit_activate; - struct wl_listener input_inhibit_deactivate; - struct wl_listener virtual_keyboard_new; - struct wl_listener pointer_constraint; - struct wl_listener output_manager_apply; - struct wl_listener output_manager_test; - -#if WLR_HAS_XWAYLAND - struct wlr_xwayland *xwayland; - struct wl_listener xwayland_surface; -#endif -}; - -struct roots_server; - -struct roots_desktop *desktop_create(struct roots_server *server, - struct roots_config *config); -void desktop_destroy(struct roots_desktop *desktop); -struct roots_output *desktop_output_from_wlr_output( - struct roots_desktop *desktop, struct wlr_output *output); - -struct wlr_surface *desktop_surface_at(struct roots_desktop *desktop, - double lx, double ly, double *sx, double *sy, - struct roots_view **view); - -void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); -void handle_xdg_shell_surface(struct wl_listener *listener, void *data); -void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data); -void handle_layer_shell_surface(struct wl_listener *listener, void *data); -void handle_xwayland_surface(struct wl_listener *listener, void *data); - -#endif diff --git a/include/rootston/ini.h b/include/rootston/ini.h deleted file mode 100644 index 2804255b..00000000 --- a/include/rootston/ini.h +++ /dev/null @@ -1,93 +0,0 @@ -/* inih -- simple .INI file parser - -inih is released under the New BSD license (see LICENSE.txt). Go to the project -home page for more info: - -https://github.com/benhoyt/inih - -*/ - -#ifndef __INI_H__ -#define __INI_H__ - -/* Make this header file easier to include in C++ code */ -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/* Typedef for prototype of handler function. */ -typedef int (*ini_handler)(void* user, const char* section, - const char* name, const char* value); - -/* Typedef for prototype of fgets-style reader function. */ -typedef char* (*ini_reader)(char* str, int num, void* stream); - -/* Parse given INI-style file. May have [section]s, name=value pairs - (whitespace stripped), and comments starting with ';' (semicolon). Section - is "" if name=value pair parsed before any section heading. name:value - pairs are also supported as a concession to Python's configparser. - - For each name=value pair parsed, call handler function with given user - pointer as well as section, name, and value (data only valid for duration - of handler call). Handler should return nonzero on success, zero on error. - - Returns 0 on success, line number of first error on parse error (doesn't - stop on first error), -1 on file open error, or -2 on memory allocation - error (only when INI_USE_STACK is zero). -*/ -int ini_parse(const char* filename, ini_handler handler, void* user); - -/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't - close the file when it's finished -- the caller must do that. */ -int ini_parse_file(FILE* file, ini_handler handler, void* user); - -/* Same as ini_parse(), but takes an ini_reader function pointer instead of - filename. Used for implementing custom or string-based I/O. */ -int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, - void* user); - -/* Nonzero to allow multi-line value parsing, in the style of Python's - configparser. If allowed, ini_parse() will call the handler with the same - name for each subsequent line parsed. */ -#ifndef INI_ALLOW_MULTILINE -#define INI_ALLOW_MULTILINE 1 -#endif - -/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of - the file. See http://code.google.com/p/inih/issues/detail?id=21 */ -#ifndef INI_ALLOW_BOM -#define INI_ALLOW_BOM 1 -#endif - -/* Nonzero to allow inline comments (with valid inline comment characters - specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match - Python 3.2+ configparser behaviour. */ -#ifndef INI_ALLOW_INLINE_COMMENTS -#define INI_ALLOW_INLINE_COMMENTS 1 -#endif -#ifndef INI_INLINE_COMMENT_PREFIXES -#define INI_INLINE_COMMENT_PREFIXES ";" -#endif - -/* Nonzero to use stack, zero to use heap (malloc/free). */ -#ifndef INI_USE_STACK -#define INI_USE_STACK 1 -#endif - -/* Stop parsing on first error (default is to keep parsing). */ -#ifndef INI_STOP_ON_FIRST_ERROR -#define INI_STOP_ON_FIRST_ERROR 0 -#endif - -/* Maximum line length for any line in INI file. */ -#ifndef INI_MAX_LINE -#define INI_MAX_LINE 2000 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* __INI_H__ */ diff --git a/include/rootston/input.h b/include/rootston/input.h deleted file mode 100644 index a799db59..00000000 --- a/include/rootston/input.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef ROOTSTON_INPUT_H -#define ROOTSTON_INPUT_H - -#include -#include -#include -#include -#include "rootston/config.h" -#include "rootston/cursor.h" -#include "rootston/server.h" -#include "rootston/view.h" - -struct roots_input { - struct roots_config *config; - struct roots_server *server; - - struct wl_listener new_input; - - struct wl_list seats; // roots_seat::link -}; - -struct roots_input *input_create(struct roots_server *server, - struct roots_config *config); -void input_destroy(struct roots_input *input); - -struct roots_seat *input_seat_from_wlr_seat(struct roots_input *input, - struct wlr_seat *seat); - -bool input_view_has_focus(struct roots_input *input, struct roots_view *view); - -struct roots_seat *input_get_seat(struct roots_input *input, char *name); - -struct roots_seat *input_last_active_seat(struct roots_input *input); - -void input_update_cursor_focus(struct roots_input *input); - -#endif diff --git a/include/rootston/keyboard.h b/include/rootston/keyboard.h deleted file mode 100644 index 0140389a..00000000 --- a/include/rootston/keyboard.h +++ /dev/null @@ -1,34 +0,0 @@ -#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 device_destroy; - 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/layers.h b/include/rootston/layers.h deleted file mode 100644 index 0dacf20f..00000000 --- a/include/rootston/layers.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef ROOTSTON_LAYERS_H -#define ROOTSTON_LAYERS_H -#include -#include -#include -#include - -struct roots_layer_surface { - struct wlr_layer_surface_v1 *layer_surface; - struct wl_list link; - - struct wl_listener destroy; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener surface_commit; - struct wl_listener output_destroy; - struct wl_listener new_popup; - - bool configured; - struct wlr_box geo; -}; - -struct roots_layer_popup { - struct roots_layer_surface *parent; - struct wlr_xdg_popup *wlr_popup; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener destroy; - struct wl_listener commit; -}; - -struct roots_output; -void arrange_layers(struct roots_output *output); - -#endif diff --git a/include/rootston/output.h b/include/rootston/output.h deleted file mode 100644 index 257d9367..00000000 --- a/include/rootston/output.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef ROOTSTON_OUTPUT_H -#define ROOTSTON_OUTPUT_H -#include -#include -#include -#include -#include - -struct roots_desktop; - -struct roots_output { - struct roots_desktop *desktop; - struct wlr_output *wlr_output; - struct wl_list link; // roots_desktop:outputs - - struct roots_view *fullscreen_view; - struct wl_list layers[4]; // layer_surface::link - - struct timespec last_frame; - struct wlr_output_damage *damage; - - struct wlr_box usable_area; - - struct wl_listener destroy; - struct wl_listener enable; - struct wl_listener mode; - struct wl_listener transform; - struct wl_listener present; - struct wl_listener damage_frame; - struct wl_listener damage_destroy; -}; - -typedef void (*roots_surface_iterator_func_t)(struct roots_output *output, - struct wlr_surface *surface, struct wlr_box *box, float rotation, - void *user_data); - -void rotate_child_position(double *sx, double *sy, double sw, double sh, - double pw, double ph, float rotation); - -struct roots_input; - -void output_surface_for_each_surface(struct roots_output *output, - struct wlr_surface *surface, double ox, double oy, - roots_surface_iterator_func_t iterator, void *user_data); -void output_view_for_each_surface(struct roots_output *output, - struct roots_view *view, roots_surface_iterator_func_t iterator, - void *user_data); -void output_drag_icons_for_each_surface(struct roots_output *output, - struct roots_input *input, roots_surface_iterator_func_t iterator, - void *user_data); -void output_layer_for_each_surface(struct roots_output *output, - struct wl_list *layer_surfaces, roots_surface_iterator_func_t iterator, - void *user_data); -#if WLR_HAS_XWAYLAND -struct wlr_xwayland_surface; -void output_xwayland_children_for_each_surface( - struct roots_output *output, struct wlr_xwayland_surface *surface, - roots_surface_iterator_func_t iterator, void *user_data); -#endif -void output_for_each_surface(struct roots_output *output, - roots_surface_iterator_func_t iterator, void *user_data); - -void handle_new_output(struct wl_listener *listener, void *data); -void handle_output_manager_apply(struct wl_listener *listener, void *data); -void handle_output_manager_test(struct wl_listener *listener, void *data); - -struct roots_view; -struct roots_drag_icon; - -void output_damage_whole(struct roots_output *output); -void output_damage_whole_view(struct roots_output *output, - struct roots_view *view); -void output_damage_from_view(struct roots_output *output, - struct roots_view *view); -void output_damage_whole_drag_icon(struct roots_output *output, - struct roots_drag_icon *icon); -void output_damage_from_local_surface(struct roots_output *output, - struct wlr_surface *surface, double ox, double oy); -void output_damage_whole_local_surface(struct roots_output *output, - struct wlr_surface *surface, double ox, double oy); - -void output_render(struct roots_output *output); - -void scale_box(struct wlr_box *box, float scale); -void get_decoration_box(struct roots_view *view, - struct roots_output *output, struct wlr_box *box); - -#endif diff --git a/include/rootston/seat.h b/include/rootston/seat.h deleted file mode 100644 index fa3a83dd..00000000 --- a/include/rootston/seat.h +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef ROOTSTON_SEAT_H -#define ROOTSTON_SEAT_H - -#include -#include "rootston/input.h" -#include "rootston/keyboard.h" -#include "rootston/layers.h" -#include "rootston/switch.h" -#include "rootston/text_input.h" - -struct roots_seat { - struct roots_input *input; - struct wlr_seat *seat; - struct roots_cursor *cursor; - struct wl_list link; // roots_input::seats - - // coordinates of the first touch point if it exists - int32_t touch_id; - double touch_x, touch_y; - - // If the focused layer is set, views cannot receive keyboard focus - struct wlr_layer_surface_v1 *focused_layer; - - struct roots_input_method_relay im_relay; - - // If non-null, only this client can receive input events - struct wl_client *exclusive_client; - - struct wl_list views; // roots_seat_view::link - bool has_focus; - - struct roots_drag_icon *drag_icon; // can be NULL - - struct wl_list keyboards; - struct wl_list pointers; - struct wl_list switches; - struct wl_list touch; - struct wl_list tablets; - struct wl_list tablet_pads; - - struct wl_listener request_set_selection; - struct wl_listener request_set_primary_selection; - struct wl_listener request_start_drag; - struct wl_listener start_drag; - struct wl_listener destroy; -}; - -struct roots_seat_view { - struct roots_seat *seat; - struct roots_view *view; - - bool has_button_grab; - double grab_sx; - double grab_sy; - - struct wl_list link; // roots_seat::views - - struct wl_listener view_unmap; - struct wl_listener view_destroy; -}; - -struct roots_drag_icon { - struct roots_seat *seat; - struct wlr_drag_icon *wlr_drag_icon; - - double x, y; - - struct wl_listener surface_commit; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener destroy; -}; - -struct roots_pointer { - struct roots_seat *seat; - struct wlr_input_device *device; - struct wl_listener device_destroy; - struct wl_list link; -}; - -struct roots_touch { - struct roots_seat *seat; - struct wlr_input_device *device; - struct wl_listener device_destroy; - struct wl_list link; -}; - -struct roots_tablet { - struct roots_seat *seat; - struct wlr_input_device *device; - struct wlr_tablet_v2_tablet *tablet_v2; - - struct wl_listener device_destroy; - struct wl_listener axis; - struct wl_listener proximity; - struct wl_listener tip; - struct wl_listener button; - struct wl_list link; -}; - -struct roots_tablet_pad { - struct wl_list link; - struct wlr_tablet_v2_tablet_pad *tablet_v2_pad; - - struct roots_seat *seat; - struct wlr_input_device *device; - - struct wl_listener device_destroy; - struct wl_listener attach; - struct wl_listener button; - struct wl_listener ring; - struct wl_listener strip; - - struct roots_tablet *tablet; - struct wl_listener tablet_destroy; -}; - -struct roots_tablet_tool { - struct wl_list link; - struct wl_list tool_link; - struct wlr_tablet_v2_tablet_tool *tablet_v2_tool; - - struct roots_seat *seat; - double tilt_x, tilt_y; - - struct wl_listener set_cursor; - struct wl_listener tool_destroy; - - struct roots_tablet *current_tablet; - struct wl_listener tablet_destroy; -}; - -struct roots_pointer_constraint { - struct wlr_pointer_constraint_v1 *constraint; - - struct wl_listener destroy; -}; - -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_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); - -struct roots_view *roots_seat_get_focus(struct roots_seat *seat); - -void roots_seat_set_focus(struct roots_seat *seat, struct roots_view *view); - -void roots_seat_set_focus_layer(struct roots_seat *seat, - struct wlr_layer_surface_v1 *layer); - -void roots_seat_cycle_focus(struct roots_seat *seat); - -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); - -void roots_seat_end_compositor_grab(struct roots_seat *seat); - -struct roots_seat_view *roots_seat_view_from_view( struct roots_seat *seat, - struct roots_view *view); - -void roots_drag_icon_update_position(struct roots_drag_icon *icon); - -void roots_drag_icon_damage_whole(struct roots_drag_icon *icon); - -void roots_seat_set_exclusive_client(struct roots_seat *seat, - struct wl_client *client); - -bool roots_seat_allow_input(struct roots_seat *seat, - struct wl_resource *resource); - -#endif diff --git a/include/rootston/server.h b/include/rootston/server.h deleted file mode 100644 index f48549f2..00000000 --- a/include/rootston/server.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _ROOTSTON_SERVER_H -#define _ROOTSTON_SERVER_H - -#include -#include -#include -#include -#include -#include -#if WLR_HAS_XWAYLAND -#include -#endif -#include "rootston/config.h" -#include "rootston/desktop.h" -#include "rootston/input.h" - -struct roots_server { - /* Rootston resources */ - struct roots_config *config; - struct roots_desktop *desktop; - struct roots_input *input; - - /* Wayland resources */ - struct wl_display *wl_display; - struct wl_event_loop *wl_event_loop; - - /* WLR tools */ - struct wlr_backend *backend; - struct wlr_renderer *renderer; - - /* Global resources */ - struct wlr_data_device_manager *data_device_manager; -}; - -extern struct roots_server server; - -#endif diff --git a/include/rootston/switch.h b/include/rootston/switch.h deleted file mode 100644 index 32bc3dab..00000000 --- a/include/rootston/switch.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ROOTSTON_SWITCH_H -#define ROOTSTON_SWITCH_H - -#include "rootston/input.h" - -struct roots_switch { - struct roots_seat *seat; - struct wlr_input_device *device; - struct wl_listener device_destroy; - - struct wl_listener toggle; - struct wl_list link; -}; - -void roots_switch_handle_toggle(struct roots_switch *switch_device, - struct wlr_event_switch_toggle *event); - -#endif diff --git a/include/rootston/text_input.h b/include/rootston/text_input.h deleted file mode 100644 index 82e45e3e..00000000 --- a/include/rootston/text_input.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef ROOTSTON_TEXT_INPUT_H -#define ROOTSTON_TEXT_INPUT_H - -#include -#include -#include -#include "rootston/seat.h" - -/** - * The relay structure manages the relationship between text-input and - * input_method interfaces on a given seat. Multiple text-input interfaces may - * be bound to a relay, but at most one will be focused (reveiving events) at - * a time. At most one input-method interface may be bound to the seat. The - * relay manages life cycle of both sides. When both sides are present and - * focused, the relay passes messages between them. - * - * Text input focus is a subset of keyboard focus - if the text-input is - * in the focused state, wl_keyboard sent an enter as well. However, having - * wl_keyboard focused doesn't mean that text-input will be focused. - */ -struct roots_input_method_relay { - struct roots_seat *seat; - - struct wl_list text_inputs; // roots_text_input::link - struct wlr_input_method_v2 *input_method; // doesn't have to be present - - struct wl_listener text_input_new; - struct wl_listener text_input_enable; - struct wl_listener text_input_commit; - struct wl_listener text_input_disable; - struct wl_listener text_input_destroy; - - struct wl_listener input_method_new; - struct wl_listener input_method_commit; - struct wl_listener input_method_destroy; -}; - -struct roots_text_input { - struct roots_input_method_relay *relay; - - struct wlr_text_input_v3 *input; - // The surface getting seat's focus. Stored for when text-input cannot - // be sent an enter event immediately after getting focus, e.g. when - // there's no input method available. Cleared once text-input is entered. - struct wlr_surface *pending_focused_surface; - - struct wl_list link; - - struct wl_listener pending_focused_surface_destroy; -}; - -void roots_input_method_relay_init(struct roots_seat *seat, - struct roots_input_method_relay *relay); - -// Updates currently focused surface. Surface must belong to the same seat. -void roots_input_method_relay_set_focus(struct roots_input_method_relay *relay, - struct wlr_surface *surface); - -struct roots_text_input *roots_text_input_create( - struct roots_input_method_relay *relay, - struct wlr_text_input_v3 *text_input); - -#endif diff --git a/include/rootston/view.h b/include/rootston/view.h deleted file mode 100644 index 1c5dcaff..00000000 --- a/include/rootston/view.h +++ /dev/null @@ -1,257 +0,0 @@ -#ifndef ROOTSTON_VIEW_H -#define ROOTSTON_VIEW_H -#include -#include -#include -#include -#include -#include -#include -#include - -struct roots_view; - -struct roots_view_interface { - 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 (*set_fullscreen)(struct roots_view *view, bool fullscreen); - void (*close)(struct roots_view *view); - void (*for_each_surface)(struct roots_view *view, - wlr_surface_iterator_func_t iterator, void *user_data); - void (*destroy)(struct roots_view *view); -}; - -enum roots_view_type { - ROOTS_XDG_SHELL_V6_VIEW, - ROOTS_XDG_SHELL_VIEW, -#if WLR_HAS_XWAYLAND - ROOTS_XWAYLAND_VIEW, -#endif -}; - -struct roots_view { - enum roots_view_type type; - const struct roots_view_interface *impl; - struct roots_desktop *desktop; - struct wl_list link; // roots_desktop::views - - struct wlr_box box; - float rotation; - float alpha; - - bool decorated; - int border_width; - int titlebar_height; - - bool maximized; - struct roots_output *fullscreen_output; - struct { - double x, y; - uint32_t width, height; - float rotation; - } saved; - - struct { - bool update_x, update_y; - double x, y; - uint32_t width, height; - } pending_move_resize; - - struct wlr_surface *wlr_surface; - struct wl_list children; // roots_view_child::link - - struct wlr_foreign_toplevel_handle_v1 *toplevel_handle; - struct wl_listener toplevel_handle_request_maximize; - struct wl_listener toplevel_handle_request_activate; - struct wl_listener toplevel_handle_request_fullscreen; - struct wl_listener toplevel_handle_request_close; - - struct wl_listener new_subsurface; - - struct { - struct wl_signal unmap; - struct wl_signal destroy; - } events; -}; - -struct roots_xdg_surface_v6 { - struct roots_view view; - - struct wlr_xdg_surface_v6 *xdg_surface_v6; - - struct wl_listener destroy; - struct wl_listener new_popup; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener request_move; - struct wl_listener request_resize; - struct wl_listener request_maximize; - struct wl_listener request_fullscreen; - struct wl_listener set_title; - struct wl_listener set_app_id; - - struct wl_listener surface_commit; - - uint32_t pending_move_resize_configure_serial; -}; - -struct roots_xdg_toplevel_decoration; - -struct roots_xdg_surface { - struct roots_view view; - - struct wlr_xdg_surface *xdg_surface; - - struct wl_listener destroy; - struct wl_listener new_popup; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener request_move; - struct wl_listener request_resize; - struct wl_listener request_maximize; - struct wl_listener request_fullscreen; - struct wl_listener set_title; - struct wl_listener set_app_id; - - struct wl_listener surface_commit; - - uint32_t pending_move_resize_configure_serial; - - struct roots_xdg_toplevel_decoration *xdg_toplevel_decoration; -}; - -#if WLR_HAS_XWAYLAND -struct roots_xwayland_surface { - struct roots_view view; - - struct wlr_xwayland_surface *xwayland_surface; - - struct wl_listener destroy; - struct wl_listener request_configure; - struct wl_listener request_move; - struct wl_listener request_resize; - struct wl_listener request_maximize; - struct wl_listener request_fullscreen; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener set_title; - struct wl_listener set_class; - - struct wl_listener surface_commit; -}; -#endif - -struct roots_view_child; - -struct roots_view_child_interface { - void (*destroy)(struct roots_view_child *child); -}; - -struct roots_view_child { - struct roots_view *view; - const struct roots_view_child_interface *impl; - struct wlr_surface *wlr_surface; - struct wl_list link; - - struct wl_listener commit; - struct wl_listener new_subsurface; -}; - -struct roots_subsurface { - struct roots_view_child view_child; - struct wlr_subsurface *wlr_subsurface; - struct wl_listener destroy; - struct wl_listener map; - struct wl_listener unmap; -}; - -struct roots_xdg_popup_v6 { - struct roots_view_child view_child; - struct wlr_xdg_popup_v6 *wlr_popup; - struct wl_listener destroy; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener new_popup; -}; - -struct roots_xdg_popup { - struct roots_view_child view_child; - struct wlr_xdg_popup *wlr_popup; - struct wl_listener destroy; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener new_popup; -}; - -struct roots_xdg_toplevel_decoration { - struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration; - struct roots_xdg_surface *surface; - struct wl_listener destroy; - struct wl_listener request_mode; - struct wl_listener surface_commit; -}; - -void view_init(struct roots_view *view, const struct roots_view_interface *impl, - enum roots_view_type type, struct roots_desktop *desktop); -void view_destroy(struct roots_view *view); -void view_apply_damage(struct roots_view *view); -void view_damage_whole(struct roots_view *view); -void view_update_position(struct roots_view *view, int x, int y); -void view_update_size(struct roots_view *view, int width, int height); -void view_update_decorated(struct roots_view *view, bool decorated); -void view_initial_focus(struct roots_view *view); -void view_map(struct roots_view *view, struct wlr_surface *surface); -void view_unmap(struct roots_view *view); -void view_arrange_maximized(struct roots_view *view); -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_set_fullscreen(struct roots_view *view, bool fullscreen, - struct wlr_output *output); -void view_rotate(struct roots_view *view, float rotation); -void view_cycle_alpha(struct roots_view *view); -void view_close(struct roots_view *view); -bool view_center(struct roots_view *view); -void view_setup(struct roots_view *view); -void view_teardown(struct roots_view *view); -void view_set_title(struct roots_view *view, const char *title); -void view_set_app_id(struct roots_view *view, const char *app_id); -void view_create_foreign_toplevel_handle(struct roots_view *view); -void view_get_deco_box(const struct roots_view *view, struct wlr_box *box); -void view_for_each_surface(struct roots_view *view, - wlr_surface_iterator_func_t iterator, void *user_data); - -struct roots_xdg_surface *roots_xdg_surface_from_view(struct roots_view *view); -struct roots_xdg_surface_v6 *roots_xdg_surface_v6_from_view( - struct roots_view *view); -struct roots_xwayland_surface *roots_xwayland_surface_from_view( - struct roots_view *view); - -enum roots_deco_part { - ROOTS_DECO_PART_NONE = 0, - ROOTS_DECO_PART_TOP_BORDER = (1 << 0), - ROOTS_DECO_PART_BOTTOM_BORDER = (1 << 1), - ROOTS_DECO_PART_LEFT_BORDER = (1 << 2), - ROOTS_DECO_PART_RIGHT_BORDER = (1 << 3), - ROOTS_DECO_PART_TITLEBAR = (1 << 4), -}; - -enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, double sy); - -void view_child_init(struct roots_view_child *child, - const struct roots_view_child_interface *impl, struct roots_view *view, - struct wlr_surface *wlr_surface); -void view_child_destroy(struct roots_view_child *child); - -struct roots_subsurface *subsurface_create(struct roots_view *view, - struct wlr_subsurface *wlr_subsurface); - -#endif diff --git a/include/rootston/virtual_keyboard.h b/include/rootston/virtual_keyboard.h deleted file mode 100644 index 613e5595..00000000 --- a/include/rootston/virtual_keyboard.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef ROOTSTON_VIRTUAL_KEYBOARD_H -#define ROOTSTON_VIRTUAL_KEYBOARD_H - -#include - -void handle_virtual_keyboard(struct wl_listener *listener, void *data); -#endif diff --git a/include/rootston/xcursor.h b/include/rootston/xcursor.h deleted file mode 100644 index f78489a4..00000000 --- a/include/rootston/xcursor.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef ROOTSTON_XCURSOR_H -#define ROOTSTON_XCURSOR_H - -#include - -#define ROOTS_XCURSOR_SIZE 24 - -#define ROOTS_XCURSOR_DEFAULT "left_ptr" -#define ROOTS_XCURSOR_MOVE "grabbing" -#define ROOTS_XCURSOR_ROTATE "grabbing" - -#endif diff --git a/meson.build b/meson.build index cd280bf5..dfada444 100644 --- a/meson.build +++ b/meson.build @@ -202,7 +202,6 @@ summary = [ message('\n'.join(summary)) subdir('examples') -subdir('rootston') pkgconfig = import('pkgconfig') pkgconfig.generate( diff --git a/meson_options.txt b/meson_options.txt index 5d322b0c..51b7f6c8 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,5 +6,4 @@ option('xcb-errors', type: 'feature', value: 'auto', description: 'Use xcb-error option('xcb-icccm', type: 'feature', value: 'auto', description: 'Use xcb-icccm util library') option('xwayland', type: 'feature', value: 'auto', yield: true, description: 'Enable support for X11 applications') option('x11-backend', type: 'feature', value: 'auto', description: 'Enable X11 backend') -option('rootston', type: 'boolean', value: true, description: 'Build the rootston example compositor') option('examples', type: 'boolean', value: true, description: 'Build example applications') diff --git a/rootston/README.md b/rootston/README.md deleted file mode 100644 index be2e6698..00000000 --- a/rootston/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# rootston - -Rootston is the "big" wlroots test compositor. It implements basically every -feature of wlroots and may be useful as a reference for new compositors. -However, it's mostly used as a testbed for wlroots development and does not have -particularly clean code and is not particularly well designed: proceed with a -grain of salt. It is not designed for end-users. - -## Running rootston - -If you followed the build instructions in `../README.md`, the rootston -executable can be found at `build/rootston/rootston`. To use it, refer to the -example config at [rootston/rootston.ini.example][rootston.ini] and place a -config file of your own at `rootston.ini` in the working directory (or in an -arbitrary location via `rootston -C`). Other options are available, refer to -`rootston -h`. - -[rootston.ini]: https://github.com/swaywm/wlroots/blob/master/rootston/rootston.ini.example diff --git a/rootston/bindings.c b/rootston/bindings.c deleted file mode 100644 index 9dc2223e..00000000 --- a/rootston/bindings.c +++ /dev/null @@ -1,110 +0,0 @@ -#include -#include -#include -#include -#include -#include "rootston/bindings.h" -#include "rootston/view.h" - -static bool outputs_enabled = true; - -static const char exec_prefix[] = "exec "; - -static void double_fork_shell_cmd(const char *shell_cmd) { - pid_t pid = fork(); - if (pid < 0) { - wlr_log(WLR_ERROR, "cannot execute binding command: fork() failed"); - return; - } - - if (pid == 0) { - pid = fork(); - if (pid == 0) { - execl("/bin/sh", "/bin/sh", "-c", shell_cmd, NULL); - _exit(EXIT_FAILURE); - } else { - _exit(pid == -1); - } - } - - int status; - while (waitpid(pid, &status, 0) < 0) { - if (errno == EINTR) { - continue; - } - wlr_log_errno(WLR_ERROR, "waitpid() on first child failed"); - return; - } - - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { - return; - } - - wlr_log(WLR_ERROR, "first child failed to fork command"); -} - -void execute_binding_command(struct roots_seat *seat, - struct roots_input *input, const char *command) { - if (strcmp(command, "exit") == 0) { - wl_display_terminate(input->server->wl_display); - } else if (strcmp(command, "close") == 0) { - struct roots_view *focus = roots_seat_get_focus(seat); - if (focus != NULL) { - view_close(focus); - } - } else if (strcmp(command, "fullscreen") == 0) { - struct roots_view *focus = roots_seat_get_focus(seat); - if (focus != NULL) { - bool is_fullscreen = focus->fullscreen_output != NULL; - view_set_fullscreen(focus, !is_fullscreen, NULL); - } - } else if (strcmp(command, "next_window") == 0) { - roots_seat_cycle_focus(seat); - } else if (strcmp(command, "alpha") == 0) { - struct roots_view *focus = roots_seat_get_focus(seat); - if (focus != NULL) { - view_cycle_alpha(focus); - } - } else if (strncmp(exec_prefix, command, strlen(exec_prefix)) == 0) { - const char *shell_cmd = command + strlen(exec_prefix); - double_fork_shell_cmd(shell_cmd); - } else if (strcmp(command, "maximize") == 0) { - struct roots_view *focus = roots_seat_get_focus(seat); - if (focus != NULL) { - view_maximize(focus, !focus->maximized); - } - } else if (strcmp(command, "nop") == 0) { - wlr_log(WLR_DEBUG, "nop command"); - } else if (strcmp(command, "toggle_outputs") == 0) { - outputs_enabled = !outputs_enabled; - struct roots_output *output; - wl_list_for_each(output, &input->server->desktop->outputs, link) { - wlr_output_enable(output->wlr_output, outputs_enabled); - } - } else if (strcmp(command, "toggle_decoration_mode") == 0) { - struct roots_view *focus = roots_seat_get_focus(seat); - if (focus != NULL && focus->type == ROOTS_XDG_SHELL_VIEW) { - struct roots_xdg_surface *xdg_surface = - roots_xdg_surface_from_view(focus); - struct roots_xdg_toplevel_decoration *decoration = - xdg_surface->xdg_toplevel_decoration; - if (decoration != NULL) { - enum wlr_xdg_toplevel_decoration_v1_mode mode = - decoration->wlr_decoration->current_mode; - mode = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE - ? WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE - : WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; - wlr_xdg_toplevel_decoration_v1_set_mode( - decoration->wlr_decoration, mode); - } - } - } else if (strcmp(command, "break_pointer_constraint") == 0) { - struct wl_list *list = &input->seats; - struct roots_seat *seat; - wl_list_for_each(seat, list, link) { - roots_cursor_constrain(seat->cursor, NULL, NAN, NAN); - } - } else { - wlr_log(WLR_ERROR, "unknown binding command: %s", command); - } -} diff --git a/rootston/config.c b/rootston/config.c deleted file mode 100644 index 314af264..00000000 --- a/rootston/config.c +++ /dev/null @@ -1,674 +0,0 @@ -#ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200809L -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/config.h" -#include "rootston/ini.h" -#include "rootston/input.h" -#include "rootston/keyboard.h" - -static void usage(const char *name, int ret) { - fprintf(stderr, - "usage: %s [-C ] [-E ]\n" - "\n" - " -C Path to the configuration file\n" - " (default: rootston.ini).\n" - " See `rootston.ini.example` for config\n" - " file documentation.\n" - " -E Command that will be ran at startup.\n" - " -D Enable damage tracking debugging.\n" - " -l Set log verbosity, where,\n" - " 0:SILENT, 1:ERROR, 2:INFO, 3+:DEBUG\n" - " (default: DEBUG)\n", - name); - - exit(ret); -} - -static struct wlr_box *parse_geometry(const char *str) { - // format: {width}x{height}+{x}+{y} - if (strlen(str) > 255) { - wlr_log(WLR_ERROR, "cannot parse geometry string, too long"); - return NULL; - } - - char *buf = strdup(str); - struct wlr_box *box = calloc(1, sizeof(struct wlr_box)); - - bool has_width = false; - bool has_height = false; - bool has_x = false; - bool has_y = false; - - char *pch = strtok(buf, "x+"); - while (pch != NULL) { - errno = 0; - char *endptr; - long val = strtol(pch, &endptr, 0); - - if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || - (errno != 0 && val == 0)) { - goto invalid_input; - } - - if (endptr == pch) { - goto invalid_input; - } - - if (!has_width) { - box->width = val; - has_width = true; - } else if (!has_height) { - box->height = val; - has_height = true; - } else if (!has_x) { - box->x = val; - has_x = true; - } else if (!has_y) { - box->y = val; - has_y = true; - } else { - break; - } - pch = strtok(NULL, "x+"); - } - - if (!has_width || !has_height) { - goto invalid_input; - } - - free(buf); - return box; - -invalid_input: - wlr_log(WLR_ERROR, "could not parse geometry string: %s", str); - free(buf); - free(box); - return NULL; -} - -static uint32_t parse_modifier(const char *symname) { - if (strcmp(symname, "Shift") == 0) { - return WLR_MODIFIER_SHIFT; - } else if (strcmp(symname, "Caps") == 0) { - return WLR_MODIFIER_CAPS; - } else if (strcmp(symname, "Ctrl") == 0) { - return WLR_MODIFIER_CTRL; - } else if (strcmp(symname, "Alt") == 0) { - return WLR_MODIFIER_ALT; - } else if (strcmp(symname, "Mod2") == 0) { - return WLR_MODIFIER_MOD2; - } else if (strcmp(symname, "Mod3") == 0) { - return WLR_MODIFIER_MOD3; - } else if (strcmp(symname, "Logo") == 0) { - return WLR_MODIFIER_LOGO; - } else if (strcmp(symname, "Mod5") == 0) { - return WLR_MODIFIER_MOD5; - } else { - return 0; - } -} - -static bool parse_modeline(const char *s, drmModeModeInfo *mode) { - char hsync[16]; - char vsync[16]; - float fclock; - - mode->type = DRM_MODE_TYPE_USERDEF; - - if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s", - &fclock, - &mode->hdisplay, - &mode->hsync_start, - &mode->hsync_end, - &mode->htotal, - &mode->vdisplay, - &mode->vsync_start, - &mode->vsync_end, - &mode->vtotal, hsync, vsync) != 11) { - return false; - } - - mode->clock = fclock * 1000; - mode->vrefresh = mode->clock * 1000.0 * 1000.0 - / mode->htotal / mode->vtotal; - if (strcasecmp(hsync, "+hsync") == 0) { - mode->flags |= DRM_MODE_FLAG_PHSYNC; - } else if (strcasecmp(hsync, "-hsync") == 0) { - mode->flags |= DRM_MODE_FLAG_NHSYNC; - } else { - return false; - } - - if (strcasecmp(vsync, "+vsync") == 0) { - mode->flags |= DRM_MODE_FLAG_PVSYNC; - } else if (strcasecmp(vsync, "-vsync") == 0) { - mode->flags |= DRM_MODE_FLAG_NVSYNC; - } else { - return false; - } - - snprintf(mode->name, sizeof(mode->name), "%dx%d@%d", - mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000); - - return true; -} - -static void add_binding_config(struct wl_list *bindings, const char* combination, - const char* command) { - 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); - char *symname = strtok(symnames, "+"); - while (symname) { - uint32_t modifier = parse_modifier(symname); - if (modifier != 0) { - bc->modifiers |= modifier; - } else { - xkb_keysym_t sym = xkb_keysym_from_name(symname, - XKB_KEYSYM_NO_FLAGS); - if (sym == XKB_KEY_NoSymbol) { - wlr_log(WLR_ERROR, "got unknown key binding symbol: %s", - symname); - free(bc); - bc = NULL; - break; - } - keysyms[bc->keysyms_len] = sym; - bc->keysyms_len++; - } - symname = strtok(NULL, "+"); - } - free(symnames); - - if (bc) { - wl_list_insert(bindings, &bc->link); - bc->command = strdup(command); - bc->keysyms = malloc(bc->keysyms_len * sizeof(xkb_keysym_t)); - memcpy(bc->keysyms, keysyms, bc->keysyms_len * sizeof(xkb_keysym_t)); - } -} - -static void add_switch_config(struct wl_list *switches, const char *switch_name, - const char *action, const char *command) { - struct roots_switch_config *sc = - calloc(1, sizeof(struct roots_switch_config)); - - if (strcmp(switch_name, "tablet") == 0) { - sc->switch_type = WLR_SWITCH_TYPE_TABLET_MODE; - } else if (strcmp(switch_name, "lid") == 0) { - sc->switch_type = WLR_SWITCH_TYPE_LID; - } else { - sc->switch_type = -1; - sc->name = strdup(switch_name); - } - - if (strcmp(action, "on") == 0) { - sc->switch_state = WLR_SWITCH_STATE_ON; - } else if (strcmp(action, "off") == 0) { - sc->switch_state = WLR_SWITCH_STATE_OFF; - } else if (strcmp(action, "toggle") == 0) { - sc->switch_state = WLR_SWITCH_STATE_TOGGLE; - } else { - wlr_log(WLR_ERROR, "Invalid switch action %s for switch %s:%s", - action, switch_name, action); - free(sc); - return; - } - - sc->command = strdup(command); - wl_list_insert(switches, &sc->link); -} - -static void config_handle_cursor(struct roots_config *config, - const char *seat_name, const char *name, const char *value) { - struct roots_cursor_config *cc; - bool found = false; - wl_list_for_each(cc, &config->cursors, link) { - if (strcmp(cc->seat, seat_name) == 0) { - found = true; - break; - } - } - - if (!found) { - cc = calloc(1, sizeof(struct roots_cursor_config)); - cc->seat = strdup(seat_name); - wl_list_insert(&config->cursors, &cc->link); - } - - if (strcmp(name, "map-to-output") == 0) { - free(cc->mapped_output); - cc->mapped_output = strdup(value); - } else if (strcmp(name, "geometry") == 0) { - free(cc->mapped_box); - cc->mapped_box = parse_geometry(value); - } else if (strcmp(name, "theme") == 0) { - free(cc->theme); - cc->theme = strdup(value); - } else if (strcmp(name, "default-image") == 0) { - free(cc->default_image); - cc->default_image = strdup(value); - } else { - wlr_log(WLR_ERROR, "got unknown cursor config: %s", name); - } -} - -static void config_handle_keyboard(struct roots_config *config, - const char *device_name, const char *name, const char *value) { - struct roots_keyboard_config *kc; - bool found = false; - wl_list_for_each(kc, &config->keyboards, link) { - if (strcmp(kc->name, device_name) == 0) { - found = true; - break; - } - } - - if (!found) { - kc = calloc(1, sizeof(struct roots_keyboard_config)); - kc->name = strdup(device_name); - wl_list_insert(&config->keyboards, &kc->link); - } - - if (strcmp(name, "meta-key") == 0) { - kc->meta_key = parse_modifier(value); - if (kc->meta_key == 0) { - wlr_log(WLR_ERROR, "got unknown meta key: %s", name); - } - } else if (strcmp(name, "rules") == 0) { - kc->rules = strdup(value); - } else if (strcmp(name, "model") == 0) { - kc->model = strdup(value); - } else if (strcmp(name, "layout") == 0) { - kc->layout = strdup(value); - } else if (strcmp(name, "variant") == 0) { - kc->variant = strdup(value); - } else if (strcmp(name, "options") == 0) { - kc->options = strdup(value); - } else if (strcmp(name, "repeat-rate") == 0) { - kc->repeat_rate = strtol(value, NULL, 10); - } else if (strcmp(name, "repeat-delay") == 0) { - kc->repeat_delay = strtol(value, NULL, 10); - } else { - wlr_log(WLR_ERROR, "got unknown keyboard config: %s", name); - } -} - -static const char *output_prefix = "output:"; -static const char *device_prefix = "device:"; -static const char *keyboard_prefix = "keyboard:"; -static const char *cursor_prefix = "cursor:"; -static const char *switch_prefix = "switch:"; - -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, "immediate") == 0) { - config->xwayland = true; - config->xwayland_lazy = false; - } else if (strcasecmp(value, "false") == 0) { - config->xwayland = false; - } else { - wlr_log(WLR_ERROR, "got unknown xwayland value: %s", value); - } - } else { - wlr_log(WLR_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 roots_output_config *oc; - bool found = false; - - wl_list_for_each(oc, &config->outputs, link) { - if (strcmp(oc->name, output_name) == 0) { - found = true; - break; - } - } - - if (!found) { - oc = calloc(1, sizeof(struct roots_output_config)); - oc->name = strdup(output_name); - oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; - oc->scale = 1; - oc->enable = true; - wl_list_init(&oc->modes); - wl_list_insert(&config->outputs, &oc->link); - } - - if (strcmp(name, "enable") == 0) { - if (strcasecmp(value, "true") == 0) { - oc->enable = true; - } else if (strcasecmp(value, "false") == 0) { - oc->enable = false; - } else { - wlr_log(WLR_ERROR, "got invalid output enable value: %s", value); - } - } else if (strcmp(name, "x") == 0) { - 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 = strtof(value, NULL); - assert(oc->scale > 0); - } else if (strcmp(name, "rotate") == 0) { - if (strcmp(value, "normal") == 0) { - oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; - } else if (strcmp(value, "90") == 0) { - oc->transform = WL_OUTPUT_TRANSFORM_90; - } else if (strcmp(value, "180") == 0) { - oc->transform = WL_OUTPUT_TRANSFORM_180; - } else if (strcmp(value, "270") == 0) { - oc->transform = WL_OUTPUT_TRANSFORM_270; - } else if (strcmp(value, "flipped") == 0) { - oc->transform = WL_OUTPUT_TRANSFORM_FLIPPED; - } else if (strcmp(value, "flipped-90") == 0) { - oc->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90; - } else if (strcmp(value, "flipped-180") == 0) { - oc->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180; - } else if (strcmp(value, "flipped-270") == 0) { - oc->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270; - } else { - wlr_log(WLR_ERROR, "got unknown transform value: %s", value); - } - } else if (strcmp(name, "mode") == 0) { - char *end; - oc->mode.width = strtol(value, &end, 10); - assert(*end == 'x'); - ++end; - oc->mode.height = strtol(end, &end, 10); - if (*end) { - assert(*end == '@'); - ++end; - oc->mode.refresh_rate = strtof(end, &end); - assert(strcmp("Hz", end) == 0); - } - wlr_log(WLR_DEBUG, "Configured output %s with mode %dx%d@%f", - oc->name, oc->mode.width, oc->mode.height, - oc->mode.refresh_rate); - } else if (strcmp(name, "modeline") == 0) { - struct roots_output_mode_config *mode = calloc(1, sizeof(*mode)); - - if (parse_modeline(value, &mode->info)) { - wl_list_insert(&oc->modes, &mode->link); - } else { - free(mode); - wlr_log(WLR_ERROR, "Invalid modeline: %s", value); - } - } - } else if (strncmp(cursor_prefix, section, strlen(cursor_prefix)) == 0) { - const char *seat_name = section + strlen(cursor_prefix); - config_handle_cursor(config, seat_name, name, value); - } else if (strcmp(section, "cursor") == 0) { - config_handle_cursor(config, ROOTS_CONFIG_DEFAULT_SEAT_NAME, name, - value); - } else if (strncmp(device_prefix, section, strlen(device_prefix)) == 0) { - const char *device_name = section + strlen(device_prefix); - - struct roots_device_config *dc; - bool found = false; - wl_list_for_each(dc, &config->devices, link) { - if (strcmp(dc->name, device_name) == 0) { - found = true; - break; - } - } - - if (!found) { - dc = calloc(1, sizeof(struct roots_device_config)); - dc->name = strdup(device_name); - dc->seat = strdup(ROOTS_CONFIG_DEFAULT_SEAT_NAME); - wl_list_insert(&config->devices, &dc->link); - } - - if (strcmp(name, "map-to-output") == 0) { - free(dc->mapped_output); - dc->mapped_output = strdup(value); - } 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 if (strcmp(name, "tap_enabled") == 0) { - if (strcasecmp(value, "true") == 0) { - dc->tap_enabled = true; - } else if (strcasecmp(value, "false") == 0) { - dc->tap_enabled = false; - } else { - wlr_log(WLR_ERROR, - "got unknown tap_enabled value: %s", - value); - } - } else { - wlr_log(WLR_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) { - const char *device_name = section + strlen(keyboard_prefix); - config_handle_keyboard(config, device_name, name, value); - } else if (strcmp(section, "bindings") == 0) { - add_binding_config(&config->bindings, name, value); - } else if (strncmp(switch_prefix, section, strlen(switch_prefix)) == 0) { - const char *switch_name = section + strlen(switch_prefix); - add_switch_config(&config->switches, switch_name, name, value); - } else { - wlr_log(WLR_ERROR, "got unknown config section: %s", section); - } - - return 1; -} - -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; - } - - config->xwayland = true; - config->xwayland_lazy = true; - wl_list_init(&config->outputs); - wl_list_init(&config->devices); - wl_list_init(&config->keyboards); - wl_list_init(&config->cursors); - wl_list_init(&config->bindings); - wl_list_init(&config->switches); - - int c; - unsigned int log_verbosity = WLR_DEBUG; - while ((c = getopt(argc, argv, "C:E:hDl:")) != -1) { - switch (c) { - case 'C': - config->config_path = strdup(optarg); - break; - case 'E': - config->startup_cmd = strdup(optarg); - break; - case 'D': - config->debug_damage_tracking = true; - break; - case 'l': - log_verbosity = strtoul(optarg, NULL, 10); - if (log_verbosity >= WLR_LOG_IMPORTANCE_LAST) { - log_verbosity = WLR_LOG_IMPORTANCE_LAST - 1; - } - break; - case 'h': - case '?': - usage(argv[0], c != 'h'); - } - } - wlr_log_init(log_verbosity, NULL); - - if (!config->config_path) { - // get the config path from the current directory - char cwd[MAXPATHLEN]; - if (getcwd(cwd, sizeof(cwd)) != NULL) { - char buf[MAXPATHLEN]; - if (snprintf(buf, MAXPATHLEN, "%s/%s", cwd, "rootston.ini") >= MAXPATHLEN) { - wlr_log(WLR_ERROR, "config path too long"); - exit(1); - } - config->config_path = strdup(buf); - } else { - wlr_log(WLR_ERROR, "could not get cwd"); - exit(1); - } - } - - int result = ini_parse(config->config_path, config_ini_handler, config); - - if (result == -1) { - wlr_log(WLR_DEBUG, "No config file found. Using sensible defaults."); - 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"); - add_binding_config(&config->bindings, "Logo+Escape", "break_pointer_constraint"); - 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); - } else if (result == -2) { - wlr_log(WLR_ERROR, "Could not allocate memory to parse config file"); - exit(1); - } else if (result != 0) { - wlr_log(WLR_ERROR, "Could not parse config file"); - exit(1); - } - - return config; -} - -void roots_config_destroy(struct roots_config *config) { - struct roots_output_config *oc, *otmp = NULL; - wl_list_for_each_safe(oc, otmp, &config->outputs, link) { - struct roots_output_mode_config *omc, *omctmp = NULL; - wl_list_for_each_safe(omc, omctmp, &oc->modes, link) { - free(omc); - } - free(oc->name); - free(oc); - } - - 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 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); - free(kc->layout); - free(kc->variant); - free(kc->options); - free(kc); - } - - struct roots_cursor_config *cc, *ctmp = NULL; - wl_list_for_each_safe(cc, ctmp, &config->cursors, link) { - free(cc->seat); - free(cc->mapped_output); - free(cc->mapped_box); - free(cc->theme); - free(cc->default_image); - free(cc); - } - - struct roots_binding_config *bc, *btmp = NULL; - wl_list_for_each_safe(bc, btmp, &config->bindings, link) { - free(bc->keysyms); - free(bc->command); - free(bc); - } - - free(config->config_path); - free(config); -} - -struct roots_output_config *roots_config_get_output(struct roots_config *config, - struct wlr_output *output) { - char name[88]; - snprintf(name, sizeof(name), "%s %s %s", output->make, output->model, - output->serial); - - struct roots_output_config *oc; - wl_list_for_each(oc, &config->outputs, link) { - if (strcmp(oc->name, output->name) == 0 || - strcmp(oc->name, name) == 0) { - return oc; - } - } - - return NULL; -} - -struct roots_device_config *roots_config_get_device(struct roots_config *config, - struct wlr_input_device *device) { - 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; - } - } - - return NULL; -} - -struct roots_keyboard_config *roots_config_get_keyboard( - struct roots_config *config, struct wlr_input_device *device) { - const char *device_name = ""; - if (device != NULL) { - device_name = device->name; - } - - struct roots_keyboard_config *kc; - wl_list_for_each(kc, &config->keyboards, link) { - if (strcmp(kc->name, device_name) == 0) { - return kc; - } - } - - return NULL; -} - -struct roots_cursor_config *roots_config_get_cursor(struct roots_config *config, - const char *seat_name) { - if (seat_name == NULL) { - seat_name = ROOTS_CONFIG_DEFAULT_SEAT_NAME; - } - - struct roots_cursor_config *cc; - wl_list_for_each(cc, &config->cursors, link) { - if (strcmp(cc->seat, seat_name) == 0) { - return cc; - } - } - - return NULL; -} diff --git a/rootston/cursor.c b/rootston/cursor.c deleted file mode 100644 index 6e09c06e..00000000 --- a/rootston/cursor.c +++ /dev/null @@ -1,632 +0,0 @@ -#define _XOPEN_SOURCE 700 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/cursor.h" -#include "rootston/desktop.h" -#include "rootston/view.h" -#include "rootston/xcursor.h" - -struct roots_cursor *roots_cursor_create(struct roots_seat *seat) { - struct roots_cursor *cursor = calloc(1, sizeof(struct roots_cursor)); - if (!cursor) { - return NULL; - } - cursor->cursor = wlr_cursor_create(); - if (!cursor->cursor) { - free(cursor); - return NULL; - } - cursor->default_xcursor = ROOTS_XCURSOR_DEFAULT; - return cursor; -} - -void roots_cursor_destroy(struct roots_cursor *cursor) { - // TODO -} - -static void seat_view_deco_motion(struct roots_seat_view *view, - double deco_sx, double deco_sy) { - struct roots_cursor *cursor = view->seat->cursor; - - double sx = deco_sx; - double sy = deco_sy; - if (view->has_button_grab) { - sx = view->grab_sx; - sy = view->grab_sy; - } - - enum roots_deco_part parts = view_get_deco_part(view->view, sx, sy); - - bool is_titlebar = (parts & ROOTS_DECO_PART_TITLEBAR); - uint32_t edges = 0; - if (parts & ROOTS_DECO_PART_LEFT_BORDER) { - edges |= WLR_EDGE_LEFT; - } else if (parts & ROOTS_DECO_PART_RIGHT_BORDER) { - edges |= WLR_EDGE_RIGHT; - } else if (parts & ROOTS_DECO_PART_BOTTOM_BORDER) { - edges |= WLR_EDGE_BOTTOM; - } else if (parts & ROOTS_DECO_PART_TOP_BORDER) { - edges |= WLR_EDGE_TOP; - } - - if (view->has_button_grab) { - if (is_titlebar) { - roots_seat_begin_move(view->seat, view->view); - } else if (edges) { - roots_seat_begin_resize(view->seat, view->view, edges); - } - view->has_button_grab = false; - } else { - if (is_titlebar) { - wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, - cursor->default_xcursor, cursor->cursor); - } else if (edges) { - const char *resize_name = wlr_xcursor_get_resize_name(edges); - wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, - resize_name, cursor->cursor); - } - } -} - -static void seat_view_deco_leave(struct roots_seat_view *view) { - struct roots_cursor *cursor = view->seat->cursor; - wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, - cursor->default_xcursor, cursor->cursor); - view->has_button_grab = false; -} - -static void seat_view_deco_button(struct roots_seat_view *view, double sx, - double sy, uint32_t button, uint32_t state) { - if (button == BTN_LEFT && state == WLR_BUTTON_PRESSED) { - view->has_button_grab = true; - view->grab_sx = sx; - view->grab_sy = sy; - } else { - view->has_button_grab = false; - } - - enum roots_deco_part parts = view_get_deco_part(view->view, sx, sy); - if (state == WLR_BUTTON_RELEASED && (parts & ROOTS_DECO_PART_TITLEBAR)) { - struct roots_cursor *cursor = view->seat->cursor; - wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, - cursor->default_xcursor, cursor->cursor); - } -} - -static void roots_passthrough_cursor(struct roots_cursor *cursor, - uint32_t time) { - double sx, sy; - struct roots_view *view = NULL; - struct roots_seat *seat = cursor->seat; - struct roots_desktop *desktop = seat->input->server->desktop; - struct wlr_surface *surface = desktop_surface_at(desktop, - cursor->cursor->x, cursor->cursor->y, &sx, &sy, &view); - - struct wl_client *client = NULL; - if (surface) { - client = wl_resource_get_client(surface->resource); - } - - if (surface && !roots_seat_allow_input(seat, surface->resource)) { - return; - } - - if (cursor->cursor_client != client) { - wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, - cursor->default_xcursor, cursor->cursor); - cursor->cursor_client = client; - } - - if (view) { - struct roots_seat_view *seat_view = - roots_seat_view_from_view(seat, view); - - if (cursor->pointer_view && - !cursor->wlr_surface && (surface || seat_view != cursor->pointer_view)) { - seat_view_deco_leave(cursor->pointer_view); - } - - cursor->pointer_view = seat_view; - - if (!surface) { - seat_view_deco_motion(seat_view, sx, sy); - } - } else { - cursor->pointer_view = NULL; - } - - cursor->wlr_surface = surface; - - if (surface) { - 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(seat->seat); - } - - if (seat->drag_icon != NULL) { - roots_drag_icon_update_position(seat->drag_icon); - } -} - -static inline int64_t timespec_to_msec(const struct timespec *a) { - return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; -} - -void roots_cursor_update_focus(struct roots_cursor *cursor) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - roots_passthrough_cursor(cursor, timespec_to_msec(&now)); -} - -void roots_cursor_update_position(struct roots_cursor *cursor, - uint32_t time) { - struct roots_seat *seat = cursor->seat; - struct roots_view *view; - switch (cursor->mode) { - case ROOTS_CURSOR_PASSTHROUGH: - roots_passthrough_cursor(cursor, time); - break; - case ROOTS_CURSOR_MOVE: - view = roots_seat_get_focus(seat); - if (view != NULL) { - double dx = cursor->cursor->x - cursor->offs_x; - double dy = cursor->cursor->y - cursor->offs_y; - view_move(view, cursor->view_x + dx, - cursor->view_y + dy); - } - break; - case ROOTS_CURSOR_RESIZE: - view = roots_seat_get_focus(seat); - if (view != NULL) { - double dx = cursor->cursor->x - cursor->offs_x; - double dy = cursor->cursor->y - cursor->offs_y; - double x = view->box.x; - double y = view->box.y; - int width = cursor->view_width; - int height = cursor->view_height; - if (cursor->resize_edges & WLR_EDGE_TOP) { - y = cursor->view_y + dy; - height -= dy; - if (height < 1) { - y += height; - } - } else if (cursor->resize_edges & WLR_EDGE_BOTTOM) { - height += dy; - } - if (cursor->resize_edges & WLR_EDGE_LEFT) { - x = cursor->view_x + dx; - width -= dx; - if (width < 1) { - x += width; - } - } else if (cursor->resize_edges & WLR_EDGE_RIGHT) { - width += dx; - } - view_move_resize(view, x, y, - width < 1 ? 1 : width, - height < 1 ? 1 : height); - } - break; - case ROOTS_CURSOR_ROTATE: - view = roots_seat_get_focus(seat); - if (view != NULL) { - int ox = view->box.x + view->wlr_surface->current.width/2, - oy = view->box.y + view->wlr_surface->current.height/2; - 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(ux*vy - uy*vx, vx*ux + vy*uy); - int steps = 12; - angle = round(angle/M_PI*steps) / (steps/M_PI); - view_rotate(view, cursor->view_rotation + angle); - } - break; - } -} - -static void roots_cursor_press_button(struct roots_cursor *cursor, - struct wlr_input_device *device, uint32_t time, uint32_t button, - uint32_t state, double lx, double ly) { - struct roots_seat *seat = cursor->seat; - struct roots_desktop *desktop = seat->input->server->desktop; - - bool is_touch = device->type == WLR_INPUT_DEVICE_TOUCH; - - double sx, sy; - struct roots_view *view; - struct wlr_surface *surface = desktop_surface_at(desktop, - lx, ly, &sx, &sy, &view); - - if (state == WLR_BUTTON_PRESSED && view && - roots_seat_has_meta_pressed(seat)) { - roots_seat_set_focus(seat, view); - - uint32_t edges; - switch (button) { - case BTN_LEFT: - roots_seat_begin_move(seat, view); - break; - case BTN_RIGHT: - edges = 0; - if (sx < view->wlr_surface->current.width/2) { - edges |= WLR_EDGE_LEFT; - } else { - edges |= WLR_EDGE_RIGHT; - } - if (sy < view->wlr_surface->current.height/2) { - edges |= WLR_EDGE_TOP; - } else { - edges |= WLR_EDGE_BOTTOM; - } - roots_seat_begin_resize(seat, view, edges); - break; - case BTN_MIDDLE: - roots_seat_begin_rotate(seat, view); - break; - } - } else { - if (view && !surface && cursor->pointer_view) { - seat_view_deco_button(cursor->pointer_view, - sx, sy, button, state); - } - - if (state == WLR_BUTTON_RELEASED && - cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { - cursor->mode = ROOTS_CURSOR_PASSTHROUGH; - } - - if (state == WLR_BUTTON_PRESSED) { - if (view) { - roots_seat_set_focus(seat, view); - } - if (surface && wlr_surface_is_layer_surface(surface)) { - struct wlr_layer_surface_v1 *layer = - wlr_layer_surface_v1_from_wlr_surface(surface); - if (layer->current.keyboard_interactive) { - roots_seat_set_focus_layer(seat, layer); - } - } - } - } - - if (!is_touch) { - wlr_seat_pointer_notify_button(seat->seat, time, button, state); - } -} - -void roots_cursor_handle_motion(struct roots_cursor *cursor, - struct wlr_event_pointer_motion *event) { - double dx = event->delta_x; - double dy = event->delta_y; - - double dx_unaccel = event->unaccel_dx; - double dy_unaccel = event->unaccel_dy; - - wlr_relative_pointer_manager_v1_send_relative_motion( - cursor->seat->input->server->desktop->relative_pointer_manager, - cursor->seat->seat, (uint64_t)event->time_msec * 1000, dx, dy, - dx_unaccel, dy_unaccel); - - if (cursor->active_constraint) { - struct roots_view *view = cursor->pointer_view->view; - assert(view); - - // TODO: handle rotated views - if (view->rotation == 0.0) { - double lx1 = cursor->cursor->x; - double ly1 = cursor->cursor->y; - - double lx2 = lx1 + dx; - double ly2 = ly1 + dy; - - double sx1 = lx1 - view->box.x; - double sy1 = ly1 - view->box.y; - - double sx2 = lx2 - view->box.x; - double sy2 = ly2 - view->box.y; - - double sx2_confined, sy2_confined; - if (!wlr_region_confine(&cursor->confine, sx1, sy1, sx2, sy2, - &sx2_confined, &sy2_confined)) { - return; - } - - dx = sx2_confined - sx1; - dy = sy2_confined - sy1; - } - } - - wlr_cursor_move(cursor->cursor, event->device, dx, dy); - roots_cursor_update_position(cursor, event->time_msec); -} - -void roots_cursor_handle_motion_absolute(struct roots_cursor *cursor, - struct wlr_event_pointer_motion_absolute *event) { - double lx, ly; - wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, event->x, - event->y, &lx, &ly); - - double dx = lx - cursor->cursor->x; - double dy = ly - cursor->cursor->y; - wlr_relative_pointer_manager_v1_send_relative_motion( - cursor->seat->input->server->desktop->relative_pointer_manager, - cursor->seat->seat, (uint64_t)event->time_msec * 1000, dx, dy, dx, dy); - - if (cursor->pointer_view) { - struct roots_view *view = cursor->pointer_view->view; - - if (cursor->active_constraint && - !pixman_region32_contains_point(&cursor->confine, - floor(lx - view->box.x), floor(ly - view->box.y), NULL)) { - return; - } - } - - wlr_cursor_warp_closest(cursor->cursor, event->device, lx, ly); - 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, cursor->cursor->x, cursor->cursor->y); -} - -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, event->delta_discrete, event->source); -} - -void roots_cursor_handle_frame(struct roots_cursor *cursor) { - wlr_seat_pointer_notify_frame(cursor->seat->seat); -} - -void roots_cursor_handle_touch_down(struct roots_cursor *cursor, - struct wlr_event_touch_down *event) { - struct roots_desktop *desktop = cursor->seat->input->server->desktop; - double lx, ly; - wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, - event->x, event->y, &lx, &ly); - - double sx, sy; - struct wlr_surface *surface = desktop_surface_at( - desktop, lx, ly, &sx, &sy, NULL); - - uint32_t serial = 0; - if (surface && roots_seat_allow_input(cursor->seat, surface->resource)) { - serial = wlr_seat_touch_notify_down(cursor->seat->seat, surface, - event->time_msec, event->touch_id, sx, sy); - } - - if (serial && wlr_seat_touch_num_points(cursor->seat->seat) == 1) { - cursor->seat->touch_id = event->touch_id; - cursor->seat->touch_x = lx; - cursor->seat->touch_y = ly; - roots_cursor_press_button(cursor, event->device, event->time_msec, - BTN_LEFT, 1, lx, ly); - } -} - -void roots_cursor_handle_touch_up(struct roots_cursor *cursor, - struct wlr_event_touch_up *event) { - struct wlr_touch_point *point = - wlr_seat_touch_get_point(cursor->seat->seat, event->touch_id); - if (!point) { - return; - } - - if (wlr_seat_touch_num_points(cursor->seat->seat) == 1) { - roots_cursor_press_button(cursor, event->device, event->time_msec, - BTN_LEFT, 0, cursor->seat->touch_x, cursor->seat->touch_y); - } - - wlr_seat_touch_notify_up(cursor->seat->seat, event->time_msec, - event->touch_id); -} - -void roots_cursor_handle_touch_motion(struct roots_cursor *cursor, - struct wlr_event_touch_motion *event) { - struct roots_desktop *desktop = cursor->seat->input->server->desktop; - struct wlr_touch_point *point = - wlr_seat_touch_get_point(cursor->seat->seat, event->touch_id); - if (!point) { - return; - } - - double lx, ly; - wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, - event->x, event->y, &lx, &ly); - - double sx, sy; - struct wlr_surface *surface = desktop_surface_at( - desktop, lx, ly, &sx, &sy, NULL); - - if (surface && roots_seat_allow_input(cursor->seat, surface->resource)) { - wlr_seat_touch_point_focus(cursor->seat->seat, surface, - event->time_msec, event->touch_id, sx, sy); - wlr_seat_touch_notify_motion(cursor->seat->seat, event->time_msec, - event->touch_id, sx, sy); - } else { - wlr_seat_touch_point_clear_focus(cursor->seat->seat, event->time_msec, - event->touch_id); - } - - if (event->touch_id == cursor->seat->touch_id) { - cursor->seat->touch_x = lx; - cursor->seat->touch_y = ly; - } -} - -void roots_cursor_handle_tool_axis(struct roots_cursor *cursor, - struct wlr_event_tablet_tool_axis *event) { - double x = NAN, y = NAN; - if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X) && - (event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { - x = event->x; - y = event->y; - } else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_X)) { - x = event->x; - } else if ((event->updated_axes & WLR_TABLET_TOOL_AXIS_Y)) { - y = event->y; - } - - double lx, ly; - wlr_cursor_absolute_to_layout_coords(cursor->cursor, event->device, - x, y, &lx, &ly); - - - if (cursor->pointer_view) { - struct roots_view *view = cursor->pointer_view->view; - - if (cursor->active_constraint && - !pixman_region32_contains_point(&cursor->confine, - floor(lx - view->box.x), floor(ly - view->box.y), NULL)) { - return; - } - } - - wlr_cursor_warp_closest(cursor->cursor, event->device, lx, ly); - roots_cursor_update_position(cursor, event->time_msec); -} - -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, cursor->cursor->x, - cursor->cursor->y); -} - -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(WLR_DEBUG, "Denying request to set cursor from unfocused client"); - return; - } - - wlr_cursor_set_surface(cursor->cursor, event->surface, event->hotspot_x, - event->hotspot_y); - cursor->cursor_client = event->seat_client->client; -} - -void roots_cursor_handle_focus_change(struct roots_cursor *cursor, - struct wlr_seat_pointer_focus_change_event *event) { - double sx = event->sx; - double sy = event->sy; - - double lx = cursor->cursor->x; - double ly = cursor->cursor->y; - - wlr_log(WLR_DEBUG, "entered surface %p, lx: %f, ly: %f, sx: %f, sy: %f", - event->new_surface, lx, ly, sx, sy); - - roots_cursor_constrain(cursor, - wlr_pointer_constraints_v1_constraint_for_surface( - cursor->seat->input->server->desktop->pointer_constraints, - event->new_surface, cursor->seat->seat), - sx, sy); -} - -void roots_cursor_handle_constraint_commit(struct roots_cursor *cursor) { - struct roots_desktop *desktop = cursor->seat->input->server->desktop; - - struct roots_view *view; - double sx, sy; - struct wlr_surface *surface = desktop_surface_at(desktop, - cursor->cursor->x, cursor->cursor->y, &sx, &sy, &view); - // This should never happen but views move around right when they're - // created from (0, 0) to their actual coordinates. - if (surface != cursor->active_constraint->surface) { - roots_cursor_update_focus(cursor); - } else { - roots_cursor_constrain(cursor, cursor->active_constraint, sx, sy); - } -} - -static void handle_constraint_commit(struct wl_listener *listener, - void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, constraint_commit); - assert(cursor->active_constraint->surface == data); - roots_cursor_handle_constraint_commit(cursor); -} - -void roots_cursor_constrain(struct roots_cursor *cursor, - struct wlr_pointer_constraint_v1 *constraint, double sx, double sy) { - if (cursor->active_constraint == constraint) { - return; - } - - wlr_log(WLR_DEBUG, "roots_cursor_constrain(%p, %p)", - cursor, constraint); - wlr_log(WLR_DEBUG, "cursor->active_constraint: %p", - cursor->active_constraint); - - wl_list_remove(&cursor->constraint_commit.link); - wl_list_init(&cursor->constraint_commit.link); - if (cursor->active_constraint) { - wlr_pointer_constraint_v1_send_deactivated( - cursor->active_constraint); - } - - cursor->active_constraint = constraint; - - if (constraint == NULL) { - return; - } - - wlr_pointer_constraint_v1_send_activated(constraint); - - wl_list_remove(&cursor->constraint_commit.link); - wl_signal_add(&constraint->surface->events.commit, - &cursor->constraint_commit); - cursor->constraint_commit.notify = handle_constraint_commit; - - pixman_region32_clear(&cursor->confine); - - pixman_region32_t *region = &constraint->region; - - if (!pixman_region32_contains_point(region, floor(sx), floor(sy), NULL)) { - // Warp into region if possible - int nboxes; - pixman_box32_t *boxes = pixman_region32_rectangles(region, &nboxes); - if (nboxes > 0) { - struct roots_view *view = cursor->pointer_view->view; - - double sx = (boxes[0].x1 + boxes[0].x2) / 2.; - double sy = (boxes[0].y1 + boxes[0].y2) / 2.; - - rotate_child_position(&sx, &sy, 0, 0, view->box.width, view->box.height, - view->rotation); - - double lx = view->box.x + sx; - double ly = view->box.y + sy; - - wlr_cursor_warp_closest(cursor->cursor, NULL, lx, ly); - } - } - - // A locked pointer will result in an empty region, thus disallowing all movement - if (constraint->type == WLR_POINTER_CONSTRAINT_V1_CONFINED) { - pixman_region32_copy(&cursor->confine, region); - } -} diff --git a/rootston/desktop.c b/rootston/desktop.c deleted file mode 100644 index 3d9888e3..00000000 --- a/rootston/desktop.c +++ /dev/null @@ -1,465 +0,0 @@ -#define _POSIX_C_SOURCE 200112L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/layers.h" -#include "rootston/seat.h" -#include "rootston/server.h" -#include "rootston/view.h" -#include "rootston/virtual_keyboard.h" -#include "rootston/xcursor.h" -#include "wlr-layer-shell-unstable-v1-protocol.h" - -static bool view_at(struct roots_view *view, double lx, double ly, - struct wlr_surface **surface, double *sx, double *sy) { - if (view->wlr_surface == NULL) { - return false; - } - - double view_sx = lx - view->box.x; - double view_sy = ly - view->box.y; - rotate_child_position(&view_sx, &view_sy, 0, 0, - view->box.width, view->box.height, -view->rotation); - - double _sx, _sy; - struct wlr_surface *_surface = NULL; - switch (view->type) { - case ROOTS_XDG_SHELL_V6_VIEW:; - struct roots_xdg_surface_v6 *xdg_surface_v6 = - roots_xdg_surface_v6_from_view(view); - _surface = wlr_xdg_surface_v6_surface_at(xdg_surface_v6->xdg_surface_v6, - view_sx, view_sy, &_sx, &_sy); - break; - case ROOTS_XDG_SHELL_VIEW:; - struct roots_xdg_surface *xdg_surface = - roots_xdg_surface_from_view(view); - _surface = wlr_xdg_surface_surface_at(xdg_surface->xdg_surface, - view_sx, view_sy, &_sx, &_sy); - break; -#if WLR_HAS_XWAYLAND - case ROOTS_XWAYLAND_VIEW: - _surface = wlr_surface_surface_at(view->wlr_surface, - view_sx, view_sy, &_sx, &_sy); - break; -#endif - } - if (_surface != NULL) { - *sx = _sx; - *sy = _sy; - *surface = _surface; - return true; - } - - if (view_get_deco_part(view, view_sx, view_sy)) { - *sx = view_sx; - *sy = view_sy; - *surface = NULL; - return true; - } - - return false; -} - -static struct roots_view *desktop_view_at(struct roots_desktop *desktop, - double lx, double ly, struct wlr_surface **surface, - double *sx, double *sy) { - struct roots_view *view; - wl_list_for_each(view, &desktop->views, link) { - if (view_at(view, lx, ly, surface, sx, sy)) { - return view; - } - } - return NULL; -} - -static struct wlr_surface *layer_surface_at(struct roots_output *output, - struct wl_list *layer, double ox, double oy, double *sx, double *sy) { - struct roots_layer_surface *roots_surface; - wl_list_for_each_reverse(roots_surface, layer, link) { - double _sx = ox - roots_surface->geo.x; - double _sy = oy - roots_surface->geo.y; - - struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( - roots_surface->layer_surface, _sx, _sy, sx, sy); - - if (sub) { - return sub; - } - } - - return NULL; -} - -struct wlr_surface *desktop_surface_at(struct roots_desktop *desktop, - double lx, double ly, double *sx, double *sy, - struct roots_view **view) { - struct wlr_surface *surface = NULL; - struct wlr_output *wlr_output = - wlr_output_layout_output_at(desktop->layout, lx, ly); - struct roots_output *roots_output = NULL; - double ox = lx, oy = ly; - if (view) { - *view = NULL; - } - - if (wlr_output) { - roots_output = wlr_output->data; - wlr_output_layout_output_coords(desktop->layout, wlr_output, &ox, &oy); - - if ((surface = layer_surface_at(roots_output, - &roots_output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - ox, oy, sx, sy))) { - return surface; - } - - struct roots_output *output = - desktop_output_from_wlr_output(desktop, wlr_output); - if (output != NULL && output->fullscreen_view != NULL) { - if (view_at(output->fullscreen_view, lx, ly, &surface, sx, sy)) { - return surface; - } else { - return NULL; - } - } - - if ((surface = layer_surface_at(roots_output, - &roots_output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - ox, oy, sx, sy))) { - return surface; - } - } - - struct roots_view *_view; - if ((_view = desktop_view_at(desktop, lx, ly, &surface, sx, sy))) { - if (view) { - *view = _view; - } - return surface; - } - - if (wlr_output) { - if ((surface = layer_surface_at(roots_output, - &roots_output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - ox, oy, sx, sy))) { - return surface; - } - if ((surface = layer_surface_at(roots_output, - &roots_output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - ox, oy, sx, sy))) { - return surface; - } - } - return NULL; -} - -static void handle_layout_change(struct wl_listener *listener, void *data) { - struct roots_desktop *desktop = - wl_container_of(listener, desktop, layout_change); - - struct wlr_output *center_output = - wlr_output_layout_get_center_output(desktop->layout); - if (center_output == NULL) { - return; - } - - struct wlr_box *center_output_box = - wlr_output_layout_get_box(desktop->layout, center_output); - double center_x = center_output_box->x + center_output_box->width/2; - double center_y = center_output_box->y + center_output_box->height/2; - - struct roots_view *view; - wl_list_for_each(view, &desktop->views, link) { - struct wlr_box box; - view_get_box(view, &box); - - if (wlr_output_layout_intersects(desktop->layout, NULL, &box)) { - continue; - } - - view_move(view, center_x - box.width/2, center_y - box.height/2); - } -} - -static void input_inhibit_activate(struct wl_listener *listener, void *data) { - struct roots_desktop *desktop = wl_container_of( - listener, desktop, input_inhibit_activate); - struct roots_seat *seat; - wl_list_for_each(seat, &desktop->server->input->seats, link) { - roots_seat_set_exclusive_client(seat, - desktop->input_inhibit->active_client); - } -} - -static void input_inhibit_deactivate(struct wl_listener *listener, void *data) { - struct roots_desktop *desktop = wl_container_of( - listener, desktop, input_inhibit_deactivate); - struct roots_seat *seat; - wl_list_for_each(seat, &desktop->server->input->seats, link) { - roots_seat_set_exclusive_client(seat, NULL); - } -} - -static void handle_constraint_destroy(struct wl_listener *listener, - void *data) { - struct roots_pointer_constraint *constraint = - wl_container_of(listener, constraint, destroy); - struct wlr_pointer_constraint_v1 *wlr_constraint = data; - struct roots_seat *seat = wlr_constraint->seat->data; - - wl_list_remove(&constraint->destroy.link); - - if (seat->cursor->active_constraint == wlr_constraint) { - wl_list_remove(&seat->cursor->constraint_commit.link); - wl_list_init(&seat->cursor->constraint_commit.link); - seat->cursor->active_constraint = NULL; - - if (wlr_constraint->current.committed & - WLR_POINTER_CONSTRAINT_V1_STATE_CURSOR_HINT && - seat->cursor->pointer_view) { - double sx = wlr_constraint->current.cursor_hint.x; - double sy = wlr_constraint->current.cursor_hint.y; - - struct roots_view *view = seat->cursor->pointer_view->view; - rotate_child_position(&sx, &sy, 0, 0, view->box.width, view->box.height, - view->rotation); - double lx = view->box.x + sx; - double ly = view->box.y + sy; - - wlr_cursor_warp(seat->cursor->cursor, NULL, lx, ly); - } - } - - free(constraint); -} - -static void handle_pointer_constraint(struct wl_listener *listener, - void *data) { - struct wlr_pointer_constraint_v1 *wlr_constraint = data; - struct roots_seat *seat = wlr_constraint->seat->data; - - struct roots_pointer_constraint *constraint = - calloc(1, sizeof(struct roots_pointer_constraint)); - constraint->constraint = wlr_constraint; - - constraint->destroy.notify = handle_constraint_destroy; - wl_signal_add(&wlr_constraint->events.destroy, &constraint->destroy); - - double sx, sy; - struct wlr_surface *surface = desktop_surface_at( - seat->input->server->desktop, - seat->cursor->cursor->x, seat->cursor->cursor->y, &sx, &sy, NULL); - - if (surface == wlr_constraint->surface) { - assert(!seat->cursor->active_constraint); - roots_cursor_constrain(seat->cursor, wlr_constraint, sx, sy); - } -} - -struct roots_desktop *desktop_create(struct roots_server *server, - struct roots_config *config) { - wlr_log(WLR_DEBUG, "Initializing roots desktop"); - - struct roots_desktop *desktop = calloc(1, sizeof(struct roots_desktop)); - if (desktop == NULL) { - return NULL; - } - - wl_list_init(&desktop->views); - wl_list_init(&desktop->outputs); - - desktop->new_output.notify = handle_new_output; - wl_signal_add(&server->backend->events.new_output, &desktop->new_output); - - desktop->server = server; - desktop->config = config; - - desktop->layout = wlr_output_layout_create(); - wlr_xdg_output_manager_v1_create(server->wl_display, desktop->layout); - desktop->layout_change.notify = handle_layout_change; - wl_signal_add(&desktop->layout->events.change, &desktop->layout_change); - - desktop->compositor = wlr_compositor_create(server->wl_display, - server->renderer); - - desktop->xdg_shell_v6 = wlr_xdg_shell_v6_create(server->wl_display); - wl_signal_add(&desktop->xdg_shell_v6->events.new_surface, - &desktop->xdg_shell_v6_surface); - desktop->xdg_shell_v6_surface.notify = handle_xdg_shell_v6_surface; - - desktop->xdg_shell = wlr_xdg_shell_create(server->wl_display); - wl_signal_add(&desktop->xdg_shell->events.new_surface, - &desktop->xdg_shell_surface); - desktop->xdg_shell_surface.notify = handle_xdg_shell_surface; - - desktop->layer_shell = wlr_layer_shell_v1_create(server->wl_display); - wl_signal_add(&desktop->layer_shell->events.new_surface, - &desktop->layer_shell_surface); - desktop->layer_shell_surface.notify = handle_layer_shell_surface; - - desktop->tablet_v2 = wlr_tablet_v2_create(server->wl_display); - - const char *cursor_theme = NULL; -#if WLR_HAS_XWAYLAND - const char *cursor_default = ROOTS_XCURSOR_DEFAULT; -#endif - struct roots_cursor_config *cc = - roots_config_get_cursor(config, ROOTS_CONFIG_DEFAULT_SEAT_NAME); - if (cc != NULL) { - cursor_theme = cc->theme; -#if WLR_HAS_XWAYLAND - if (cc->default_image != NULL) { - cursor_default = cc->default_image; - } -#endif - } - - char cursor_size_fmt[16]; - snprintf(cursor_size_fmt, sizeof(cursor_size_fmt), - "%d", ROOTS_XCURSOR_SIZE); - setenv("XCURSOR_SIZE", cursor_size_fmt, 1); - if (cursor_theme != NULL) { - setenv("XCURSOR_THEME", cursor_theme, 1); - } - -#if WLR_HAS_XWAYLAND - desktop->xcursor_manager = wlr_xcursor_manager_create(cursor_theme, - ROOTS_XCURSOR_SIZE); - if (desktop->xcursor_manager == NULL) { - wlr_log(WLR_ERROR, "Cannot create XCursor manager for theme %s", - cursor_theme); - free(desktop); - return NULL; - } - - if (config->xwayland) { - desktop->xwayland = wlr_xwayland_create(server->wl_display, - desktop->compositor, config->xwayland_lazy); - wl_signal_add(&desktop->xwayland->events.new_surface, - &desktop->xwayland_surface); - desktop->xwayland_surface.notify = handle_xwayland_surface; - - setenv("DISPLAY", desktop->xwayland->display_name, true); - - if (wlr_xcursor_manager_load(desktop->xcursor_manager, 1)) { - wlr_log(WLR_ERROR, "Cannot load XWayland XCursor theme"); - } - struct wlr_xcursor *xcursor = wlr_xcursor_manager_get_xcursor( - desktop->xcursor_manager, cursor_default, 1); - if (xcursor != NULL) { - struct wlr_xcursor_image *image = xcursor->images[0]; - wlr_xwayland_set_cursor(desktop->xwayland, image->buffer, - image->width * 4, image->width, image->height, image->hotspot_x, - image->hotspot_y); - } - } -#endif - - desktop->gamma_control_manager_v1 = wlr_gamma_control_manager_v1_create( - server->wl_display); - desktop->export_dmabuf_manager_v1 = - wlr_export_dmabuf_manager_v1_create(server->wl_display); - desktop->server_decoration_manager = - wlr_server_decoration_manager_create(server->wl_display); - wlr_server_decoration_manager_set_default_mode( - desktop->server_decoration_manager, - WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT); - desktop->idle = wlr_idle_create(server->wl_display); - desktop->idle_inhibit = wlr_idle_inhibit_v1_create(server->wl_display); - desktop->primary_selection_device_manager = - wlr_gtk_primary_selection_device_manager_create(server->wl_display); - desktop->input_inhibit = - wlr_input_inhibit_manager_create(server->wl_display); - desktop->input_inhibit_activate.notify = input_inhibit_activate; - wl_signal_add(&desktop->input_inhibit->events.activate, - &desktop->input_inhibit_activate); - desktop->input_inhibit_deactivate.notify = input_inhibit_deactivate; - wl_signal_add(&desktop->input_inhibit->events.deactivate, - &desktop->input_inhibit_deactivate); - - desktop->input_method = - wlr_input_method_manager_v2_create(server->wl_display); - - desktop->text_input = wlr_text_input_manager_v3_create(server->wl_display); - - desktop->virtual_keyboard = wlr_virtual_keyboard_manager_v1_create( - server->wl_display); - wl_signal_add(&desktop->virtual_keyboard->events.new_virtual_keyboard, - &desktop->virtual_keyboard_new); - desktop->virtual_keyboard_new.notify = handle_virtual_keyboard; - - desktop->screencopy = wlr_screencopy_manager_v1_create(server->wl_display); - - desktop->xdg_decoration_manager = - wlr_xdg_decoration_manager_v1_create(server->wl_display); - wl_signal_add(&desktop->xdg_decoration_manager->events.new_toplevel_decoration, - &desktop->xdg_toplevel_decoration); - desktop->xdg_toplevel_decoration.notify = handle_xdg_toplevel_decoration; - - desktop->pointer_constraints = - wlr_pointer_constraints_v1_create(server->wl_display); - desktop->pointer_constraint.notify = handle_pointer_constraint; - wl_signal_add(&desktop->pointer_constraints->events.new_constraint, - &desktop->pointer_constraint); - - desktop->presentation = - wlr_presentation_create(server->wl_display, server->backend); - desktop->foreign_toplevel_manager_v1 = - wlr_foreign_toplevel_manager_v1_create(server->wl_display); - desktop->relative_pointer_manager = - wlr_relative_pointer_manager_v1_create(server->wl_display); - desktop->pointer_gestures = - wlr_pointer_gestures_v1_create(server->wl_display); - - desktop->output_manager_v1 = - wlr_output_manager_v1_create(server->wl_display); - desktop->output_manager_apply.notify = handle_output_manager_apply; - wl_signal_add(&desktop->output_manager_v1->events.apply, - &desktop->output_manager_apply); - desktop->output_manager_test.notify = handle_output_manager_test; - wl_signal_add(&desktop->output_manager_v1->events.test, - &desktop->output_manager_test); - - wlr_primary_selection_v1_device_manager_create(server->wl_display); - wlr_data_control_manager_v1_create(server->wl_display); - - return desktop; -} - -void desktop_destroy(struct roots_desktop *desktop) { - // TODO -} - -struct roots_output *desktop_output_from_wlr_output( - struct roots_desktop *desktop, struct wlr_output *wlr_output) { - struct roots_output *output; - wl_list_for_each(output, &desktop->outputs, link) { - if (output->wlr_output == wlr_output) { - return output; - } - } - return NULL; -} diff --git a/rootston/ini.c b/rootston/ini.c deleted file mode 100644 index f515dd38..00000000 --- a/rootston/ini.c +++ /dev/null @@ -1,195 +0,0 @@ -/* inih -- simple .INI file parser - -inih is released under the New BSD license (see LICENSE.txt). Go to the project -home page for more info: - -https://github.com/benhoyt/inih - -*/ - -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif - -#include -#include -#include - -#include "rootston/ini.h" - -#if !INI_USE_STACK -#include -#endif - -#define MAX_SECTION 50 -#define MAX_NAME 50 - -/* Strip whitespace chars off end of given string, in place. Return s. */ -static char* rstrip(char* s) -{ - char* p = s + strlen(s); - while (p > s && isspace((unsigned char)(*--p))) - *p = '\0'; - return s; -} - -/* Return pointer to first non-whitespace char in given string. */ -static char* lskip(const char* s) -{ - while (*s && isspace((unsigned char)(*s))) - s++; - return (char*)s; -} - -/* Return pointer to first char (of chars) or inline comment in given string, - or pointer to null at end of string if neither found. Inline comment must - be prefixed by a whitespace character to register as a comment. */ -static char* find_chars_or_comment(const char* s, const char* chars) -{ -#if INI_ALLOW_INLINE_COMMENTS - int was_space = 0; - while (*s && (!chars || !strchr(chars, *s)) && - !(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) { - was_space = isspace((unsigned char)(*s)); - s++; - } -#else - while (*s && (!chars || !strchr(chars, *s))) { - s++; - } -#endif - return (char*)s; -} - -/* Version of strncpy that ensures dest (size bytes) is null-terminated. */ -static char* strncpy0(char* dest, const char* src, size_t size) -{ - strncpy(dest, src, size-1); - dest[size - 1] = '\0'; - return dest; -} - -/* See documentation in header file. */ -int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler, - void* user) -{ - /* Uses a fair bit of stack (use heap instead if you need to) */ -#if INI_USE_STACK - char line[INI_MAX_LINE]; -#else - char* line; -#endif - char section[MAX_SECTION] = ""; - char prev_name[MAX_NAME] = ""; - - char* start; - char* end; - char* name; - char* value; - int lineno = 0; - int error = 0; - -#if !INI_USE_STACK - line = (char*)malloc(INI_MAX_LINE); - if (!line) { - return -2; - } -#endif - - /* Scan through stream line by line */ - while (reader(line, INI_MAX_LINE, stream) != NULL) { - lineno++; - - start = line; -#if INI_ALLOW_BOM - if (lineno == 1 && (unsigned char)start[0] == 0xEF && - (unsigned char)start[1] == 0xBB && - (unsigned char)start[2] == 0xBF) { - start += 3; - } -#endif - start = lskip(rstrip(start)); - - if (*start == ';' || *start == '#') { - /* Per Python configparser, allow both ; and # comments at the - start of a line */ - } -#if INI_ALLOW_MULTILINE - else if (*prev_name && *start && start > line) { - /* Non-blank line with leading whitespace, treat as continuation - of previous name's value (as per Python configparser). */ - if (!handler(user, section, prev_name, start) && !error) - error = lineno; - } -#endif - else if (*start == '[') { - /* A "[section]" line */ - end = find_chars_or_comment(start + 1, "]"); - if (*end == ']') { - *end = '\0'; - strncpy0(section, start + 1, sizeof(section)); - *prev_name = '\0'; - } - else if (!error) { - /* No ']' found on section line */ - error = lineno; - } - } - else if (*start) { - /* Not a comment, must be a name[=:]value pair */ - end = find_chars_or_comment(start, "=:"); - if (*end == '=' || *end == ':') { - *end = '\0'; - name = rstrip(start); - value = lskip(end + 1); -#if INI_ALLOW_INLINE_COMMENTS - end = find_chars_or_comment(value, NULL); - if (*end) - *end = '\0'; -#endif - rstrip(value); - - /* Valid name[=:]value pair found, call handler */ - strncpy0(prev_name, name, sizeof(prev_name)); - if (!handler(user, section, name, value) && !error) - error = lineno; - memset(value, 0, strlen(value)); - } - else if (!error) { - /* No '=' or ':' found on name[=:]value line */ - error = lineno; - } - } - -#if INI_STOP_ON_FIRST_ERROR - if (error) - break; -#endif - } - -#if !INI_USE_STACK - free(line); -#endif - - return error; -} - -/* See documentation in header file. */ -int ini_parse_file(FILE* file, ini_handler handler, void* user) -{ - return ini_parse_stream((ini_reader)fgets, file, handler, user); -} - -/* See documentation in header file. */ -int ini_parse(const char* filename, ini_handler handler, void* user) -{ - FILE* file; - int error; - - file = fopen(filename, "r"); - if (!file) - return -1; - error = ini_parse_file(file, handler, user); - fclose(file); - return error; -} diff --git a/rootston/input.c b/rootston/input.c deleted file mode 100644 index d5e04d3d..00000000 --- a/rootston/input.c +++ /dev/null @@ -1,146 +0,0 @@ -#define _POSIX_C_SOURCE 200112L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if WLR_HAS_XWAYLAND -#include -#endif -#include "rootston/config.h" -#include "rootston/input.h" -#include "rootston/keyboard.h" -#include "rootston/seat.h" -#include "rootston/server.h" - -static const char *device_type(enum wlr_input_device_type type) { - switch (type) { - case WLR_INPUT_DEVICE_KEYBOARD: - return "keyboard"; - case WLR_INPUT_DEVICE_POINTER: - return "pointer"; - case WLR_INPUT_DEVICE_SWITCH: - return "switch"; - case WLR_INPUT_DEVICE_TOUCH: - return "touch"; - case WLR_INPUT_DEVICE_TABLET_TOOL: - return "tablet tool"; - case WLR_INPUT_DEVICE_TABLET_PAD: - return "tablet pad"; - } - return NULL; -} - -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 handle_new_input(struct wl_listener *listener, void *data) { - struct wlr_input_device *device = data; - struct roots_input *input = wl_container_of(listener, input, new_input); - - char *seat_name = ROOTS_CONFIG_DEFAULT_SEAT_NAME; - 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(WLR_ERROR, "could not create roots seat"); - return; - } - - wlr_log(WLR_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); - - if (dc && wlr_input_device_is_libinput(device)) { - struct libinput_device *libinput_dev = - wlr_libinput_get_device_handle(device); - - wlr_log(WLR_DEBUG, "input has config, tap_enabled: %d\n", dc->tap_enabled); - if (dc->tap_enabled) { - libinput_device_config_tap_set_enabled(libinput_dev, - LIBINPUT_CONFIG_TAP_ENABLED); - } - } -} - -struct roots_input *input_create(struct roots_server *server, - struct roots_config *config) { - wlr_log(WLR_DEBUG, "Initializing roots input"); - assert(server->desktop); - - struct roots_input *input = calloc(1, sizeof(struct roots_input)); - if (input == NULL) { - return NULL; - } - - input->config = config; - input->server = server; - - wl_list_init(&input->seats); - - input->new_input.notify = handle_new_input; - wl_signal_add(&server->backend->events.new_input, &input->new_input); - - 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 (view == roots_seat_get_focus(seat)) { - return true; - } - } - - return false; -} - -static inline int64_t timespec_to_msec(const struct timespec *a) { - return (int64_t)a->tv_sec * 1000 + a->tv_nsec / 1000000; -} - -void input_update_cursor_focus(struct roots_input *input) { - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - struct roots_seat *seat; - wl_list_for_each(seat, &input->seats, link) { - roots_cursor_update_position(seat->cursor, timespec_to_msec(&now)); - } -} diff --git a/rootston/keyboard.c b/rootston/keyboard.c deleted file mode 100644 index da88e914..00000000 --- a/rootston/keyboard.c +++ /dev/null @@ -1,349 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/bindings.h" -#include "rootston/input.h" -#include "rootston/keyboard.h" -#include "rootston/seat.h" - -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 (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 void keyboard_binding_execute(struct roots_keyboard *keyboard, - const char *command) { - execute_binding_command(keyboard->seat, keyboard->input, command); -} - -/** - * 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_execute_compositor_binding(struct roots_keyboard *keyboard, - xkb_keysym_t keysym) { - if (keysym >= XKB_KEY_XF86Switch_VT_1 && - keysym <= XKB_KEY_XF86Switch_VT_12) { - struct roots_server *server = keyboard->input->server; - - struct wlr_session *session = wlr_backend_get_session(server->backend); - if (session) { - unsigned vt = keysym - XKB_KEY_XF86Switch_VT_1 + 1; - wlr_session_change_vt(session, vt); - } - - return true; - } - - if (keysym == XKB_KEY_Escape) { - wlr_seat_pointer_end_grab(keyboard->seat->seat); - wlr_seat_keyboard_end_grab(keyboard->seat->seat); - roots_seat_end_compositor_grab(keyboard->seat); - } - - 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 roots_binding_config *bc; - wl_list_for_each(bc, bindings, link) { - 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 = pressed_keysyms_index(pressed_keysyms, bc->keysyms[i]); - if (j < 0) { - ok = false; - break; - } - } - - if (ok) { - keyboard_binding_execute(keyboard, bc->command); - return true; - } - } - - return false; -} - -/* - * 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); -} - -/* - * 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); - - 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; - 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->seat->seat, keyboard->device); - wlr_seat_keyboard_notify_key(keyboard->seat->seat, event->time_msec, - event->keycode, event->state); - } -} - -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, - &r_keyboard->device->keyboard->modifiers); -} - -static void keyboard_config_merge(struct roots_keyboard_config *config, - struct roots_keyboard_config *fallback) { - if (fallback == NULL) { - return; - } - if (config->rules == NULL) { - config->rules = fallback->rules; - } - if (config->model == NULL) { - config->model = fallback->model; - } - if (config->layout == NULL) { - config->layout = fallback->layout; - } - if (config->variant == NULL) { - config->variant = fallback->variant; - } - 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; - } - if (config->repeat_rate <= 0) { - config->repeat_rate = fallback->repeat_rate; - } - if (config->repeat_delay <= 0) { - config->repeat_delay = fallback->repeat_delay; - } -} - -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 NULL; - } - device->data = keyboard; - keyboard->device = device; - keyboard->input = input; - - 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)); - - 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 = config; - - struct xkb_rule_names rules = { 0 }; - 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(WLR_ERROR, "Cannot create XKB context"); - return NULL; - } - - struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, - XKB_KEYMAP_COMPILE_NO_FLAGS); - if (keymap == NULL) { - xkb_context_unref(context); - wlr_log(WLR_ERROR, "Cannot create XKB keymap"); - return NULL; - } - - wlr_keyboard_set_keymap(device->keyboard, keymap); - xkb_keymap_unref(keymap); - xkb_context_unref(context); - - int repeat_rate = (config->repeat_rate > 0) ? config->repeat_rate : 25; - int repeat_delay = (config->repeat_delay > 0) ? config->repeat_delay : 600; - wlr_keyboard_set_repeat_info(device->keyboard, repeat_rate, repeat_delay); - - return keyboard; -} - -void roots_keyboard_destroy(struct roots_keyboard *keyboard) { - wl_list_remove(&keyboard->link); - free(keyboard->config); - free(keyboard); -} diff --git a/rootston/layer_shell.c b/rootston/layer_shell.c deleted file mode 100644 index 278046a3..00000000 --- a/rootston/layer_shell.c +++ /dev/null @@ -1,506 +0,0 @@ -#ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200112L -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/desktop.h" -#include "rootston/layers.h" -#include "rootston/output.h" -#include "rootston/server.h" - -static void apply_exclusive(struct wlr_box *usable_area, - uint32_t anchor, int32_t exclusive, - int32_t margin_top, int32_t margin_right, - int32_t margin_bottom, int32_t margin_left) { - if (exclusive <= 0) { - return; - } - struct { - uint32_t anchors; - int *positive_axis; - int *negative_axis; - int margin; - } edges[] = { - { - .anchors = - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, - .positive_axis = &usable_area->y, - .negative_axis = &usable_area->height, - .margin = margin_top, - }, - { - .anchors = - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = NULL, - .negative_axis = &usable_area->height, - .margin = margin_bottom, - }, - { - .anchors = - ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = &usable_area->x, - .negative_axis = &usable_area->width, - .margin = margin_left, - }, - { - .anchors = - ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | - ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | - ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, - .positive_axis = NULL, - .negative_axis = &usable_area->width, - .margin = margin_right, - }, - }; - for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) { - if ((anchor & edges[i].anchors) == edges[i].anchors) { - if (edges[i].positive_axis) { - *edges[i].positive_axis += exclusive + edges[i].margin; - } - if (edges[i].negative_axis) { - *edges[i].negative_axis -= exclusive + edges[i].margin; - } - } - } -} - -static void update_cursors(struct roots_layer_surface *roots_surface, - struct wl_list *seats /* struct roots_seat */) { - struct roots_seat *seat; - wl_list_for_each(seat, seats, link) { - double sx, sy; - - struct wlr_surface *surface = desktop_surface_at( - seat->input->server->desktop, - seat->cursor->cursor->x, seat->cursor->cursor->y, &sx, &sy, NULL); - - if (surface == roots_surface->layer_surface->surface) { - struct timespec time; - if (clock_gettime(CLOCK_MONOTONIC, &time) == 0) { - roots_cursor_update_position(seat->cursor, - time.tv_sec * 1000 + time.tv_nsec / 1000000); - } else { - wlr_log(WLR_ERROR, "Failed to get time, not updating" - "position. Errno: %s\n", strerror(errno)); - } - } - } -} - -static void arrange_layer(struct wlr_output *output, - struct wl_list *seats /* struct *roots_seat */, - struct wl_list *list /* struct *roots_layer_surface */, - struct wlr_box *usable_area, bool exclusive) { - struct roots_layer_surface *roots_surface; - struct wlr_box full_area = { 0 }; - wlr_output_effective_resolution(output, - &full_area.width, &full_area.height); - wl_list_for_each_reverse(roots_surface, list, link) { - struct wlr_layer_surface_v1 *layer = roots_surface->layer_surface; - struct wlr_layer_surface_v1_state *state = &layer->current; - if (exclusive != (state->exclusive_zone > 0)) { - continue; - } - struct wlr_box bounds; - if (state->exclusive_zone == -1) { - bounds = full_area; - } else { - bounds = *usable_area; - } - struct wlr_box box = { - .width = state->desired_width, - .height = state->desired_height - }; - // Horizontal axis - const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT - | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - if ((state->anchor & both_horiz) && box.width == 0) { - box.x = bounds.x; - box.width = bounds.width; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { - box.x = bounds.x; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { - box.x = bounds.x + (bounds.width - box.width); - } else { - box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); - } - // Vertical axis - const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP - | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - if ((state->anchor & both_vert) && box.height == 0) { - box.y = bounds.y; - box.height = bounds.height; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { - box.y = bounds.y; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { - box.y = bounds.y + (bounds.height - box.height); - } else { - box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); - } - // Margin - if ((state->anchor & both_horiz) == both_horiz) { - box.x += state->margin.left; - box.width -= state->margin.left + state->margin.right; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { - box.x += state->margin.left; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { - box.x -= state->margin.right; - } - if ((state->anchor & both_vert) == both_vert) { - box.y += state->margin.top; - box.height -= state->margin.top + state->margin.bottom; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { - box.y += state->margin.top; - } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { - box.y -= state->margin.bottom; - } - if (box.width < 0 || box.height < 0) { - // TODO: Bubble up a protocol error? - wlr_layer_surface_v1_close(layer); - continue; - } - - // Apply - struct wlr_box old_geo = roots_surface->geo; - roots_surface->geo = box; - apply_exclusive(usable_area, state->anchor, state->exclusive_zone, - state->margin.top, state->margin.right, - state->margin.bottom, state->margin.left); - wlr_layer_surface_v1_configure(layer, box.width, box.height); - - // Having a cursor newly end up over the moved layer will not - // automatically send a motion event to the surface. The event needs to - // be synthesized. - // Only update layer surfaces which kept their size (and so buffers) the - // same, because those with resized buffers will be handled separately. - - if (roots_surface->geo.x != old_geo.x - || roots_surface->geo.y != old_geo.y) { - update_cursors(roots_surface, seats); - } - } -} - -void arrange_layers(struct roots_output *output) { - struct wlr_box usable_area = { 0 }; - wlr_output_effective_resolution(output->wlr_output, - &usable_area.width, &usable_area.height); - - // Arrange exclusive surfaces from top->bottom - arrange_layer(output->wlr_output, &output->desktop->server->input->seats, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &usable_area, true); - arrange_layer(output->wlr_output, &output->desktop->server->input->seats, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &usable_area, true); - arrange_layer(output->wlr_output, &output->desktop->server->input->seats, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - &usable_area, true); - arrange_layer(output->wlr_output, &output->desktop->server->input->seats, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - &usable_area, true); - memcpy(&output->usable_area, &usable_area, sizeof(struct wlr_box)); - - struct roots_view *view; - wl_list_for_each(view, &output->desktop->views, link) { - if (view->maximized) { - view_arrange_maximized(view); - } - } - - // Arrange non-exlusive surfaces from top->bottom - arrange_layer(output->wlr_output, &output->desktop->server->input->seats, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], - &usable_area, false); - arrange_layer(output->wlr_output, &output->desktop->server->input->seats, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], - &usable_area, false); - arrange_layer(output->wlr_output, &output->desktop->server->input->seats, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], - &usable_area, false); - arrange_layer(output->wlr_output, &output->desktop->server->input->seats, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], - &usable_area, false); - - // Find topmost keyboard interactive layer, if such a layer exists - uint32_t layers_above_shell[] = { - ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, - ZWLR_LAYER_SHELL_V1_LAYER_TOP, - }; - size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]); - struct roots_layer_surface *layer, *topmost = NULL; - for (size_t i = 0; i < nlayers; ++i) { - wl_list_for_each_reverse(layer, - &output->layers[layers_above_shell[i]], link) { - if (layer->layer_surface->current.keyboard_interactive) { - topmost = layer; - break; - } - } - if (topmost != NULL) { - break; - } - } - - struct roots_input *input = output->desktop->server->input; - struct roots_seat *seat; - wl_list_for_each(seat, &input->seats, link) { - roots_seat_set_focus_layer(seat, - topmost ? topmost->layer_surface : NULL); - } -} - -static void handle_output_destroy(struct wl_listener *listener, void *data) { - struct roots_layer_surface *layer = - wl_container_of(listener, layer, output_destroy); - layer->layer_surface->output = NULL; - wl_list_remove(&layer->output_destroy.link); - wlr_layer_surface_v1_close(layer->layer_surface); -} - -static void handle_surface_commit(struct wl_listener *listener, void *data) { - struct roots_layer_surface *layer = - wl_container_of(listener, layer, surface_commit); - struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; - struct wlr_output *wlr_output = layer_surface->output; - if (wlr_output != NULL) { - struct roots_output *output = wlr_output->data; - struct wlr_box old_geo = layer->geo; - arrange_layers(output); - - // Cursor changes which happen as a consequence of resizing a layer - // surface are applied in arrange_layers. Because the resize happens - // before the underlying surface changes, it will only receive a cursor - // update if the new cursor position crosses the *old* sized surface in - // the *new* layer surface. - // Another cursor move event is needed when the surface actually - // changes. - struct wlr_surface *surface = layer_surface->surface; - if (surface->previous.width != surface->current.width || - surface->previous.height != surface->current.height) { - update_cursors(layer, &output->desktop->server->input->seats); - } - - if (memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0) { - output_damage_whole_local_surface(output, layer_surface->surface, - old_geo.x, old_geo.y); - output_damage_whole_local_surface(output, layer_surface->surface, - layer->geo.x, layer->geo.y); - } else { - output_damage_from_local_surface(output, layer_surface->surface, - layer->geo.x, layer->geo.y); - } - } -} - -static void unmap(struct wlr_layer_surface_v1 *layer_surface) { - struct roots_layer_surface *layer = layer_surface->data; - struct wlr_output *wlr_output = layer_surface->output; - if (wlr_output != NULL) { - struct roots_output *output = wlr_output->data; - output_damage_whole_local_surface(output, layer_surface->surface, - layer->geo.x, layer->geo.y); - } -} - -static void handle_destroy(struct wl_listener *listener, void *data) { - struct roots_layer_surface *layer = wl_container_of( - listener, layer, destroy); - if (layer->layer_surface->mapped) { - unmap(layer->layer_surface); - } - wl_list_remove(&layer->link); - wl_list_remove(&layer->destroy.link); - wl_list_remove(&layer->map.link); - wl_list_remove(&layer->unmap.link); - wl_list_remove(&layer->surface_commit.link); - if (layer->layer_surface->output) { - wl_list_remove(&layer->output_destroy.link); - arrange_layers((struct roots_output *)layer->layer_surface->output->data); - } - free(layer); -} - -static void handle_map(struct wl_listener *listener, void *data) { - struct wlr_layer_surface_v1 *layer_surface = data; - struct roots_layer_surface *layer = layer_surface->data; - struct wlr_output *wlr_output = layer_surface->output; - struct roots_output *output = wlr_output->data; - output_damage_whole_local_surface(output, layer_surface->surface, - layer->geo.x, layer->geo.y); - wlr_surface_send_enter(layer_surface->surface, wlr_output); -} - -static void handle_unmap(struct wl_listener *listener, void *data) { - struct roots_layer_surface *layer = wl_container_of( - listener, layer, unmap); - struct wlr_output *wlr_output = layer->layer_surface->output; - struct roots_output *output = wlr_output->data; - unmap(layer->layer_surface); - input_update_cursor_focus(output->desktop->server->input); -} - -static void popup_handle_map(struct wl_listener *listener, void *data) { - struct roots_layer_popup *popup = wl_container_of(listener, popup, map); - struct roots_layer_surface *layer = popup->parent; - struct wlr_output *wlr_output = layer->layer_surface->output; - struct roots_output *output = wlr_output->data; - int ox = popup->wlr_popup->geometry.x + layer->geo.x; - int oy = popup->wlr_popup->geometry.y + layer->geo.y; - output_damage_whole_local_surface(output, popup->wlr_popup->base->surface, - ox, oy); - input_update_cursor_focus(output->desktop->server->input); -} - -static void popup_handle_unmap(struct wl_listener *listener, void *data) { - struct roots_layer_popup *popup = wl_container_of(listener, popup, unmap); - struct roots_layer_surface *layer = popup->parent; - struct wlr_output *wlr_output = layer->layer_surface->output; - struct roots_output *output = wlr_output->data; - int ox = popup->wlr_popup->geometry.x + layer->geo.x; - int oy = popup->wlr_popup->geometry.y + layer->geo.y; - output_damage_whole_local_surface(output, popup->wlr_popup->base->surface, - ox, oy); -} - -static void popup_handle_commit(struct wl_listener *listener, void *data) { - struct roots_layer_popup *popup = wl_container_of(listener, popup, commit); - struct roots_layer_surface *layer = popup->parent; - struct wlr_output *wlr_output = layer->layer_surface->output; - struct roots_output *output = wlr_output->data; - int ox = popup->wlr_popup->geometry.x + layer->geo.x; - int oy = popup->wlr_popup->geometry.y + layer->geo.y; - output_damage_from_local_surface(output, popup->wlr_popup->base->surface, - ox, oy); -} - -static void popup_handle_destroy(struct wl_listener *listener, void *data) { - struct roots_layer_popup *popup = - wl_container_of(listener, popup, destroy); - - wl_list_remove(&popup->map.link); - wl_list_remove(&popup->unmap.link); - wl_list_remove(&popup->destroy.link); - wl_list_remove(&popup->commit.link); - free(popup); -} - -static struct roots_layer_popup *popup_create(struct roots_layer_surface *parent, - struct wlr_xdg_popup *wlr_popup) { - struct roots_layer_popup *popup = - calloc(1, sizeof(struct roots_layer_popup)); - if (popup == NULL) { - return NULL; - } - popup->wlr_popup = wlr_popup; - popup->parent = parent; - popup->map.notify = popup_handle_map; - wl_signal_add(&wlr_popup->base->events.map, &popup->map); - popup->unmap.notify = popup_handle_unmap; - wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap); - popup->destroy.notify = popup_handle_destroy; - wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); - popup->commit.notify = popup_handle_commit; - wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); - /* TODO: popups can have popups, see xdg_shell::popup_create */ - - return popup; -} - -static void handle_new_popup(struct wl_listener *listener, void *data) { - struct roots_layer_surface *roots_layer_surface = - wl_container_of(listener, roots_layer_surface, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - popup_create(roots_layer_surface, wlr_popup); -} - -void handle_layer_shell_surface(struct wl_listener *listener, void *data) { - struct wlr_layer_surface_v1 *layer_surface = data; - struct roots_desktop *desktop = - wl_container_of(listener, desktop, layer_shell_surface); - wlr_log(WLR_DEBUG, "new layer surface: namespace %s layer %d anchor %d " - "size %dx%d margin %d,%d,%d,%d", - layer_surface->namespace, layer_surface->layer, layer_surface->layer, - layer_surface->client_pending.desired_width, - layer_surface->client_pending.desired_height, - layer_surface->client_pending.margin.top, - layer_surface->client_pending.margin.right, - layer_surface->client_pending.margin.bottom, - layer_surface->client_pending.margin.left); - - if (!layer_surface->output) { - struct roots_input *input = desktop->server->input; - struct roots_seat *seat = input_last_active_seat(input); - assert(seat); // Technically speaking we should handle this case - struct wlr_output *output = - wlr_output_layout_output_at(desktop->layout, - seat->cursor->cursor->x, - seat->cursor->cursor->y); - if (!output) { - wlr_log(WLR_ERROR, "Couldn't find output at (%.0f,%.0f)", - seat->cursor->cursor->x, - seat->cursor->cursor->y); - output = wlr_output_layout_get_center_output(desktop->layout); - } - if (output) { - layer_surface->output = output; - } else { - wlr_layer_surface_v1_close(layer_surface); - return; - } - } - - struct roots_layer_surface *roots_surface = - calloc(1, sizeof(struct roots_layer_surface)); - if (!roots_surface) { - return; - } - - roots_surface->surface_commit.notify = handle_surface_commit; - wl_signal_add(&layer_surface->surface->events.commit, - &roots_surface->surface_commit); - - roots_surface->output_destroy.notify = handle_output_destroy; - wl_signal_add(&layer_surface->output->events.destroy, - &roots_surface->output_destroy); - - roots_surface->destroy.notify = handle_destroy; - wl_signal_add(&layer_surface->events.destroy, &roots_surface->destroy); - roots_surface->map.notify = handle_map; - wl_signal_add(&layer_surface->events.map, &roots_surface->map); - roots_surface->unmap.notify = handle_unmap; - wl_signal_add(&layer_surface->events.unmap, &roots_surface->unmap); - roots_surface->new_popup.notify = handle_new_popup; - wl_signal_add(&layer_surface->events.new_popup, &roots_surface->new_popup); - // TODO: Listen for subsurfaces - - roots_surface->layer_surface = layer_surface; - layer_surface->data = roots_surface; - - struct roots_output *output = layer_surface->output->data; - wl_list_insert(&output->layers[layer_surface->layer], &roots_surface->link); - - // Temporarily set the layer's current state to client_pending - // So that we can easily arrange it - struct wlr_layer_surface_v1_state old_state = layer_surface->current; - layer_surface->current = layer_surface->client_pending; - - arrange_layers(output); - - layer_surface->current = old_state; -} diff --git a/rootston/main.c b/rootston/main.c deleted file mode 100644 index 350906e3..00000000 --- a/rootston/main.c +++ /dev/null @@ -1,83 +0,0 @@ -#define _POSIX_C_SOURCE 200112L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/config.h" -#include "rootston/server.h" - -struct roots_server server = { 0 }; - -int main(int argc, char **argv) { - wlr_log_init(WLR_DEBUG, NULL); - server.config = roots_config_create_from_args(argc, argv); - server.wl_display = wl_display_create(); - server.wl_event_loop = wl_display_get_event_loop(server.wl_display); - assert(server.config && server.wl_display && server.wl_event_loop); - - server.backend = wlr_backend_autocreate(server.wl_display, NULL); - if (server.backend == NULL) { - wlr_log(WLR_ERROR, "could not start backend"); - return 1; - } - - server.renderer = wlr_backend_get_renderer(server.backend); - assert(server.renderer); - server.data_device_manager = - wlr_data_device_manager_create(server.wl_display); - wlr_renderer_init_wl_display(server.renderer, server.wl_display); - server.desktop = desktop_create(&server, server.config); - server.input = input_create(&server, server.config); - - const char *socket = wl_display_add_socket_auto(server.wl_display); - if (!socket) { - wlr_log_errno(WLR_ERROR, "Unable to open wayland socket"); - wlr_backend_destroy(server.backend); - return 1; - } - - wlr_log(WLR_INFO, "Running compositor on wayland display '%s'", socket); - setenv("_WAYLAND_DISPLAY", socket, true); - - if (!wlr_backend_start(server.backend)) { - wlr_log(WLR_ERROR, "Failed to start backend"); - wlr_backend_destroy(server.backend); - wl_display_destroy(server.wl_display); - return 1; - } - - setenv("WAYLAND_DISPLAY", socket, true); -#if WLR_HAS_XWAYLAND - if (server.desktop->xwayland != NULL) { - struct roots_seat *xwayland_seat = - input_get_seat(server.input, ROOTS_CONFIG_DEFAULT_SEAT_NAME); - wlr_xwayland_set_seat(server.desktop->xwayland, xwayland_seat->seat); - } -#endif - - if (server.config->startup_cmd != NULL) { - const char *cmd = server.config->startup_cmd; - pid_t pid = fork(); - if (pid < 0) { - wlr_log(WLR_ERROR, "cannot execute binding command: fork() failed"); - } else if (pid == 0) { - execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL); - } - } - - wl_display_run(server.wl_display); -#if WLR_HAS_XWAYLAND - // We need to shutdown Xwayland before disconnecting all clients, otherwise - // wlroots will restart it automatically. - wlr_xwayland_destroy(server.desktop->xwayland); -#endif - wl_display_destroy_clients(server.wl_display); - wl_display_destroy(server.wl_display); - return 0; -} diff --git a/rootston/meson.build b/rootston/meson.build deleted file mode 100644 index 853fecc8..00000000 --- a/rootston/meson.build +++ /dev/null @@ -1,31 +0,0 @@ -sources = [ - 'bindings.c', - 'config.c', - 'cursor.c', - 'desktop.c', - 'ini.c', - 'input.c', - 'keyboard.c', - 'layer_shell.c', - 'main.c', - 'output.c', - 'render.c', - 'seat.c', - 'switch.c', - 'text_input.c', - 'view.c', - 'virtual_keyboard.c', - 'xdg_shell_v6.c', - 'xdg_shell.c', -] - -if conf_data.get('WLR_HAS_XWAYLAND', 0) == 1 - sources += 'xwayland.c' -endif - -executable( - 'rootston', - sources, - dependencies: [wlroots, wlr_protos, pixman], - build_by_default: get_option('rootston'), -) diff --git a/rootston/output.c b/rootston/output.c deleted file mode 100644 index 66a43694..00000000 --- a/rootston/output.c +++ /dev/null @@ -1,688 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/config.h" -#include "rootston/layers.h" -#include "rootston/output.h" -#include "rootston/server.h" - -/** - * 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). - */ -void rotate_child_position(double *sx, double *sy, double sw, double sh, - double pw, double ph, float rotation) { - if (rotation == 0.0) { - return; - } - - // Coordinates relative to the center of the subsurface - double cx = *sx - pw/2 + sw/2, - cy = *sy - ph/2 + sh/2; - // Rotated coordinates - double rx = cos(rotation)*cx - sin(rotation)*cy, - ry = cos(rotation)*cy + sin(rotation)*cx; - *sx = rx + pw/2 - sw/2; - *sy = ry + ph/2 - sh/2; -} - -struct surface_iterator_data { - roots_surface_iterator_func_t user_iterator; - void *user_data; - - struct roots_output *output; - double ox, oy; - int width, height; - float rotation; -}; - -static bool get_surface_box(struct surface_iterator_data *data, - struct wlr_surface *surface, int sx, int sy, - struct wlr_box *surface_box) { - struct roots_output *output = data->output; - - if (!wlr_surface_has_buffer(surface)) { - return false; - } - - int sw = surface->current.width; - int sh = surface->current.height; - - double _sx = sx + surface->sx; - double _sy = sy + surface->sy; - rotate_child_position(&_sx, &_sy, sw, sh, data->width, data->height, - data->rotation); - - struct wlr_box box = { - .x = data->ox + _sx, - .y = data->oy + _sy, - .width = sw, - .height = sh, - }; - if (surface_box != NULL) { - *surface_box = box; - } - - struct wlr_box rotated_box; - wlr_box_rotated_bounds(&rotated_box, &box, data->rotation); - - struct wlr_box output_box = {0}; - wlr_output_effective_resolution(output->wlr_output, - &output_box.width, &output_box.height); - - struct wlr_box intersection; - return wlr_box_intersection(&intersection, &output_box, &rotated_box); -} - -static void output_for_each_surface_iterator(struct wlr_surface *surface, - int sx, int sy, void *_data) { - struct surface_iterator_data *data = _data; - - struct wlr_box box; - bool intersects = get_surface_box(data, surface, sx, sy, &box); - if (!intersects) { - return; - } - - data->user_iterator(data->output, surface, &box, data->rotation, - data->user_data); -} - -void output_surface_for_each_surface(struct roots_output *output, - struct wlr_surface *surface, double ox, double oy, - roots_surface_iterator_func_t iterator, void *user_data) { - struct surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .output = output, - .ox = ox, - .oy = oy, - .width = surface->current.width, - .height = surface->current.height, - .rotation = 0, - }; - - wlr_surface_for_each_surface(surface, - output_for_each_surface_iterator, &data); -} - -void output_view_for_each_surface(struct roots_output *output, - struct roots_view *view, roots_surface_iterator_func_t iterator, - void *user_data) { - struct wlr_box *output_box = - wlr_output_layout_get_box(output->desktop->layout, output->wlr_output); - if (!output_box) { - return; - } - - struct surface_iterator_data data = { - .user_iterator = iterator, - .user_data = user_data, - .output = output, - .ox = view->box.x - output_box->x, - .oy = view->box.y - output_box->y, - .width = view->box.width, - .height = view->box.height, - .rotation = view->rotation, - }; - - view_for_each_surface(view, output_for_each_surface_iterator, &data); -} - -#if WLR_HAS_XWAYLAND -void output_xwayland_children_for_each_surface( - struct roots_output *output, struct wlr_xwayland_surface *surface, - roots_surface_iterator_func_t iterator, void *user_data) { - struct wlr_box *output_box = - wlr_output_layout_get_box(output->desktop->layout, output->wlr_output); - if (!output_box) { - return; - } - - struct wlr_xwayland_surface *child; - wl_list_for_each(child, &surface->children, parent_link) { - if (child->mapped) { - double ox = child->x - output_box->x; - double oy = child->y - output_box->y; - output_surface_for_each_surface(output, child->surface, - ox, oy, iterator, user_data); - } - output_xwayland_children_for_each_surface(output, child, - iterator, user_data); - } -} -#endif - -void output_layer_for_each_surface(struct roots_output *output, - struct wl_list *layer_surfaces, roots_surface_iterator_func_t iterator, - void *user_data) { - struct roots_layer_surface *layer_surface; - wl_list_for_each(layer_surface, layer_surfaces, link) { - struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = - layer_surface->layer_surface; - output_surface_for_each_surface(output, wlr_layer_surface_v1->surface, - layer_surface->geo.x, layer_surface->geo.y, iterator, - user_data); - - struct wlr_xdg_popup *state; - wl_list_for_each(state, &wlr_layer_surface_v1->popups, link) { - struct wlr_xdg_surface *popup = state->base; - if (!popup->configured) { - continue; - } - - double popup_sx, popup_sy; - popup_sx = layer_surface->geo.x; - popup_sx += popup->popup->geometry.x - popup->geometry.x; - popup_sy = layer_surface->geo.y; - popup_sy += popup->popup->geometry.y - popup->geometry.y; - - output_surface_for_each_surface(output, popup->surface, - popup_sx, popup_sy, iterator, user_data); - } - } -} - -void output_drag_icons_for_each_surface(struct roots_output *output, - struct roots_input *input, roots_surface_iterator_func_t iterator, - void *user_data) { - struct wlr_box *output_box = - wlr_output_layout_get_box(output->desktop->layout, output->wlr_output); - if (!output_box) { - return; - } - - struct roots_seat *seat; - wl_list_for_each(seat, &input->seats, link) { - struct roots_drag_icon *drag_icon = seat->drag_icon; - if (!drag_icon || !drag_icon->wlr_drag_icon->mapped) { - continue; - } - - double ox = drag_icon->x - output_box->x; - double oy = drag_icon->y - output_box->y; - output_surface_for_each_surface(output, - drag_icon->wlr_drag_icon->surface, ox, oy, iterator, user_data); - } -} - -void output_for_each_surface(struct roots_output *output, - roots_surface_iterator_func_t iterator, void *user_data) { - struct roots_desktop *desktop = output->desktop; - - if (output->fullscreen_view != NULL) { - struct roots_view *view = output->fullscreen_view; - - output_view_for_each_surface(output, view, iterator, user_data); - -#if WLR_HAS_XWAYLAND - if (view->type == ROOTS_XWAYLAND_VIEW) { - struct roots_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view); - output_xwayland_children_for_each_surface(output, - xwayland_surface->xwayland_surface, iterator, user_data); - } -#endif - } else { - struct roots_view *view; - wl_list_for_each_reverse(view, &desktop->views, link) { - output_view_for_each_surface(output, view, iterator, user_data); - } - } - - output_drag_icons_for_each_surface(output, desktop->server->input, - iterator, user_data); - - size_t len = sizeof(output->layers) / sizeof(output->layers[0]); - for (size_t i = 0; i < len; ++i) { - output_layer_for_each_surface(output, &output->layers[i], - iterator, user_data); - } -} - -static int scale_length(int length, int offset, float scale) { - return round((offset + length) * scale) - round(offset * scale); -} - -void scale_box(struct wlr_box *box, float scale) { - box->width = scale_length(box->width, box->x, scale); - box->height = scale_length(box->height, box->y, scale); - box->x = round(box->x * scale); - box->y = round(box->y * scale); -} - -void get_decoration_box(struct roots_view *view, - struct roots_output *output, struct wlr_box *box) { - struct wlr_output *wlr_output = output->wlr_output; - - struct wlr_box deco_box; - view_get_deco_box(view, &deco_box); - double sx = deco_box.x - view->box.x; - double sy = deco_box.y - view->box.y; - rotate_child_position(&sx, &sy, deco_box.width, deco_box.height, - view->wlr_surface->current.width, - view->wlr_surface->current.height, view->rotation); - double x = sx + view->box.x; - double y = sy + view->box.y; - - wlr_output_layout_output_coords(output->desktop->layout, wlr_output, &x, &y); - - box->x = x * wlr_output->scale; - box->y = y * wlr_output->scale; - box->width = deco_box.width * wlr_output->scale; - box->height = deco_box.height * wlr_output->scale; -} - -void output_damage_whole(struct roots_output *output) { - wlr_output_damage_add_whole(output->damage); -} - -static bool view_accept_damage(struct roots_output *output, - struct roots_view *view) { - if (view->wlr_surface == NULL) { - return false; - } - if (output->fullscreen_view == NULL) { - return true; - } - if (output->fullscreen_view == view) { - return true; - } -#if WLR_HAS_XWAYLAND - if (output->fullscreen_view->type == ROOTS_XWAYLAND_VIEW && - view->type == ROOTS_XWAYLAND_VIEW) { - // Special case: accept damage from children - struct wlr_xwayland_surface *xsurface = - roots_xwayland_surface_from_view(view)->xwayland_surface; - struct wlr_xwayland_surface *fullscreen_xsurface = - roots_xwayland_surface_from_view(output->fullscreen_view)->xwayland_surface; - while (xsurface != NULL) { - if (fullscreen_xsurface == xsurface) { - return true; - } - xsurface = xsurface->parent; - } - } -#endif - return false; -} - -static void damage_surface_iterator(struct roots_output *output, - struct wlr_surface *surface, struct wlr_box *_box, float rotation, - void *data) { - bool *whole = data; - - struct wlr_box box = *_box; - scale_box(&box, output->wlr_output->scale); - - int center_x = box.x + box.width/2; - int center_y = box.y + box.height/2; - - if (pixman_region32_not_empty(&surface->buffer_damage)) { - pixman_region32_t damage; - pixman_region32_init(&damage); - wlr_surface_get_effective_damage(surface, &damage); - wlr_region_scale(&damage, &damage, output->wlr_output->scale); - if (ceil(output->wlr_output->scale) > surface->current.scale) { - // When scaling up a surface, it'll become blurry so we need to - // expand the damage region - wlr_region_expand(&damage, &damage, - ceil(output->wlr_output->scale) - surface->current.scale); - } - pixman_region32_translate(&damage, box.x, box.y); - wlr_region_rotated_bounds(&damage, &damage, rotation, - center_x, center_y); - wlr_output_damage_add(output->damage, &damage); - pixman_region32_fini(&damage); - } - - if (*whole) { - wlr_box_rotated_bounds(&box, &box, rotation); - wlr_output_damage_add_box(output->damage, &box); - } - - wlr_output_schedule_frame(output->wlr_output); -} - -void output_damage_whole_local_surface(struct roots_output *output, - struct wlr_surface *surface, double ox, double oy) { - bool whole = true; - output_surface_for_each_surface(output, surface, ox, oy, - damage_surface_iterator, &whole); -} - -static void damage_whole_decoration(struct roots_view *view, - struct roots_output *output) { - if (!view->decorated || view->wlr_surface == NULL) { - return; - } - - struct wlr_box box; - get_decoration_box(view, output, &box); - - wlr_box_rotated_bounds(&box, &box, view->rotation); - - wlr_output_damage_add_box(output->damage, &box); -} - -void output_damage_whole_view(struct roots_output *output, - struct roots_view *view) { - if (!view_accept_damage(output, view)) { - return; - } - - damage_whole_decoration(view, output); - - bool whole = true; - output_view_for_each_surface(output, view, damage_surface_iterator, &whole); -} - -void output_damage_whole_drag_icon(struct roots_output *output, - struct roots_drag_icon *icon) { - bool whole = true; - output_surface_for_each_surface(output, icon->wlr_drag_icon->surface, - icon->x, icon->y, damage_surface_iterator, &whole); -} - -void output_damage_from_local_surface(struct roots_output *output, - struct wlr_surface *surface, double ox, double oy) { - bool whole = false; - output_surface_for_each_surface(output, surface, ox, oy, - damage_surface_iterator, &whole); -} - -void output_damage_from_view(struct roots_output *output, - struct roots_view *view) { - if (!view_accept_damage(output, view)) { - return; - } - - bool whole = false; - output_view_for_each_surface(output, view, damage_surface_iterator, &whole); -} - -static void set_mode(struct wlr_output *output, - struct roots_output_config *oc) { - int mhz = (int)(oc->mode.refresh_rate * 1000); - - if (wl_list_empty(&output->modes)) { - // Output has no mode, try setting a custom one - wlr_output_set_custom_mode(output, oc->mode.width, oc->mode.height, mhz); - return; - } - - struct wlr_output_mode *mode, *best = NULL; - wl_list_for_each(mode, &output->modes, link) { - if (mode->width == oc->mode.width && mode->height == oc->mode.height) { - if (mode->refresh == mhz) { - best = mode; - break; - } - best = mode; - } - } - if (!best) { - wlr_log(WLR_ERROR, "Configured mode for %s not available", output->name); - } else { - wlr_log(WLR_DEBUG, "Assigning configured mode to %s", output->name); - wlr_output_set_mode(output, best); - } -} - -static void update_output_manager_config(struct roots_desktop *desktop) { - struct wlr_output_configuration_v1 *config = - wlr_output_configuration_v1_create(); - - struct roots_output *output; - wl_list_for_each(output, &desktop->outputs, link) { - struct wlr_output_configuration_head_v1 *config_head = - wlr_output_configuration_head_v1_create(config, output->wlr_output); - struct wlr_box *output_box = wlr_output_layout_get_box( - output->desktop->layout, output->wlr_output); - if (output_box) { - config_head->state.x = output_box->x; - config_head->state.y = output_box->y; - } - } - - wlr_output_manager_v1_set_configuration(desktop->output_manager_v1, config); -} - -void handle_output_manager_apply(struct wl_listener *listener, void *data) { - struct roots_desktop *desktop = - wl_container_of(listener, desktop, output_manager_apply); - struct wlr_output_configuration_v1 *config = data; - - bool ok = true; - struct wlr_output_configuration_head_v1 *config_head; - // First disable outputs we need to disable - wl_list_for_each(config_head, &config->heads, link) { - struct wlr_output *wlr_output = config_head->state.output; - if (!config_head->state.enabled) { - ok &= wlr_output_enable(wlr_output, false); - wlr_output_layout_remove(desktop->layout, wlr_output); - } - } - - // Then enable outputs that need to - wl_list_for_each(config_head, &config->heads, link) { - struct wlr_output *wlr_output = config_head->state.output; - if (!config_head->state.enabled) { - continue; - } - ok &= wlr_output_enable(wlr_output, true); - if (config_head->state.mode != NULL) { - ok &= wlr_output_set_mode(wlr_output, config_head->state.mode); - } else { - ok &= wlr_output_set_custom_mode(wlr_output, - config_head->state.custom_mode.width, - config_head->state.custom_mode.height, - config_head->state.custom_mode.refresh); - } - wlr_output_layout_add(desktop->layout, wlr_output, - config_head->state.x, config_head->state.y); - wlr_output_set_transform(wlr_output, config_head->state.transform); - wlr_output_set_scale(wlr_output, config_head->state.scale); - } - - if (ok) { - wlr_output_configuration_v1_send_succeeded(config); - } else { - wlr_output_configuration_v1_send_failed(config); - } - wlr_output_configuration_v1_destroy(config); - - update_output_manager_config(desktop); -} - -void handle_output_manager_test(struct wl_listener *listener, void *data) { - struct roots_desktop *desktop = - wl_container_of(listener, desktop, output_manager_test); - struct wlr_output_configuration_v1 *config = data; - - // TODO: implement test-only mode - wlr_output_configuration_v1_send_succeeded(config); - wlr_output_configuration_v1_destroy(config); -} - -static void output_destroy(struct roots_output *output) { - // TODO: cursor - //example_config_configure_cursor(sample->config, sample->cursor, - // sample->compositor); - - wl_list_remove(&output->link); - wl_list_remove(&output->destroy.link); - wl_list_remove(&output->enable.link); - wl_list_remove(&output->mode.link); - wl_list_remove(&output->transform.link); - wl_list_remove(&output->present.link); - wl_list_remove(&output->damage_frame.link); - wl_list_remove(&output->damage_destroy.link); - free(output); -} - -static void output_handle_destroy(struct wl_listener *listener, void *data) { - struct roots_output *output = wl_container_of(listener, output, destroy); - struct roots_desktop *desktop = output->desktop; - output_destroy(output); - update_output_manager_config(desktop); -} - -static void output_handle_enable(struct wl_listener *listener, void *data) { - struct roots_output *output = wl_container_of(listener, output, enable); - update_output_manager_config(output->desktop); -} - -static void output_damage_handle_frame(struct wl_listener *listener, - void *data) { - struct roots_output *output = - wl_container_of(listener, output, damage_frame); - output_render(output); -} - -static void output_damage_handle_destroy(struct wl_listener *listener, - void *data) { - struct roots_output *output = - wl_container_of(listener, output, damage_destroy); - output_destroy(output); -} - -static void output_handle_mode(struct wl_listener *listener, void *data) { - struct roots_output *output = - wl_container_of(listener, output, mode); - arrange_layers(output); - update_output_manager_config(output->desktop); -} - -static void output_handle_transform(struct wl_listener *listener, void *data) { - struct roots_output *output = - wl_container_of(listener, output, transform); - arrange_layers(output); -} - -static void surface_send_presented_iterator(struct roots_output *output, - struct wlr_surface *surface, struct wlr_box *_box, float rotation, - void *data) { - struct wlr_presentation_event *event = data; - wlr_presentation_send_surface_presented(output->desktop->presentation, - surface, event); -} - -static void output_handle_present(struct wl_listener *listener, void *data) { - struct roots_output *output = - wl_container_of(listener, output, present); - struct wlr_output_event_present *output_event = data; - - struct wlr_presentation_event event = { - .output = output->wlr_output, - .tv_sec = (uint64_t)output_event->when->tv_sec, - .tv_nsec = (uint32_t)output_event->when->tv_nsec, - .refresh = (uint32_t)output_event->refresh, - .seq = (uint64_t)output_event->seq, - .flags = output_event->flags, - }; - - output_for_each_surface(output, - surface_send_presented_iterator, &event); -} - -void handle_new_output(struct wl_listener *listener, void *data) { - struct roots_desktop *desktop = wl_container_of(listener, desktop, - new_output); - struct wlr_output *wlr_output = data; - struct roots_input *input = desktop->server->input; - struct roots_config *config = desktop->config; - - wlr_log(WLR_DEBUG, "Output '%s' added", wlr_output->name); - wlr_log(WLR_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); - - struct roots_output *output = calloc(1, sizeof(struct roots_output)); - clock_gettime(CLOCK_MONOTONIC, &output->last_frame); - output->desktop = desktop; - output->wlr_output = wlr_output; - wlr_output->data = output; - wl_list_insert(&desktop->outputs, &output->link); - - output->damage = wlr_output_damage_create(wlr_output); - - output->destroy.notify = output_handle_destroy; - wl_signal_add(&wlr_output->events.destroy, &output->destroy); - output->enable.notify = output_handle_enable; - wl_signal_add(&wlr_output->events.enable, &output->enable); - output->mode.notify = output_handle_mode; - wl_signal_add(&wlr_output->events.mode, &output->mode); - output->transform.notify = output_handle_transform; - wl_signal_add(&wlr_output->events.transform, &output->transform); - output->present.notify = output_handle_present; - wl_signal_add(&wlr_output->events.present, &output->present); - - output->damage_frame.notify = output_damage_handle_frame; - wl_signal_add(&output->damage->events.frame, &output->damage_frame); - output->damage_destroy.notify = output_damage_handle_destroy; - wl_signal_add(&output->damage->events.destroy, &output->damage_destroy); - - size_t len = sizeof(output->layers) / sizeof(output->layers[0]); - for (size_t i = 0; i < len; ++i) { - wl_list_init(&output->layers[i]); - } - - struct roots_output_config *output_config = - roots_config_get_output(config, wlr_output); - - struct wlr_output_mode *preferred_mode = - wlr_output_preferred_mode(wlr_output); - if (output_config) { - if (output_config->enable) { - if (wlr_output_is_drm(wlr_output)) { - struct roots_output_mode_config *mode_config; - wl_list_for_each(mode_config, &output_config->modes, link) { - wlr_drm_connector_add_mode(wlr_output, &mode_config->info); - } - } else if (!wl_list_empty(&output_config->modes)) { - wlr_log(WLR_ERROR, "Can only add modes for DRM backend"); - } - - if (output_config->mode.width) { - set_mode(wlr_output, output_config); - } else if (preferred_mode != NULL) { - wlr_output_set_mode(wlr_output, preferred_mode); - } - - wlr_output_set_scale(wlr_output, output_config->scale); - wlr_output_set_transform(wlr_output, output_config->transform); - wlr_output_layout_add(desktop->layout, wlr_output, output_config->x, - output_config->y); - } else { - wlr_output_enable(wlr_output, false); - } - } else { - if (preferred_mode != NULL) { - wlr_output_set_mode(wlr_output, preferred_mode); - } - wlr_output_layout_add_auto(desktop->layout, wlr_output); - } - - struct roots_seat *seat; - wl_list_for_each(seat, &input->seats, link) { - roots_seat_configure_cursor(seat); - roots_seat_configure_xcursor(seat); - } - - arrange_layers(output); - output_damage_whole(output); - - update_output_manager_config(desktop); -} diff --git a/rootston/render.c b/rootston/render.c deleted file mode 100644 index 3b242b88..00000000 --- a/rootston/render.c +++ /dev/null @@ -1,422 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/layers.h" -#include "rootston/output.h" -#include "rootston/server.h" - -struct render_data { - pixman_region32_t *damage; - float alpha; -}; - -static void scissor_output(struct wlr_output *wlr_output, - pixman_box32_t *rect) { - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); - assert(renderer); - - struct wlr_box box = { - .x = rect->x1, - .y = rect->y1, - .width = rect->x2 - rect->x1, - .height = rect->y2 - rect->y1, - }; - - int ow, oh; - wlr_output_transformed_resolution(wlr_output, &ow, &oh); - - enum wl_output_transform transform = - wlr_output_transform_invert(wlr_output->transform); - wlr_box_transform(&box, &box, transform, ow, oh); - - wlr_renderer_scissor(renderer, &box); -} - -static void render_texture(struct wlr_output *wlr_output, - pixman_region32_t *output_damage, struct wlr_texture *texture, - const struct wlr_box *box, const float matrix[static 9], - float rotation, float alpha) { - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); - assert(renderer); - - struct wlr_box rotated; - wlr_box_rotated_bounds(&rotated, box, rotation); - - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, - rotated.width, rotated.height); - pixman_region32_intersect(&damage, &damage, output_damage); - bool damaged = pixman_region32_not_empty(&damage); - if (!damaged) { - goto buffer_damage_finish; - } - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(wlr_output, &rects[i]); - wlr_render_texture_with_matrix(renderer, texture, matrix, alpha); - } - -buffer_damage_finish: - pixman_region32_fini(&damage); -} - -static void render_surface_iterator(struct roots_output *output, - struct wlr_surface *surface, struct wlr_box *_box, float rotation, - void *_data) { - struct render_data *data = _data; - struct wlr_output *wlr_output = output->wlr_output; - pixman_region32_t *output_damage = data->damage; - float alpha = data->alpha; - - struct wlr_texture *texture = wlr_surface_get_texture(surface); - if (!texture) { - return; - } - - struct wlr_box box = *_box; - scale_box(&box, wlr_output->scale); - - float matrix[9]; - enum wl_output_transform transform = - wlr_output_transform_invert(surface->current.transform); - wlr_matrix_project_box(matrix, &box, transform, rotation, - wlr_output->transform_matrix); - - render_texture(wlr_output, output_damage, - texture, &box, matrix, rotation, alpha); -} - -static void render_decorations(struct roots_output *output, - struct roots_view *view, struct render_data *data) { - if (!view->decorated || view->wlr_surface == NULL) { - return; - } - - struct wlr_renderer *renderer = - wlr_backend_get_renderer(output->wlr_output->backend); - assert(renderer); - - struct wlr_box box; - get_decoration_box(view, output, &box); - - struct wlr_box rotated; - wlr_box_rotated_bounds(&rotated, &box, view->rotation); - - pixman_region32_t damage; - pixman_region32_init(&damage); - pixman_region32_union_rect(&damage, &damage, rotated.x, rotated.y, - rotated.width, rotated.height); - pixman_region32_intersect(&damage, &damage, data->damage); - bool damaged = pixman_region32_not_empty(&damage); - if (!damaged) { - goto buffer_damage_finish; - } - - float matrix[9]; - wlr_matrix_project_box(matrix, &box, WL_OUTPUT_TRANSFORM_NORMAL, - view->rotation, output->wlr_output->transform_matrix); - float color[] = { 0.2, 0.2, 0.2, view->alpha }; - - int nrects; - pixman_box32_t *rects = - pixman_region32_rectangles(&damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(output->wlr_output, &rects[i]); - wlr_render_quad_with_matrix(renderer, color, matrix); - } - -buffer_damage_finish: - pixman_region32_fini(&damage); -} - -static void render_view(struct roots_output *output, struct roots_view *view, - struct render_data *data) { - // Do not render views fullscreened on other outputs - if (view->fullscreen_output != NULL && view->fullscreen_output != output) { - return; - } - - data->alpha = view->alpha; - if (view->fullscreen_output == NULL) { - render_decorations(output, view, data); - } - output_view_for_each_surface(output, view, render_surface_iterator, data); -} - -static void render_layer(struct roots_output *output, - pixman_region32_t *damage, struct wl_list *layer_surfaces) { - struct render_data data = { - .damage = damage, - .alpha = 1.0f, - }; - output_layer_for_each_surface(output, layer_surfaces, - render_surface_iterator, &data); -} - -static void render_drag_icons(struct roots_output *output, - pixman_region32_t *damage, struct roots_input *input) { - struct render_data data = { - .damage = damage, - .alpha = 1.0f, - }; - output_drag_icons_for_each_surface(output, input, - render_surface_iterator, &data); -} - -static void count_surface_iterator(struct roots_output *output, - struct wlr_surface *surface, struct wlr_box *_box, float rotation, - void *data) { - size_t *n = data; - n++; -} - -static bool scan_out_fullscreen_view(struct roots_output *output) { - struct wlr_output *wlr_output = output->wlr_output; - struct roots_desktop *desktop = output->desktop; - - struct roots_seat *seat; - wl_list_for_each(seat, &desktop->server->input->seats, link) { - struct roots_drag_icon *drag_icon = seat->drag_icon; - if (drag_icon && drag_icon->wlr_drag_icon->mapped) { - return false; - } - } - - if (!wl_list_empty(&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY])) { - return false; - } - - struct wlr_output_cursor *cursor; - wl_list_for_each(cursor, &wlr_output->cursors, link) { - if (cursor->enabled && cursor->visible && - wlr_output->hardware_cursor != cursor) { - return false; - } - } - - struct roots_view *view = output->fullscreen_view; - assert(view != NULL); - if (view->wlr_surface == NULL) { - return false; - } - size_t n_surfaces = 0; - output_view_for_each_surface(output, view, - count_surface_iterator, &n_surfaces); - if (n_surfaces > 1) { - return false; - } - -#if WLR_HAS_XWAYLAND - if (view->type == ROOTS_XWAYLAND_VIEW) { - struct roots_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view); - if (!wl_list_empty(&xwayland_surface->xwayland_surface->children)) { - return false; - } - } -#endif - - struct wlr_surface *surface = view->wlr_surface; - - if (surface->buffer == NULL) { - return false; - } - - if ((float)surface->current.scale != wlr_output->scale || - surface->current.transform != wlr_output->transform) { - return false; - } - - if (!wlr_output_attach_buffer(wlr_output, surface->buffer)) { - return false; - } - return wlr_output_commit(wlr_output); -} - -static void surface_send_frame_done_iterator(struct roots_output *output, - struct wlr_surface *surface, struct wlr_box *box, float rotation, - void *data) { - struct timespec *when = data; - wlr_surface_send_frame_done(surface, when); -} - -void output_render(struct roots_output *output) { - struct wlr_output *wlr_output = output->wlr_output; - struct roots_desktop *desktop = output->desktop; - struct roots_server *server = desktop->server; - struct wlr_renderer *renderer = - wlr_backend_get_renderer(wlr_output->backend); - assert(renderer); - - if (!wlr_output->enabled) { - return; - } - - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - float clear_color[] = {0.25f, 0.25f, 0.25f, 1.0f}; - - const struct wlr_box *output_box = - wlr_output_layout_get_box(desktop->layout, wlr_output); - - // Check if we can delegate the fullscreen surface to the output - if (output->fullscreen_view != NULL && - output->fullscreen_view->wlr_surface != NULL) { - struct roots_view *view = output->fullscreen_view; - - // Make sure the view is centered on screen - struct wlr_box view_box; - view_get_box(view, &view_box); - double view_x = (double)(output_box->width - view_box.width) / 2 + - output_box->x; - double view_y = (double)(output_box->height - view_box.height) / 2 + - output_box->y; - view_move(view, view_x, view_y); - - // Fullscreen views are rendered on a black background - clear_color[0] = clear_color[1] = clear_color[2] = 0; - - // Check if we can scan-out the fullscreen view - static bool last_scanned_out = false; - bool scanned_out = scan_out_fullscreen_view(output); - - if (scanned_out && !last_scanned_out) { - wlr_log(WLR_DEBUG, "Scanning out fullscreen view"); - } - if (last_scanned_out && !scanned_out) { - wlr_log(WLR_DEBUG, "Stopping fullscreen view scan out"); - } - last_scanned_out = scanned_out; - - if (scanned_out) { - goto send_frame_done; - } - } - - bool needs_frame; - pixman_region32_t buffer_damage; - pixman_region32_init(&buffer_damage); - if (!wlr_output_damage_attach_render(output->damage, &needs_frame, - &buffer_damage)) { - return; - } - - struct render_data data = { - .damage = &buffer_damage, - .alpha = 1.0, - }; - - if (!needs_frame) { - // Output doesn't need swap and isn't damaged, skip rendering completely - goto buffer_damage_finish; - } - - wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); - - if (!pixman_region32_not_empty(&buffer_damage)) { - // Output isn't damaged but needs buffer swap - goto renderer_end; - } - - if (server->config->debug_damage_tracking) { - wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); - } - - int nrects; - pixman_box32_t *rects = pixman_region32_rectangles(&buffer_damage, &nrects); - for (int i = 0; i < nrects; ++i) { - scissor_output(output->wlr_output, &rects[i]); - wlr_renderer_clear(renderer, clear_color); - } - - // If a view is fullscreen on this output, render it - if (output->fullscreen_view != NULL) { - struct roots_view *view = output->fullscreen_view; - render_view(output, view, &data); - - // During normal rendering the xwayland window tree isn't traversed - // because all windows are rendered. Here we only want to render - // the fullscreen window's children so we have to traverse the tree. -#if WLR_HAS_XWAYLAND - if (view->type == ROOTS_XWAYLAND_VIEW) { - struct roots_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view); - output_xwayland_children_for_each_surface(output, - xwayland_surface->xwayland_surface, - render_surface_iterator, &data); - } -#endif - } else { - // Render background and bottom layers under views - render_layer(output, &buffer_damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND]); - render_layer(output, &buffer_damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]); - - // Render all views - struct roots_view *view; - wl_list_for_each_reverse(view, &desktop->views, link) { - render_view(output, view, &data); - } - - // Render top layer above views - render_layer(output, &buffer_damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]); - } - - render_drag_icons(output, &buffer_damage, server->input); - - render_layer(output, &buffer_damage, - &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY]); - -renderer_end: - wlr_output_render_software_cursors(wlr_output, &buffer_damage); - wlr_renderer_scissor(renderer, NULL); - wlr_renderer_end(renderer); - - int width, height; - wlr_output_transformed_resolution(wlr_output, &width, &height); - - pixman_region32_t frame_damage; - pixman_region32_init(&frame_damage); - - enum wl_output_transform transform = - wlr_output_transform_invert(wlr_output->transform); - wlr_region_transform(&frame_damage, &output->damage->current, - transform, width, height); - - if (server->config->debug_damage_tracking) { - pixman_region32_union_rect(&frame_damage, &frame_damage, - 0, 0, wlr_output->width, wlr_output->height); - } - - wlr_output_set_damage(wlr_output, &frame_damage); - pixman_region32_fini(&frame_damage); - - if (!wlr_output_commit(wlr_output)) { - goto buffer_damage_finish; - } - output->last_frame = desktop->last_frame = now; - -buffer_damage_finish: - pixman_region32_fini(&buffer_damage); - -send_frame_done: - // Send frame done events to all surfaces - output_for_each_surface(output, surface_send_frame_done_iterator, &now); -} diff --git a/rootston/rootston.ini.example b/rootston/rootston.ini.example deleted file mode 100644 index 4b75e9c6..00000000 --- a/rootston/rootston.ini.example +++ /dev/null @@ -1,63 +0,0 @@ -[core] -# X11 support -# - true: enables X11, xwayland is started only when an X11 client connects -# - immediate: enables X11, xwayland is started immediately -# - false: disables xwayland -xwayland=false - -# Single output configuration. String after colon must match output's name. -[output:VGA-1] -# Set logical (layout) coordinates for this screen -x = 1920 -y = 0 - -# Screen transformation -# possible values are: -# '90', '180' or '270' - rotate output by specified angle clockwise -# 'flipped' - flip output horizontally -# 'flipped-90', 'flipped-180', 'flipped-270' - flip output horizontally -# and rotate by specified angle -rotate = 90 - -# Additional video mode to add -# Format is generated by cvt and is documented in x.org.conf(5) -modeline = 87.25 720 776 848 976 1440 1443 1453 1493 -hsync +vsync -modeline = 65.13 768 816 896 1024 1024 1025 1028 1060 -HSync +VSync -# Select one of the above modes -mode = 768x1024 - -[cursor] -# Restrict cursor movements to single output -map-to-output = VGA-1 -# Restrict cursor movements to concrete rectangle -geometry = 2500x800 -# Load a custom XCursor theme -theme = default - -# Single device configuration. String after colon must match device's name. -[device:PixArt Dell MS116 USB Optical Mouse] -# Restrict cursor movements for this mouse to single output -map-to-output = VGA-1 -# Restrict cursor movements for this mouse to concrete rectangle -geometry = 2500x800 -# tap_enabled=true - -[keyboard] -meta-key = Logo - -# Keybindings -# Maps key combinations with commands to execute -# Commands include: -# - "exit" to stop the compositor -# - "exec" to execute a shell command -# - "close" to close the current view -# - "next_window" to cycle through windows -# - "alpha" to cycle a window's alpha channel -# - "break_pointer_constraint" to decline and deactivate all pointer constraints -[bindings] -Logo+Shift+e = exit -Logo+q = close -Logo+m = maximize -Logo+Escape = break_pointer_constraint -Alt+Tab = next_window -Ctrl+Shift+a = alpha diff --git a/rootston/seat.c b/rootston/seat.c deleted file mode 100644 index c51d6ee5..00000000 --- a/rootston/seat.c +++ /dev/null @@ -1,1642 +0,0 @@ -#define _POSIX_C_SOURCE 200112L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/cursor.h" -#include "rootston/input.h" -#include "rootston/keyboard.h" -#include "rootston/seat.h" -#include "rootston/text_input.h" -#include "rootston/xcursor.h" - -static void handle_keyboard_key(struct wl_listener *listener, void *data) { - struct roots_keyboard *keyboard = - wl_container_of(listener, keyboard, keyboard_key); - struct roots_desktop *desktop = keyboard->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, keyboard->seat->seat); - 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); - struct roots_desktop *desktop = keyboard->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, keyboard->seat->seat); - 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 roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - 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 roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - 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 roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - 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 roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - struct wlr_event_pointer_axis *event = data; - roots_cursor_handle_axis(cursor, event); -} - -static void handle_cursor_frame(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, frame); - struct roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - roots_cursor_handle_frame(cursor); -} - -static void handle_swipe_begin(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, swipe_begin); - struct wlr_pointer_gestures_v1 *gestures = - cursor->seat->input->server->desktop->pointer_gestures; - struct wlr_event_pointer_swipe_begin *event = data; - wlr_pointer_gestures_v1_send_swipe_begin(gestures, cursor->seat->seat, - event->time_msec, event->fingers); -} - -static void handle_swipe_update(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, swipe_update); - struct wlr_pointer_gestures_v1 *gestures = - cursor->seat->input->server->desktop->pointer_gestures; - struct wlr_event_pointer_swipe_update *event = data; - wlr_pointer_gestures_v1_send_swipe_update(gestures, cursor->seat->seat, - event->time_msec, event->dx, event->dy); -} - -static void handle_swipe_end(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, swipe_end); - struct wlr_pointer_gestures_v1 *gestures = - cursor->seat->input->server->desktop->pointer_gestures; - struct wlr_event_pointer_swipe_end *event = data; - wlr_pointer_gestures_v1_send_swipe_end(gestures, cursor->seat->seat, - event->time_msec, event->cancelled); -} - -static void handle_pinch_begin(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, pinch_begin); - struct wlr_pointer_gestures_v1 *gestures = - cursor->seat->input->server->desktop->pointer_gestures; - struct wlr_event_pointer_pinch_begin *event = data; - wlr_pointer_gestures_v1_send_pinch_begin(gestures, cursor->seat->seat, - event->time_msec, event->fingers); -} - -static void handle_pinch_update(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, pinch_update); - struct wlr_pointer_gestures_v1 *gestures = - cursor->seat->input->server->desktop->pointer_gestures; - struct wlr_event_pointer_pinch_update *event = data; - wlr_pointer_gestures_v1_send_pinch_update(gestures, cursor->seat->seat, - event->time_msec, event->dx, event->dy, - event->scale, event->rotation); -} - -static void handle_pinch_end(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, pinch_end); - struct wlr_pointer_gestures_v1 *gestures = - cursor->seat->input->server->desktop->pointer_gestures; - struct wlr_event_pointer_pinch_end *event = data; - wlr_pointer_gestures_v1_send_pinch_end(gestures, cursor->seat->seat, - event->time_msec, event->cancelled); -} - -static void handle_switch_toggle(struct wl_listener *listener, void *data) { - struct roots_switch *switch_device = - wl_container_of(listener, switch_device, toggle); - struct roots_desktop *desktop = switch_device->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, switch_device->seat->seat); - struct wlr_event_switch_toggle *event = data; - roots_switch_handle_toggle(switch_device, event); -} - -static void handle_touch_down(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, touch_down); - struct roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - 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 roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - 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 roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - struct wlr_event_touch_motion *event = data; - roots_cursor_handle_touch_motion(cursor, event); -} - -static void handle_tablet_tool_position(struct roots_cursor *cursor, - struct roots_tablet *tablet, - struct wlr_tablet_tool *tool, - bool change_x, bool change_y, - double x, double y, double dx, double dy) { - if (!change_x && !change_y) { - return; - } - - switch (tool->type) { - case WLR_TABLET_TOOL_TYPE_MOUSE: - // They are 0 either way when they weren't modified - wlr_cursor_move(cursor->cursor, tablet->device, dx, dy); - break; - default: - wlr_cursor_warp_absolute(cursor->cursor, tablet->device, - change_x ? x : NAN, change_y ? y : NAN); - } - - double sx, sy; - struct roots_view *view = NULL; - struct roots_seat *seat = cursor->seat; - struct roots_desktop *desktop = seat->input->server->desktop; - struct wlr_surface *surface = desktop_surface_at(desktop, - cursor->cursor->x, cursor->cursor->y, &sx, &sy, &view); - struct roots_tablet_tool *roots_tool = tool->data; - - if (!surface) { - wlr_tablet_v2_tablet_tool_notify_proximity_out(roots_tool->tablet_v2_tool); - /* XXX: TODO: Fallback pointer semantics */ - return; - } - - if (!wlr_surface_accepts_tablet_v2(tablet->tablet_v2, surface)) { - wlr_tablet_v2_tablet_tool_notify_proximity_out(roots_tool->tablet_v2_tool); - /* XXX: TODO: Fallback pointer semantics */ - return; - } - - wlr_tablet_v2_tablet_tool_notify_proximity_in(roots_tool->tablet_v2_tool, - tablet->tablet_v2, surface); - - wlr_tablet_v2_tablet_tool_notify_motion(roots_tool->tablet_v2_tool, sx, sy); -} - -static void handle_tool_axis(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, tool_axis); - struct roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - struct wlr_event_tablet_tool_axis *event = data; - struct roots_tablet_tool *roots_tool = event->tool->data; - - if (!roots_tool) { // Should this be an assert? - wlr_log(WLR_DEBUG, "Tool Axis, before proximity"); - return; - } - - /** - * We need to handle them ourselves, not pass it into the cursor - * without any consideration - */ - handle_tablet_tool_position(cursor, event->device->data, event->tool, - event->updated_axes & WLR_TABLET_TOOL_AXIS_X, - event->updated_axes & WLR_TABLET_TOOL_AXIS_Y, - event->x, event->y, event->dx, event->dy); - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_PRESSURE) { - wlr_tablet_v2_tablet_tool_notify_pressure( - roots_tool->tablet_v2_tool, event->pressure); - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE) { - wlr_tablet_v2_tablet_tool_notify_distance( - roots_tool->tablet_v2_tool, event->distance); - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_X) { - roots_tool->tilt_x = event->tilt_x; - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_TILT_Y) { - roots_tool->tilt_y = event->tilt_y; - } - - if (event->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y)) { - wlr_tablet_v2_tablet_tool_notify_tilt( - roots_tool->tablet_v2_tool, - roots_tool->tilt_x, roots_tool->tilt_y); - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION) { - wlr_tablet_v2_tablet_tool_notify_rotation( - roots_tool->tablet_v2_tool, event->rotation); - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER) { - wlr_tablet_v2_tablet_tool_notify_slider( - roots_tool->tablet_v2_tool, event->slider); - } - - if (event->updated_axes & WLR_TABLET_TOOL_AXIS_WHEEL) { - wlr_tablet_v2_tablet_tool_notify_wheel( - roots_tool->tablet_v2_tool, event->wheel_delta, 0); - } -} - -static void handle_tool_tip(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, tool_tip); - struct roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - struct wlr_event_tablet_tool_tip *event = data; - struct roots_tablet_tool *roots_tool = event->tool->data; - - if (event->state == WLR_TABLET_TOOL_TIP_DOWN) { - wlr_tablet_v2_tablet_tool_notify_down(roots_tool->tablet_v2_tool); - wlr_tablet_tool_v2_start_implicit_grab(roots_tool->tablet_v2_tool); - } else { - wlr_tablet_v2_tablet_tool_notify_up(roots_tool->tablet_v2_tool); - } -} - -static void handle_tablet_tool_destroy(struct wl_listener *listener, void *data) { - struct roots_tablet_tool *tool = - wl_container_of(listener, tool, tool_destroy); - - wl_list_remove(&tool->link); - wl_list_remove(&tool->tool_link); - - wl_list_remove(&tool->tool_destroy.link); - wl_list_remove(&tool->set_cursor.link); - - free(tool); -} - -static void handle_tool_button(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, tool_button); - struct roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - struct wlr_event_tablet_tool_button *event = data; - struct roots_tablet_tool *roots_tool = event->tool->data; - - wlr_tablet_v2_tablet_tool_notify_button(roots_tool->tablet_v2_tool, - (enum zwp_tablet_pad_v2_button_state)event->button, - (enum zwp_tablet_pad_v2_button_state)event->state); -} - -static void handle_tablet_tool_set_cursor(struct wl_listener *listener, void *data) { - struct roots_tablet_tool *tool = - wl_container_of(listener, tool, set_cursor); - struct wlr_tablet_v2_event_cursor *evt = data; - - - struct wlr_seat_pointer_request_set_cursor_event event = { - .surface = evt->surface, - .hotspot_x = evt->hotspot_x, - .hotspot_y = evt->hotspot_y, - .serial = evt->serial, - .seat_client = evt->seat_client, - }; - - roots_cursor_handle_request_set_cursor(tool->seat->cursor, &event); -} - -static void handle_tool_proximity(struct wl_listener *listener, void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, tool_proximity); - struct roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - struct wlr_event_tablet_tool_proximity *event = data; - - struct wlr_tablet_tool *tool = event->tool; - if (!tool->data) { - struct roots_tablet_tool *roots_tool = - calloc(1, sizeof(struct roots_tablet_tool)); - roots_tool->seat = cursor->seat; - tool->data = roots_tool; - roots_tool->tablet_v2_tool = - wlr_tablet_tool_create(desktop->tablet_v2, - cursor->seat->seat, tool); - roots_tool->tool_destroy.notify = handle_tablet_tool_destroy; - wl_signal_add(&tool->events.destroy, &roots_tool->tool_destroy); - - roots_tool->set_cursor.notify = handle_tablet_tool_set_cursor; - wl_signal_add(&roots_tool->tablet_v2_tool->events.set_cursor, - &roots_tool->set_cursor); - - wl_list_init(&roots_tool->link); - wl_list_init(&roots_tool->tool_link); - } - - if (event->state == WLR_TABLET_TOOL_PROXIMITY_OUT) { - struct roots_tablet_tool *roots_tool = tool->data; - wlr_tablet_v2_tablet_tool_notify_proximity_out(roots_tool->tablet_v2_tool); - return; - } - - handle_tablet_tool_position(cursor, event->device->data, event->tool, - true, true, event->x, event->y, 0, 0); -} - -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 roots_desktop *desktop = cursor->seat->input->server->desktop; - wlr_idle_notify_activity(desktop->idle, cursor->seat->seat); - struct wlr_seat_pointer_request_set_cursor_event *event = data; - roots_cursor_handle_request_set_cursor(cursor, event); -} - -static void handle_pointer_focus_change(struct wl_listener *listener, - void *data) { - struct roots_cursor *cursor = - wl_container_of(listener, cursor, focus_change); - struct wlr_seat_pointer_focus_change_event *event = data; - roots_cursor_handle_focus_change(cursor, event); -} - -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 = - roots_config_get_device(config, device); - - const char *mapped_output = NULL; - if (dconfig != NULL) { - mapped_output = dconfig->mapped_output; - } - if (mapped_output == NULL) { - mapped_output = device->output_name; - } - - if (mapped_output && strcmp(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 *tablet; - 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, &seat->tablets, link) { - seat_reset_device_mappings(seat, tablet->device); - } - - // configure device to output mappings - const char *mapped_output = NULL; - struct roots_cursor_config *cc = - roots_config_get_cursor(config, seat->seat->name); - if (cc != NULL) { - mapped_output = cc->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, &seat->tablets, link) { - seat_set_device_output_mappings(seat, tablet->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); - - 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.frame, &seat->cursor->frame); - seat->cursor->frame.notify = handle_cursor_frame; - - wl_signal_add(&wlr_cursor->events.swipe_begin, &seat->cursor->swipe_begin); - seat->cursor->swipe_begin.notify = handle_swipe_begin; - - wl_signal_add(&wlr_cursor->events.swipe_update, &seat->cursor->swipe_update); - seat->cursor->swipe_update.notify = handle_swipe_update; - - wl_signal_add(&wlr_cursor->events.swipe_end, &seat->cursor->swipe_end); - seat->cursor->swipe_end.notify = handle_swipe_end; - - wl_signal_add(&wlr_cursor->events.pinch_begin, &seat->cursor->pinch_begin); - seat->cursor->pinch_begin.notify = handle_pinch_begin; - - wl_signal_add(&wlr_cursor->events.pinch_update, &seat->cursor->pinch_update); - seat->cursor->pinch_update.notify = handle_pinch_update; - - wl_signal_add(&wlr_cursor->events.pinch_end, &seat->cursor->pinch_end); - seat->cursor->pinch_end.notify = handle_pinch_end; - - 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(&wlr_cursor->events.tablet_tool_proximity, &seat->cursor->tool_proximity); - seat->cursor->tool_proximity.notify = handle_tool_proximity; - - wl_signal_add(&wlr_cursor->events.tablet_tool_button, &seat->cursor->tool_button); - seat->cursor->tool_button.notify = handle_tool_button; - - 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->pointer_state.events.focus_change, - &seat->cursor->focus_change); - seat->cursor->focus_change.notify = handle_pointer_focus_change; - - wl_list_init(&seat->cursor->constraint_commit.link); -} - -static void roots_drag_icon_handle_surface_commit(struct wl_listener *listener, - void *data) { - struct roots_drag_icon *icon = - wl_container_of(listener, icon, surface_commit); - roots_drag_icon_update_position(icon); -} - -static void roots_drag_icon_handle_map(struct wl_listener *listener, - void *data) { - struct roots_drag_icon *icon = - wl_container_of(listener, icon, map); - roots_drag_icon_damage_whole(icon); -} - -static void roots_drag_icon_handle_unmap(struct wl_listener *listener, - void *data) { - struct roots_drag_icon *icon = - wl_container_of(listener, icon, unmap); - roots_drag_icon_damage_whole(icon); -} - -static void roots_drag_icon_handle_destroy(struct wl_listener *listener, - void *data) { - struct roots_drag_icon *icon = - wl_container_of(listener, icon, destroy); - roots_drag_icon_damage_whole(icon); - - assert(icon->seat->drag_icon == icon); - icon->seat->drag_icon = NULL; - - wl_list_remove(&icon->surface_commit.link); - wl_list_remove(&icon->unmap.link); - wl_list_remove(&icon->destroy.link); - free(icon); -} - -static void roots_seat_handle_request_start_drag(struct wl_listener *listener, - void *data) { - struct roots_seat *seat = - wl_container_of(listener, seat, request_start_drag); - struct wlr_seat_request_start_drag_event *event = data; - - if (wlr_seat_validate_pointer_grab_serial(seat->seat, - event->origin, event->serial)) { - wlr_seat_start_pointer_drag(seat->seat, event->drag, event->serial); - return; - } - - struct wlr_touch_point *point; - if (wlr_seat_validate_touch_grab_serial(seat->seat, - event->origin, event->serial, &point)) { - wlr_seat_start_touch_drag(seat->seat, event->drag, event->serial, point); - return; - } - - wlr_log(WLR_DEBUG, "Ignoring start_drag request: " - "could not validate pointer or touch serial %" PRIu32, event->serial); - wlr_data_source_destroy(event->drag->source); -} - -static void roots_seat_handle_start_drag(struct wl_listener *listener, - void *data) { - struct roots_seat *seat = wl_container_of(listener, seat, start_drag); - struct wlr_drag *wlr_drag = data; - struct wlr_drag_icon *wlr_drag_icon = wlr_drag->icon; - if (wlr_drag_icon == NULL) { - return; - } - - struct roots_drag_icon *icon = calloc(1, sizeof(struct roots_drag_icon)); - if (icon == NULL) { - return; - } - icon->seat = seat; - icon->wlr_drag_icon = wlr_drag_icon; - - icon->surface_commit.notify = roots_drag_icon_handle_surface_commit; - wl_signal_add(&wlr_drag_icon->surface->events.commit, &icon->surface_commit); - icon->unmap.notify = roots_drag_icon_handle_unmap; - wl_signal_add(&wlr_drag_icon->events.unmap, &icon->unmap); - icon->map.notify = roots_drag_icon_handle_map; - wl_signal_add(&wlr_drag_icon->events.map, &icon->map); - icon->destroy.notify = roots_drag_icon_handle_destroy; - wl_signal_add(&wlr_drag_icon->events.destroy, &icon->destroy); - - assert(seat->drag_icon == NULL); - seat->drag_icon = icon; - - roots_drag_icon_update_position(icon); -} - -static void roots_seat_handle_request_set_selection( - struct wl_listener *listener, void *data) { - struct roots_seat *seat = - wl_container_of(listener, seat, request_set_selection); - struct wlr_seat_request_set_selection_event *event = data; - wlr_seat_set_selection(seat->seat, event->source, event->serial); -} - -static void roots_seat_handle_request_set_primary_selection( - struct wl_listener *listener, void *data) { - struct roots_seat *seat = - wl_container_of(listener, seat, request_set_primary_selection); - struct wlr_seat_request_set_primary_selection_event *event = data; - wlr_seat_set_primary_selection(seat->seat, event->source, event->serial); -} - -void roots_drag_icon_update_position(struct roots_drag_icon *icon) { - roots_drag_icon_damage_whole(icon); - - struct roots_seat *seat = icon->seat; - struct wlr_drag *wlr_drag = icon->wlr_drag_icon->drag; - assert(wlr_drag != NULL); - - switch (seat->seat->drag->grab_type) { - case WLR_DRAG_GRAB_KEYBOARD: - assert(false); - case WLR_DRAG_GRAB_KEYBOARD_POINTER:; - struct wlr_cursor *cursor = seat->cursor->cursor; - icon->x = cursor->x; - icon->y = cursor->y; - break; - case WLR_DRAG_GRAB_KEYBOARD_TOUCH:; - struct wlr_touch_point *point = - wlr_seat_touch_get_point(seat->seat, wlr_drag->touch_id); - if (point == NULL) { - return; - } - icon->x = seat->touch_x; - icon->y = seat->touch_y; - break; - } - - roots_drag_icon_damage_whole(icon); -} - -void roots_drag_icon_damage_whole(struct roots_drag_icon *icon) { - struct roots_output *output; - wl_list_for_each(output, &icon->seat->input->server->desktop->outputs, - link) { - output_damage_whole_drag_icon(output, icon); - } -} - -static void seat_view_destroy(struct roots_seat_view *seat_view); - -static void roots_seat_handle_destroy(struct wl_listener *listener, - void *data) { - struct roots_seat *seat = wl_container_of(listener, seat, destroy); - - // TODO: probably more to be freed here - wl_list_remove(&seat->destroy.link); - - struct roots_seat_view *view, *nview; - wl_list_for_each_safe(view, nview, &seat->views, link) { - seat_view_destroy(view); - } -} - -void roots_seat_destroy(struct roots_seat *seat) { - roots_seat_handle_destroy(&seat->destroy, seat->seat); - wlr_seat_destroy(seat->seat); -} - -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->tablets); - wl_list_init(&seat->tablet_pads); - wl_list_init(&seat->switches); - wl_list_init(&seat->views); - - seat->input = input; - - seat->seat = wlr_seat_create(input->server->wl_display, name); - if (!seat->seat) { - free(seat); - return NULL; - } - seat->seat->data = seat; - - roots_seat_init_cursor(seat); - if (!seat->cursor) { - wlr_seat_destroy(seat->seat); - free(seat); - return NULL; - } - - roots_input_method_relay_init(seat, &seat->im_relay); - - wl_list_insert(&input->seats, &seat->link); - - seat->request_set_selection.notify = - roots_seat_handle_request_set_selection; - wl_signal_add(&seat->seat->events.request_set_selection, - &seat->request_set_selection); - seat->request_set_primary_selection.notify = - roots_seat_handle_request_set_primary_selection; - wl_signal_add(&seat->seat->events.request_set_primary_selection, - &seat->request_set_primary_selection); - seat->request_start_drag.notify = roots_seat_handle_request_start_drag; - wl_signal_add(&seat->seat->events.request_start_drag, - &seat->request_start_drag); - seat->start_drag.notify = roots_seat_handle_start_drag; - wl_signal_add(&seat->seat->events.start_drag, &seat->start_drag); - seat->destroy.notify = roots_seat_handle_destroy; - wl_signal_add(&seat->seat->events.destroy, &seat->destroy); - - return seat; -} - -static void seat_update_capabilities(struct roots_seat *seat) { - uint32_t caps = 0; - if (!wl_list_empty(&seat->keyboards)) { - caps |= WL_SEAT_CAPABILITY_KEYBOARD; - } - if (!wl_list_empty(&seat->pointers) || !wl_list_empty(&seat->tablets)) { - caps |= WL_SEAT_CAPABILITY_POINTER; - } - if (!wl_list_empty(&seat->touch)) { - caps |= WL_SEAT_CAPABILITY_TOUCH; - } - wlr_seat_set_capabilities(seat->seat, caps); - - // Hide cursor if seat doesn't have pointer capability - if ((caps & WL_SEAT_CAPABILITY_POINTER) == 0) { - wlr_cursor_set_image(seat->cursor->cursor, NULL, 0, 0, 0, 0, 0, 0); - } else { - wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, - seat->cursor->default_xcursor, seat->cursor->cursor); - } -} - -static void handle_keyboard_destroy(struct wl_listener *listener, void *data) { - struct roots_keyboard *keyboard = - wl_container_of(listener, keyboard, device_destroy); - struct roots_seat *seat = keyboard->seat; - wl_list_remove(&keyboard->device_destroy.link); - wl_list_remove(&keyboard->keyboard_key.link); - wl_list_remove(&keyboard->keyboard_modifiers.link); - roots_keyboard_destroy(keyboard); - seat_update_capabilities(seat); -} - -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(WLR_ERROR, "could not allocate keyboard for seat"); - return; - } - - keyboard->seat = seat; - - wl_list_insert(&seat->keyboards, &keyboard->link); - - keyboard->device_destroy.notify = handle_keyboard_destroy; - wl_signal_add(&keyboard->device->events.destroy, &keyboard->device_destroy); - 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 handle_pointer_destroy(struct wl_listener *listener, void *data) { - struct roots_pointer *pointer = - wl_container_of(listener, pointer, device_destroy); - struct roots_seat *seat = pointer->seat; - - wl_list_remove(&pointer->link); - wlr_cursor_detach_input_device(seat->cursor->cursor, pointer->device); - wl_list_remove(&pointer->device_destroy.link); - free(pointer); - - seat_update_capabilities(seat); -} - -static void seat_add_pointer(struct roots_seat *seat, - struct wlr_input_device *device) { - struct roots_pointer *pointer = calloc(1, sizeof(struct roots_pointer)); - if (!pointer) { - wlr_log(WLR_ERROR, "could not allocate pointer for seat"); - return; - } - - device->data = pointer; - pointer->device = device; - pointer->seat = seat; - wl_list_insert(&seat->pointers, &pointer->link); - - pointer->device_destroy.notify = handle_pointer_destroy; - wl_signal_add(&pointer->device->events.destroy, &pointer->device_destroy); - - wlr_cursor_attach_input_device(seat->cursor->cursor, device); - roots_seat_configure_cursor(seat); -} - -static void handle_switch_destroy(struct wl_listener *listener, void *data) { - struct roots_switch *switch_device = - wl_container_of(listener, switch_device, device_destroy); - struct roots_seat *seat = switch_device->seat; - - wl_list_remove(&switch_device->link); - wl_list_remove(&switch_device->device_destroy.link); - free(switch_device); - - seat_update_capabilities(seat); -} - -static void seat_add_switch(struct roots_seat *seat, - struct wlr_input_device *device) { - assert(device->type == WLR_INPUT_DEVICE_SWITCH); - struct roots_switch *switch_device = calloc(1, sizeof(struct roots_switch)); - if (!switch_device) { - wlr_log(WLR_ERROR, "could not allocate switch for seat"); - return; - } - device->data = switch_device; - switch_device->device = device; - switch_device->seat = seat; - wl_list_insert(&seat->switches, &switch_device->link); - switch_device->device_destroy.notify = handle_switch_destroy; - - switch_device->toggle.notify = handle_switch_toggle; - wl_signal_add(&switch_device->device->switch_device->events.toggle, &switch_device->toggle); -} - -static void handle_touch_destroy(struct wl_listener *listener, void *data) { - struct roots_pointer *touch = - wl_container_of(listener, touch, device_destroy); - struct roots_seat *seat = touch->seat; - - wl_list_remove(&touch->link); - wlr_cursor_detach_input_device(seat->cursor->cursor, touch->device); - wl_list_remove(&touch->device_destroy.link); - free(touch); - - seat_update_capabilities(seat); -} - -static void seat_add_touch(struct roots_seat *seat, - struct wlr_input_device *device) { - struct roots_touch *touch = calloc(1, sizeof(struct roots_touch)); - if (!touch) { - wlr_log(WLR_ERROR, "could not allocate touch for seat"); - return; - } - - device->data = touch; - touch->device = device; - touch->seat = seat; - wl_list_insert(&seat->touch, &touch->link); - - touch->device_destroy.notify = handle_touch_destroy; - wl_signal_add(&touch->device->events.destroy, &touch->device_destroy); - - wlr_cursor_attach_input_device(seat->cursor->cursor, device); - roots_seat_configure_cursor(seat); -} - -static void handle_tablet_pad_destroy(struct wl_listener *listener, - void *data) { - struct roots_tablet_pad *tablet_pad = - wl_container_of(listener, tablet_pad, device_destroy); - struct roots_seat *seat = tablet_pad->seat; - - wl_list_remove(&tablet_pad->device_destroy.link); - wl_list_remove(&tablet_pad->tablet_destroy.link); - wl_list_remove(&tablet_pad->attach.link); - wl_list_remove(&tablet_pad->link); - - wl_list_remove(&tablet_pad->button.link); - wl_list_remove(&tablet_pad->strip.link); - wl_list_remove(&tablet_pad->ring.link); - free(tablet_pad); - - seat_update_capabilities(seat); -} - -static void handle_pad_tool_destroy(struct wl_listener *listener, void *data) { - struct roots_tablet_pad *pad = - wl_container_of(listener, pad, tablet_destroy); - - pad->tablet = NULL; - - wl_list_remove(&pad->tablet_destroy.link); - wl_list_init(&pad->tablet_destroy.link); -} - -static void attach_tablet_pad(struct roots_tablet_pad *pad, - struct roots_tablet *tool) { - wlr_log(WLR_DEBUG, "Attaching tablet pad \"%s\" to tablet tool \"%s\"", - pad->device->name, tool->device->name); - - pad->tablet = tool; - - wl_list_remove(&pad->tablet_destroy.link); - pad->tablet_destroy.notify = handle_pad_tool_destroy; - wl_signal_add(&tool->device->events.destroy, &pad->tablet_destroy); -} - -static void handle_tablet_pad_attach(struct wl_listener *listener, void *data) { - struct roots_tablet_pad *pad = - wl_container_of(listener, pad, attach); - struct wlr_tablet_tool *wlr_tool = data; - struct roots_tablet *tool = wlr_tool->data; - - attach_tablet_pad(pad, tool); -} - -static void handle_tablet_pad_ring(struct wl_listener *listener, void *data) { - struct roots_tablet_pad *pad = - wl_container_of(listener, pad, ring); - struct wlr_event_tablet_pad_ring *event = data; - - wlr_tablet_v2_tablet_pad_notify_ring(pad->tablet_v2_pad, - event->ring, event->position, - event->source == WLR_TABLET_PAD_RING_SOURCE_FINGER, - event->time_msec); -} - -static void handle_tablet_pad_strip(struct wl_listener *listener, void *data) { - struct roots_tablet_pad *pad = - wl_container_of(listener, pad, strip); - struct wlr_event_tablet_pad_strip *event = data; - - wlr_tablet_v2_tablet_pad_notify_strip(pad->tablet_v2_pad, - event->strip, event->position, - event->source == WLR_TABLET_PAD_STRIP_SOURCE_FINGER, - event->time_msec); -} - -static void handle_tablet_pad_button(struct wl_listener *listener, void *data) { - struct roots_tablet_pad *pad = - wl_container_of(listener, pad, button); - struct wlr_event_tablet_pad_button *event = data; - - wlr_tablet_v2_tablet_pad_notify_mode(pad->tablet_v2_pad, - event->group, event->mode, event->time_msec); - - wlr_tablet_v2_tablet_pad_notify_button(pad->tablet_v2_pad, - event->button, event->time_msec, - (enum zwp_tablet_pad_v2_button_state)event->state); -} - -static void seat_add_tablet_pad(struct roots_seat *seat, - struct wlr_input_device *device) { - struct roots_tablet_pad *tablet_pad = - calloc(1, sizeof(struct roots_tablet_pad)); - if (!tablet_pad) { - wlr_log(WLR_ERROR, "could not allocate tablet_pad for seat"); - return; - } - - device->data = tablet_pad; - tablet_pad->device = device; - tablet_pad->seat = seat; - wl_list_insert(&seat->tablet_pads, &tablet_pad->link); - - tablet_pad->device_destroy.notify = handle_tablet_pad_destroy; - wl_signal_add(&tablet_pad->device->events.destroy, - &tablet_pad->device_destroy); - - tablet_pad->attach.notify = handle_tablet_pad_attach; - wl_signal_add(&tablet_pad->device->tablet_pad->events.attach_tablet, - &tablet_pad->attach); - - tablet_pad->button.notify = handle_tablet_pad_button; - wl_signal_add(&tablet_pad->device->tablet_pad->events.button, &tablet_pad->button); - - tablet_pad->strip.notify = handle_tablet_pad_strip; - wl_signal_add(&tablet_pad->device->tablet_pad->events.strip, &tablet_pad->strip); - - tablet_pad->ring.notify = handle_tablet_pad_ring; - wl_signal_add(&tablet_pad->device->tablet_pad->events.ring, &tablet_pad->ring); - - wl_list_init(&tablet_pad->tablet_destroy.link); - - struct roots_desktop *desktop = seat->input->server->desktop; - tablet_pad->tablet_v2_pad = - wlr_tablet_pad_create(desktop->tablet_v2, seat->seat, device); - - /* Search for a sibling tablet */ - if (!wlr_input_device_is_libinput(device)) { - /* We can only do this on libinput devices */ - return; - } - - struct libinput_device_group *group = - libinput_device_get_device_group(wlr_libinput_get_device_handle(device)); - struct roots_tablet *tool; - wl_list_for_each(tool, &seat->tablets, link) { - if (!wlr_input_device_is_libinput(tool->device)) { - continue; - } - - struct libinput_device *li_dev = - wlr_libinput_get_device_handle(tool->device); - if (libinput_device_get_device_group(li_dev) == group) { - attach_tablet_pad(tablet_pad, tool); - break; - } - } -} - -static void handle_tablet_destroy(struct wl_listener *listener, - void *data) { - struct roots_tablet *tablet = - wl_container_of(listener, tablet, device_destroy); - struct roots_seat *seat = tablet->seat; - - wlr_cursor_detach_input_device(seat->cursor->cursor, tablet->device); - wl_list_remove(&tablet->device_destroy.link); - wl_list_remove(&tablet->link); - free(tablet); - - seat_update_capabilities(seat); -} - -static void seat_add_tablet_tool(struct roots_seat *seat, - struct wlr_input_device *device) { - struct roots_tablet *tablet = - calloc(1, sizeof(struct roots_tablet)); - if (!tablet) { - wlr_log(WLR_ERROR, "could not allocate tablet for seat"); - return; - } - - device->data = tablet; - tablet->device = device; - tablet->seat = seat; - wl_list_insert(&seat->tablets, &tablet->link); - - tablet->device_destroy.notify = handle_tablet_destroy; - wl_signal_add(&tablet->device->events.destroy, - &tablet->device_destroy); - - wlr_cursor_attach_input_device(seat->cursor->cursor, device); - roots_seat_configure_cursor(seat); - - struct roots_desktop *desktop = seat->input->server->desktop; - - tablet->tablet_v2 = - wlr_tablet_create(desktop->tablet_v2, seat->seat, device); - - struct libinput_device_group *group = - libinput_device_get_device_group(wlr_libinput_get_device_handle(device)); - struct roots_tablet_pad *pad; - wl_list_for_each(pad, &seat->tablet_pads, link) { - if (!wlr_input_device_is_libinput(pad->device)) { - continue; - } - - struct libinput_device *li_dev = - wlr_libinput_get_device_handle(pad->device); - if (libinput_device_get_device_group(li_dev) == group) { - attach_tablet_pad(pad, tablet); - } - } -} - -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_SWITCH: - seat_add_switch(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; - } - - seat_update_capabilities(seat); -} - -void roots_seat_configure_xcursor(struct roots_seat *seat) { - const char *cursor_theme = NULL; - struct roots_cursor_config *cc = - roots_config_get_cursor(seat->input->config, seat->seat->name); - if (cc != NULL) { - cursor_theme = cc->theme; - if (cc->default_image != NULL) { - seat->cursor->default_xcursor = cc->default_image; - } - } - - if (!seat->cursor->xcursor_manager) { - seat->cursor->xcursor_manager = - wlr_xcursor_manager_create(cursor_theme, ROOTS_XCURSOR_SIZE); - if (seat->cursor->xcursor_manager == NULL) { - wlr_log(WLR_ERROR, "Cannot create XCursor manager for theme %s", - cursor_theme); - return; - } - } - - struct roots_output *output; - wl_list_for_each(output, &seat->input->server->desktop->outputs, link) { - float scale = output->wlr_output->scale; - if (wlr_xcursor_manager_load(seat->cursor->xcursor_manager, scale)) { - wlr_log(WLR_ERROR, "Cannot load xcursor theme for output '%s' " - "with scale %f", output->wlr_output->name, scale); - } - } - - wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, - seat->cursor->default_xcursor, 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; -} - -struct roots_view *roots_seat_get_focus(struct roots_seat *seat) { - if (!seat->has_focus || wl_list_empty(&seat->views)) { - return NULL; - } - struct roots_seat_view *seat_view = - wl_container_of(seat->views.next, seat_view, link); - return seat_view->view; -} - -static void seat_view_destroy(struct roots_seat_view *seat_view) { - struct roots_seat *seat = seat_view->seat; - - if (seat_view->view == roots_seat_get_focus(seat)) { - seat->has_focus = false; - seat->cursor->mode = ROOTS_CURSOR_PASSTHROUGH; - } - - if (seat_view == seat->cursor->pointer_view) { - seat->cursor->pointer_view = NULL; - } - - wl_list_remove(&seat_view->view_unmap.link); - wl_list_remove(&seat_view->view_destroy.link); - wl_list_remove(&seat_view->link); - free(seat_view); - - // Focus first view - if (!wl_list_empty(&seat->views)) { - struct roots_seat_view *first_seat_view = wl_container_of( - seat->views.next, first_seat_view, link); - roots_seat_set_focus(seat, first_seat_view->view); - } -} - -static void seat_view_handle_unmap(struct wl_listener *listener, void *data) { - struct roots_seat_view *seat_view = - wl_container_of(listener, seat_view, view_unmap); - seat_view_destroy(seat_view); -} - -static void seat_view_handle_destroy(struct wl_listener *listener, void *data) { - struct roots_seat_view *seat_view = - wl_container_of(listener, seat_view, view_destroy); - seat_view_destroy(seat_view); -} - -static struct roots_seat_view *seat_add_view(struct roots_seat *seat, - struct roots_view *view) { - struct roots_seat_view *seat_view = - calloc(1, sizeof(struct roots_seat_view)); - if (seat_view == NULL) { - return NULL; - } - seat_view->seat = seat; - seat_view->view = view; - - wl_list_insert(seat->views.prev, &seat_view->link); - - seat_view->view_unmap.notify = seat_view_handle_unmap; - wl_signal_add(&view->events.unmap, &seat_view->view_unmap); - seat_view->view_destroy.notify = seat_view_handle_destroy; - wl_signal_add(&view->events.destroy, &seat_view->view_destroy); - - return seat_view; -} - -struct roots_seat_view *roots_seat_view_from_view( - struct roots_seat *seat, struct roots_view *view) { - if (view == NULL) { - return NULL; - } - - bool found = false; - struct roots_seat_view *seat_view = NULL; - wl_list_for_each(seat_view, &seat->views, link) { - if (seat_view->view == view) { - found = true; - break; - } - } - if (!found) { - seat_view = seat_add_view(seat, view); - if (seat_view == NULL) { - wlr_log(WLR_ERROR, "Allocation failed"); - return NULL; - } - } - - return seat_view; -} - -bool roots_seat_allow_input(struct roots_seat *seat, - struct wl_resource *resource) { - return !seat->exclusive_client || - wl_resource_get_client(resource) == seat->exclusive_client; -} - -void roots_seat_set_focus(struct roots_seat *seat, struct roots_view *view) { - if (view && !roots_seat_allow_input(seat, view->wlr_surface->resource)) { - return; - } - - // Make sure the view will be rendered on top of others, even if it's - // already focused in this seat - if (view != NULL) { - wl_list_remove(&view->link); - wl_list_insert(&seat->input->server->desktop->views, &view->link); - } - - bool unfullscreen = true; - -#if WLR_HAS_XWAYLAND - if (view && view->type == ROOTS_XWAYLAND_VIEW) { - struct roots_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view); - if (xwayland_surface->xwayland_surface->override_redirect) { - unfullscreen = false; - } - } -#endif - - if (view && unfullscreen) { - 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) { - if (output->fullscreen_view && - output->fullscreen_view != view && - wlr_output_layout_intersects( - desktop->layout, - output->wlr_output, &box)) { - view_set_fullscreen(output->fullscreen_view, - false, NULL); - } - } - } - - struct roots_view *prev_focus = roots_seat_get_focus(seat); - if (view == prev_focus) { - return; - } - -#if WLR_HAS_XWAYLAND - if (view && view->type == ROOTS_XWAYLAND_VIEW) { - struct roots_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view); - if (!wlr_xwayland_or_surface_wants_focus( - xwayland_surface->xwayland_surface)) { - return; - } - } -#endif - struct roots_seat_view *seat_view = NULL; - if (view != NULL) { - seat_view = roots_seat_view_from_view(seat, view); - if (seat_view == NULL) { - return; - } - } - - seat->has_focus = false; - - // Deactivate the old view if it is not focused by some other seat - if (prev_focus != NULL && !input_view_has_focus(seat->input, prev_focus)) { - view_activate(prev_focus, false); - } - - if (view == NULL) { - seat->cursor->mode = ROOTS_CURSOR_PASSTHROUGH; - wlr_seat_keyboard_clear_focus(seat->seat); - roots_input_method_relay_set_focus(&seat->im_relay, NULL); - return; - } - - wl_list_remove(&seat_view->link); - wl_list_insert(&seat->views, &seat_view->link); - - view_damage_whole(view); - - if (seat->focused_layer) { - return; - } - - view_activate(view, true); - seat->has_focus = true; - - // An existing keyboard grab might try to deny setting focus, so cancel it - wlr_seat_keyboard_end_grab(seat->seat); - - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->seat); - if (keyboard != NULL) { - wlr_seat_keyboard_notify_enter(seat->seat, view->wlr_surface, - keyboard->keycodes, keyboard->num_keycodes, - &keyboard->modifiers); - /* FIXME: Move this to a better place */ - struct roots_tablet_pad *pad; - wl_list_for_each(pad, &seat->tablet_pads, link) { - if (pad->tablet) { - wlr_tablet_v2_tablet_pad_notify_enter(pad->tablet_v2_pad, pad->tablet->tablet_v2, view->wlr_surface); - } - } - } else { - wlr_seat_keyboard_notify_enter(seat->seat, view->wlr_surface, - NULL, 0, NULL); - } - - if (seat->cursor) { - roots_cursor_update_focus(seat->cursor); - } - - roots_input_method_relay_set_focus(&seat->im_relay, view->wlr_surface); -} - -/** - * Focus semantics of layer surfaces are somewhat detached from the normal focus - * flow. For layers above the shell layer, for example, you cannot unfocus them. - * You also cannot alt-tab between layer surfaces and shell surfaces. - */ -void roots_seat_set_focus_layer(struct roots_seat *seat, - struct wlr_layer_surface_v1 *layer) { - if (!layer) { - if (seat->focused_layer) { - seat->focused_layer = NULL; - if (!wl_list_empty(&seat->views)) { - // Focus first view - struct roots_seat_view *first_seat_view = wl_container_of( - seat->views.next, first_seat_view, link); - roots_seat_set_focus(seat, first_seat_view->view); - } - } - return; - } - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->seat); - if (!roots_seat_allow_input(seat, layer->resource)) { - return; - } - if (seat->has_focus) { - struct roots_view *prev_focus = roots_seat_get_focus(seat); - wlr_seat_keyboard_clear_focus(seat->seat); - view_activate(prev_focus, false); - } - seat->has_focus = false; - if (layer->layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP) { - seat->focused_layer = layer; - } - if (keyboard != NULL) { - wlr_seat_keyboard_notify_enter(seat->seat, layer->surface, - keyboard->keycodes, keyboard->num_keycodes, - &keyboard->modifiers); - } else { - wlr_seat_keyboard_notify_enter(seat->seat, layer->surface, - NULL, 0, NULL); - } - - - if (seat->cursor) { - roots_cursor_update_focus(seat->cursor); - } -} - -void roots_seat_set_exclusive_client(struct roots_seat *seat, - struct wl_client *client) { - if (!client) { - seat->exclusive_client = client; - // Triggers a refocus of the topmost surface layer if necessary - // TODO: Make layer surface focus per-output based on cursor position - struct roots_output *output; - wl_list_for_each(output, &seat->input->server->desktop->outputs, link) { - arrange_layers(output); - } - return; - } - if (seat->focused_layer) { - if (wl_resource_get_client(seat->focused_layer->resource) != client) { - roots_seat_set_focus_layer(seat, NULL); - } - } - if (seat->has_focus) { - struct roots_view *focus = roots_seat_get_focus(seat); - if (wl_resource_get_client(focus->wlr_surface->resource) != client) { - roots_seat_set_focus(seat, NULL); - } - } - if (seat->seat->pointer_state.focused_client) { - if (seat->seat->pointer_state.focused_client->client != client) { - wlr_seat_pointer_clear_focus(seat->seat); - } - } - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - struct wlr_touch_point *point; - wl_list_for_each(point, &seat->seat->touch_state.touch_points, link) { - if (point->client->client != client) { - wlr_seat_touch_point_clear_focus(seat->seat, - now.tv_nsec / 1000, point->touch_id); - } - } - seat->exclusive_client = client; -} - -void roots_seat_cycle_focus(struct roots_seat *seat) { - if (wl_list_empty(&seat->views)) { - return; - } - - struct roots_seat_view *first_seat_view = wl_container_of( - seat->views.next, first_seat_view, link); - if (!seat->has_focus) { - roots_seat_set_focus(seat, first_seat_view->view); - return; - } - if (wl_list_length(&seat->views) < 2) { - return; - } - - // Focus the next view - struct roots_seat_view *next_seat_view = wl_container_of( - first_seat_view->link.next, next_seat_view, link); - roots_seat_set_focus(seat, next_seat_view->view); - - // Move the first view to the end of the list - wl_list_remove(&first_seat_view->link); - wl_list_insert(seat->views.prev, &first_seat_view->link); -} - -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->box.x; - cursor->view_y = view->box.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->box.x; - cursor->view_y = view->box.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); - - const char *resize_name = wlr_xcursor_get_resize_name(edges); - wlr_xcursor_manager_set_cursor_image(seat->cursor->xcursor_manager, - resize_name, 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); -} - -void roots_seat_end_compositor_grab(struct roots_seat *seat) { - struct roots_cursor *cursor = seat->cursor; - struct roots_view *view = roots_seat_get_focus(seat); - - if (view == NULL) { - return; - } - - switch(cursor->mode) { - case ROOTS_CURSOR_MOVE: - view_move(view, cursor->view_x, cursor->view_y); - break; - case ROOTS_CURSOR_RESIZE: - view_move_resize(view, cursor->view_x, cursor->view_y, cursor->view_width, cursor->view_height); - break; - case ROOTS_CURSOR_ROTATE: - view->rotation = cursor->view_rotation; - break; - case ROOTS_CURSOR_PASSTHROUGH: - break; - } - - cursor->mode = ROOTS_CURSOR_PASSTHROUGH; -} - -struct roots_seat *input_last_active_seat(struct roots_input *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; - } - } - return seat; -} diff --git a/rootston/switch.c b/rootston/switch.c deleted file mode 100644 index f95a8e07..00000000 --- a/rootston/switch.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include "rootston/bindings.h" - -void roots_switch_handle_toggle(struct roots_switch *switch_device, - struct wlr_event_switch_toggle *event) { - struct wl_list *bound_switches = - &switch_device->seat->input->server->config->switches; - struct roots_switch_config *sc; - wl_list_for_each(sc, bound_switches, link) { - if ((sc->name != NULL && strcmp(event->device->name, sc->name) != 0) && - (sc->name == NULL && event->switch_type != sc->switch_type)) { - continue; - } - if (sc->switch_state != WLR_SWITCH_STATE_TOGGLE && - event->switch_state != sc->switch_state) { - continue; - } - execute_binding_command(switch_device->seat, - switch_device->seat->input, sc->command); - } -} diff --git a/rootston/text_input.c b/rootston/text_input.c deleted file mode 100644 index dcd81104..00000000 --- a/rootston/text_input.c +++ /dev/null @@ -1,312 +0,0 @@ -#include -#include -#include -#include "rootston/seat.h" -#include "rootston/text_input.h" - -static struct roots_text_input *relay_get_focusable_text_input( - struct roots_input_method_relay *relay) { - struct roots_text_input *text_input = NULL; - wl_list_for_each(text_input, &relay->text_inputs, link) { - if (text_input->pending_focused_surface) { - return text_input; - } - } - return NULL; -} - -static struct roots_text_input *relay_get_focused_text_input( - struct roots_input_method_relay *relay) { - struct roots_text_input *text_input = NULL; - wl_list_for_each(text_input, &relay->text_inputs, link) { - if (text_input->input->focused_surface) { - return text_input; - } - } - return NULL; -} - -static void handle_im_commit(struct wl_listener *listener, void *data) { - struct roots_input_method_relay *relay = wl_container_of(listener, relay, - input_method_commit); - - struct roots_text_input *text_input = relay_get_focused_text_input(relay); - if (!text_input) { - return; - } - struct wlr_input_method_v2 *context = data; - assert(context == relay->input_method); - if (context->current.preedit.text) { - wlr_text_input_v3_send_preedit_string(text_input->input, - context->current.preedit.text, - context->current.preedit.cursor_begin, - context->current.preedit.cursor_end); - } - if (context->current.commit_text) { - wlr_text_input_v3_send_commit_string(text_input->input, - context->current.commit_text); - } - if (context->current.delete.before_length - || context->current.delete.after_length) { - wlr_text_input_v3_send_delete_surrounding_text(text_input->input, - context->current.delete.before_length, - context->current.delete.after_length); - } - wlr_text_input_v3_send_done(text_input->input); -} - -static void text_input_set_pending_focused_surface( - struct roots_text_input *text_input, struct wlr_surface *surface) { - text_input->pending_focused_surface = surface; - wl_signal_add(&surface->events.destroy, - &text_input->pending_focused_surface_destroy); -} - -static void text_input_clear_pending_focused_surface( - struct roots_text_input *text_input) { - wl_list_remove(&text_input->pending_focused_surface_destroy.link); - wl_list_init(&text_input->pending_focused_surface_destroy.link); - text_input->pending_focused_surface = NULL; -} - -static void handle_im_destroy(struct wl_listener *listener, void *data) { - struct roots_input_method_relay *relay = wl_container_of(listener, relay, - input_method_destroy); - struct wlr_input_method_v2 *context = data; - assert(context == relay->input_method); - relay->input_method = NULL; - struct roots_text_input *text_input = relay_get_focused_text_input(relay); - if (text_input) { - // keyboard focus is still there, so keep the surface at hand in case - // the input method returns - text_input_set_pending_focused_surface(text_input, - text_input->input->focused_surface); - wlr_text_input_v3_send_leave(text_input->input); - } -} - -static void relay_send_im_done(struct roots_input_method_relay *relay, - struct wlr_text_input_v3 *input) { - struct wlr_input_method_v2 *input_method = relay->input_method; - if (!input_method) { - wlr_log(WLR_INFO, "Sending IM_DONE but im is gone"); - return; - } - // TODO: only send each of those if they were modified - wlr_input_method_v2_send_surrounding_text(input_method, - input->current.surrounding.text, input->current.surrounding.cursor, - input->current.surrounding.anchor); - wlr_input_method_v2_send_text_change_cause(input_method, - input->current.text_change_cause); - wlr_input_method_v2_send_content_type(input_method, - input->current.content_type.hint, input->current.content_type.purpose); - wlr_input_method_v2_send_done(input_method); - // TODO: pass intent, display popup size -} - -static struct roots_text_input *text_input_to_roots( - struct roots_input_method_relay *relay, - struct wlr_text_input_v3 *text_input) { - struct roots_text_input *roots_text_input = NULL; - wl_list_for_each(roots_text_input, &relay->text_inputs, link) { - if (roots_text_input->input == text_input) { - return roots_text_input; - } - } - return NULL; -} - -static void handle_text_input_enable(struct wl_listener *listener, void *data) { - struct roots_input_method_relay *relay = wl_container_of(listener, relay, - text_input_enable); - if (relay->input_method == NULL) { - wlr_log(WLR_INFO, "Enabling text input when input method is gone"); - return; - } - struct roots_text_input *text_input = text_input_to_roots(relay, - (struct wlr_text_input_v3*)data); - wlr_input_method_v2_send_activate(relay->input_method); - relay_send_im_done(relay, text_input->input); -} - -static void handle_text_input_commit(struct wl_listener *listener, - void *data) { - struct roots_input_method_relay *relay = wl_container_of(listener, relay, - text_input_commit); - struct roots_text_input *text_input = text_input_to_roots(relay, - (struct wlr_text_input_v3*)data); - if (!text_input->input->current_enabled) { - wlr_log(WLR_INFO, "Inactive text input tried to commit an update"); - return; - } - wlr_log(WLR_DEBUG, "Text input committed update"); - if (relay->input_method == NULL) { - wlr_log(WLR_INFO, "Text input committed, but input method is gone"); - return; - } - relay_send_im_done(relay, text_input->input); -} - -static void relay_disable_text_input(struct roots_input_method_relay *relay, - struct roots_text_input *text_input) { - if (relay->input_method == NULL) { - wlr_log(WLR_DEBUG, "Disabling text input, but input method is gone"); - return; - } - wlr_input_method_v2_send_deactivate(relay->input_method); - relay_send_im_done(relay, text_input->input); -} - -static void handle_text_input_disable(struct wl_listener *listener, - void *data) { - struct roots_input_method_relay *relay = wl_container_of(listener, relay, - text_input_disable); - struct roots_text_input *text_input = text_input_to_roots(relay, - (struct wlr_text_input_v3*)data); - relay_disable_text_input(relay, text_input); -} - -static void handle_text_input_destroy(struct wl_listener *listener, - void *data) { - struct roots_input_method_relay *relay = wl_container_of(listener, relay, - text_input_destroy); - struct roots_text_input *text_input = text_input_to_roots(relay, - (struct wlr_text_input_v3*)data); - - if (text_input->input->current_enabled) { - relay_disable_text_input(relay, text_input); - } - text_input_clear_pending_focused_surface(text_input); - wl_list_remove(&text_input->link); - text_input->input = NULL; - free(text_input); -} - -static void handle_pending_focused_surface_destroy(struct wl_listener *listener, - void *data) { - struct roots_text_input *text_input = wl_container_of(listener, text_input, - pending_focused_surface_destroy); - struct wlr_surface *surface = data; - assert(text_input->pending_focused_surface == surface); - text_input->pending_focused_surface = NULL; -} - -struct roots_text_input *roots_text_input_create( - struct roots_input_method_relay *relay, - struct wlr_text_input_v3 *text_input) { - struct roots_text_input *input = calloc(1, sizeof(struct roots_text_input)); - if (!input) { - return NULL; - } - input->input = text_input; - input->relay = relay; - - wl_signal_add(&text_input->events.enable, &relay->text_input_enable); - relay->text_input_enable.notify = handle_text_input_enable; - - wl_signal_add(&text_input->events.commit, &relay->text_input_commit); - relay->text_input_commit.notify = handle_text_input_commit; - - wl_signal_add(&text_input->events.disable, &relay->text_input_disable); - relay->text_input_disable.notify = handle_text_input_disable; - - wl_signal_add(&text_input->events.destroy, &relay->text_input_destroy); - relay->text_input_destroy.notify = handle_text_input_destroy; - - input->pending_focused_surface_destroy.notify = - handle_pending_focused_surface_destroy; - wl_list_init(&input->pending_focused_surface_destroy.link); - return input; -} - -static void relay_handle_text_input(struct wl_listener *listener, - void *data) { - struct roots_input_method_relay *relay = wl_container_of(listener, relay, - text_input_new); - struct wlr_text_input_v3 *wlr_text_input = data; - if (relay->seat->seat != wlr_text_input->seat) { - return; - } - - struct roots_text_input *text_input = roots_text_input_create(relay, - wlr_text_input); - if (!text_input) { - return; - } - wl_list_insert(&relay->text_inputs, &text_input->link); -} - -static void relay_handle_input_method(struct wl_listener *listener, - void *data) { - struct roots_input_method_relay *relay = wl_container_of(listener, relay, - input_method_new); - struct wlr_input_method_v2 *input_method = data; - if (relay->seat->seat != input_method->seat) { - return; - } - - if (relay->input_method != NULL) { - wlr_log(WLR_INFO, "Attempted to connect second input method to a seat"); - wlr_input_method_v2_send_unavailable(input_method); - return; - } - - relay->input_method = input_method; - wl_signal_add(&relay->input_method->events.commit, - &relay->input_method_commit); - relay->input_method_commit.notify = handle_im_commit; - wl_signal_add(&relay->input_method->events.destroy, - &relay->input_method_destroy); - relay->input_method_destroy.notify = handle_im_destroy; - - struct roots_text_input *text_input = relay_get_focusable_text_input(relay); - if (text_input) { - wlr_text_input_v3_send_enter(text_input->input, - text_input->pending_focused_surface); - text_input_clear_pending_focused_surface(text_input); - } -} - -void roots_input_method_relay_init(struct roots_seat *seat, - struct roots_input_method_relay *relay) { - relay->seat = seat; - wl_list_init(&relay->text_inputs); - - relay->text_input_new.notify = relay_handle_text_input; - wl_signal_add(&seat->input->server->desktop->text_input->events.text_input, - &relay->text_input_new); - - relay->input_method_new.notify = relay_handle_input_method; - wl_signal_add( - &seat->input->server->desktop->input_method->events.input_method, - &relay->input_method_new); -} - -void roots_input_method_relay_set_focus(struct roots_input_method_relay *relay, - struct wlr_surface *surface) { - struct roots_text_input *text_input; - wl_list_for_each(text_input, &relay->text_inputs, link) { - if (text_input->pending_focused_surface) { - assert(text_input->input->focused_surface == NULL); - if (surface != text_input->pending_focused_surface) { - text_input_clear_pending_focused_surface(text_input); - } - } else if (text_input->input->focused_surface) { - assert(text_input->pending_focused_surface == NULL); - if (surface != text_input->input->focused_surface) { - relay_disable_text_input(relay, text_input); - wlr_text_input_v3_send_leave(text_input->input); - } - } - - if (surface - && wl_resource_get_client(text_input->input->resource) - == wl_resource_get_client(surface->resource)) { - if (relay->input_method) { - wlr_text_input_v3_send_enter(text_input->input, surface); - } else { - text_input_set_pending_focused_surface(text_input, surface); - } - } - } -} diff --git a/rootston/view.c b/rootston/view.c deleted file mode 100644 index 6619743a..00000000 --- a/rootston/view.c +++ /dev/null @@ -1,685 +0,0 @@ -#include -#include -#include -#include -#include "rootston/desktop.h" -#include "rootston/input.h" -#include "rootston/seat.h" -#include "rootston/server.h" -#include "rootston/view.h" - -void view_init(struct roots_view *view, const struct roots_view_interface *impl, - enum roots_view_type type, struct roots_desktop *desktop) { - assert(impl->destroy); - view->impl = impl; - view->type = type; - view->desktop = desktop; - view->alpha = 1.0f; - wl_signal_init(&view->events.unmap); - wl_signal_init(&view->events.destroy); - wl_list_init(&view->children); -} - -void view_destroy(struct roots_view *view) { - if (view == NULL) { - return; - } - - wl_signal_emit(&view->events.destroy, view); - - if (view->wlr_surface != NULL) { - view_unmap(view); - } - - // Can happen if fullscreened while unmapped, and hasn't been mapped - if (view->fullscreen_output != NULL) { - view->fullscreen_output->fullscreen_view = NULL; - } - - view->impl->destroy(view); -} - -void view_get_box(const struct roots_view *view, struct wlr_box *box) { - box->x = view->box.x; - box->y = view->box.y; - box->width = view->box.width; - box->height = view->box.height; -} - -void view_get_deco_box(const struct roots_view *view, struct wlr_box *box) { - view_get_box(view, box); - if (!view->decorated) { - return; - } - - box->x -= view->border_width; - box->y -= (view->border_width + view->titlebar_height); - box->width += view->border_width * 2; - box->height += (view->border_width * 2 + view->titlebar_height); -} - -enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, - double sy) { - if (!view->decorated) { - return ROOTS_DECO_PART_NONE; - } - - int sw = view->wlr_surface->current.width; - int sh = view->wlr_surface->current.height; - int bw = view->border_width; - int titlebar_h = view->titlebar_height; - - if (sx > 0 && sx < sw && sy < 0 && sy > -view->titlebar_height) { - return ROOTS_DECO_PART_TITLEBAR; - } - - enum roots_deco_part parts = 0; - if (sy >= -(titlebar_h + bw) && - sy <= sh + bw) { - if (sx < 0 && sx > -bw) { - parts |= ROOTS_DECO_PART_LEFT_BORDER; - } else if (sx > sw && sx < sw + bw) { - parts |= ROOTS_DECO_PART_RIGHT_BORDER; - } - } - - if (sx >= -bw && sx <= sw + bw) { - if (sy > sh && sy <= sh + bw) { - parts |= ROOTS_DECO_PART_BOTTOM_BORDER; - } else if (sy >= -(titlebar_h + bw) && sy < 0) { - parts |= ROOTS_DECO_PART_TOP_BORDER; - } - } - - // TODO corners - - return parts; -} - -static void view_update_output(const struct roots_view *view, - const struct wlr_box *before) { - struct roots_desktop *desktop = view->desktop; - - if (view->wlr_surface == NULL) { - return; - } - - struct wlr_box box; - view_get_box(view, &box); - - struct roots_output *output; - wl_list_for_each(output, &desktop->outputs, link) { - bool intersected = before != NULL && wlr_output_layout_intersects( - desktop->layout, output->wlr_output, before); - bool intersects = wlr_output_layout_intersects(desktop->layout, - output->wlr_output, &box); - if (intersected && !intersects) { - wlr_surface_send_leave(view->wlr_surface, output->wlr_output); - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_output_leave( - view->toplevel_handle, output->wlr_output); - } - } - if (!intersected && intersects) { - wlr_surface_send_enter(view->wlr_surface, output->wlr_output); - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_output_enter( - view->toplevel_handle, output->wlr_output); - } - } - } -} - -void view_move(struct roots_view *view, double x, double y) { - if (view->box.x == x && view->box.y == y) { - return; - } - - struct wlr_box before; - view_get_box(view, &before); - if (view->impl->move) { - view->impl->move(view, x, y); - } else { - view_update_position(view, x, y); - } - view_update_output(view, &before); -} - -void view_activate(struct roots_view *view, bool activate) { - if (view->impl->activate) { - view->impl->activate(view, activate); - } - - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_set_activated(view->toplevel_handle, - activate); - } -} - -void view_resize(struct roots_view *view, uint32_t width, uint32_t height) { - struct wlr_box before; - view_get_box(view, &before); - if (view->impl->resize) { - view->impl->resize(view, width, height); - } - view_update_output(view, &before); -} - -void view_move_resize(struct roots_view *view, double x, double y, - uint32_t width, uint32_t height) { - bool update_x = x != view->box.x; - bool update_y = y != view->box.y; - if (!update_x && !update_y) { - view_resize(view, width, height); - return; - } - - if (view->impl->move_resize) { - view->impl->move_resize(view, x, y, width, height); - return; - } - - view->pending_move_resize.update_x = update_x; - view->pending_move_resize.update_y = update_y; - view->pending_move_resize.x = x; - view->pending_move_resize.y = y; - view->pending_move_resize.width = width; - view->pending_move_resize.height = height; - - view_resize(view, width, height); -} - -static struct wlr_output *view_get_output(struct roots_view *view) { - struct wlr_box view_box; - view_get_box(view, &view_box); - - double output_x, output_y; - wlr_output_layout_closest_point(view->desktop->layout, NULL, - view->box.x + (double)view_box.width/2, - view->box.y + (double)view_box.height/2, - &output_x, &output_y); - return wlr_output_layout_output_at(view->desktop->layout, output_x, - output_y); -} - -void view_arrange_maximized(struct roots_view *view) { - if (view->fullscreen_output != NULL) { - return; - } - - struct wlr_box view_box; - view_get_box(view, &view_box); - - struct wlr_output *output = view_get_output(view); - struct roots_output *roots_output = output->data; - struct wlr_box *output_box = - wlr_output_layout_get_box(view->desktop->layout, output); - struct wlr_box usable_area; - memcpy(&usable_area, &roots_output->usable_area, - sizeof(struct wlr_box)); - usable_area.x += output_box->x; - usable_area.y += output_box->y; - - view_move_resize(view, usable_area.x, usable_area.y, - usable_area.width, usable_area.height); - view_rotate(view, 0); -} - -void view_maximize(struct roots_view *view, bool maximized) { - if (view->maximized == maximized || view->fullscreen_output != NULL) { - return; - } - - if (view->impl->maximize) { - view->impl->maximize(view, maximized); - } - - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_set_maximized(view->toplevel_handle, - maximized); - } - - if (!view->maximized && maximized) { - view->maximized = true; - view->saved.x = view->box.x; - view->saved.y = view->box.y; - view->saved.rotation = view->rotation; - view->saved.width = view->box.width; - view->saved.height = view->box.height; - - view_arrange_maximized(view); - } - - if (view->maximized && !maximized) { - view->maximized = false; - - view_move_resize(view, view->saved.x, view->saved.y, view->saved.width, - view->saved.height); - view_rotate(view, view->saved.rotation); - } -} - -void view_set_fullscreen(struct roots_view *view, bool fullscreen, - struct wlr_output *output) { - bool was_fullscreen = view->fullscreen_output != NULL; - if (was_fullscreen == fullscreen) { - // TODO: support changing the output? - return; - } - - // TODO: check if client is focused? - - if (view->impl->set_fullscreen) { - view->impl->set_fullscreen(view, fullscreen); - } - - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_set_fullscreen(view->toplevel_handle, - fullscreen); - } - - if (!was_fullscreen && fullscreen) { - if (output == NULL) { - output = view_get_output(view); - } - struct roots_output *roots_output = - desktop_output_from_wlr_output(view->desktop, output); - if (roots_output == NULL) { - return; - } - - struct wlr_box view_box; - view_get_box(view, &view_box); - - view->saved.x = view->box.x; - view->saved.y = view->box.y; - view->saved.rotation = view->rotation; - view->saved.width = view_box.width; - view->saved.height = view_box.height; - - 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_rotate(view, 0); - - roots_output->fullscreen_view = view; - view->fullscreen_output = roots_output; - output_damage_whole(roots_output); - } - - if (was_fullscreen && !fullscreen) { - view_move_resize(view, view->saved.x, view->saved.y, view->saved.width, - view->saved.height); - view_rotate(view, view->saved.rotation); - - output_damage_whole(view->fullscreen_output); - view->fullscreen_output->fullscreen_view = NULL; - view->fullscreen_output = NULL; - } -} - -void view_rotate(struct roots_view *view, float rotation) { - if (view->rotation == rotation) { - return; - } - - view_damage_whole(view); - view->rotation = rotation; - view_damage_whole(view); -} - -void view_cycle_alpha(struct roots_view *view) { - view->alpha -= 0.05; - /* Don't go completely transparent */ - if (view->alpha < 0.1) { - view->alpha = 1.0; - } - view_damage_whole(view); -} - -void view_close(struct roots_view *view) { - if (view->impl->close) { - view->impl->close(view); - } -} - -bool view_center(struct roots_view *view) { - struct wlr_box box; - view_get_box(view, &box); - - struct roots_desktop *desktop = view->desktop; - struct roots_input *input = desktop->server->input; - struct roots_seat *seat = input_last_active_seat(input); - 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; - } - - const struct wlr_output_layout_output *l_output = - wlr_output_layout_get(desktop->layout, output); - - int width, height; - wlr_output_effective_resolution(output, &width, &height); - - 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_child_destroy(struct roots_view_child *child) { - if (child == NULL) { - return; - } - view_damage_whole(child->view); - wl_list_remove(&child->link); - wl_list_remove(&child->commit.link); - wl_list_remove(&child->new_subsurface.link); - child->impl->destroy(child); -} - -static void view_child_handle_commit(struct wl_listener *listener, - void *data) { - struct roots_view_child *child = wl_container_of(listener, child, commit); - view_apply_damage(child->view); -} - -static void view_child_handle_new_subsurface(struct wl_listener *listener, - void *data) { - struct roots_view_child *child = - wl_container_of(listener, child, new_subsurface); - struct wlr_subsurface *wlr_subsurface = data; - subsurface_create(child->view, wlr_subsurface); -} - -void view_child_init(struct roots_view_child *child, - const struct roots_view_child_interface *impl, struct roots_view *view, - struct wlr_surface *wlr_surface) { - assert(impl->destroy); - child->impl = impl; - child->view = view; - child->wlr_surface = wlr_surface; - child->commit.notify = view_child_handle_commit; - wl_signal_add(&wlr_surface->events.commit, &child->commit); - child->new_subsurface.notify = view_child_handle_new_subsurface; - wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface); - wl_list_insert(&view->children, &child->link); -} - -static const struct roots_view_child_interface subsurface_impl; - -static void subsurface_destroy(struct roots_view_child *child) { - assert(child->impl == &subsurface_impl); - struct roots_subsurface *subsurface = (struct roots_subsurface *)child; - wl_list_remove(&subsurface->destroy.link); - wl_list_remove(&subsurface->map.link); - wl_list_remove(&subsurface->unmap.link); - free(subsurface); -} - -static const struct roots_view_child_interface subsurface_impl = { - .destroy = subsurface_destroy, -}; - -static void subsurface_handle_destroy(struct wl_listener *listener, - void *data) { - struct roots_subsurface *subsurface = - wl_container_of(listener, subsurface, destroy); - view_child_destroy(&subsurface->view_child); -} - -static void subsurface_handle_map(struct wl_listener *listener, - void *data) { - struct roots_subsurface *subsurface = - wl_container_of(listener, subsurface, map); - struct roots_view *view = subsurface->view_child.view; - view_damage_whole(view); - input_update_cursor_focus(view->desktop->server->input); -} - -static void subsurface_handle_unmap(struct wl_listener *listener, - void *data) { - struct roots_subsurface *subsurface = - wl_container_of(listener, subsurface, unmap); - struct roots_view *view = subsurface->view_child.view; - view_damage_whole(view); - input_update_cursor_focus(view->desktop->server->input); -} - -struct roots_subsurface *subsurface_create(struct roots_view *view, - struct wlr_subsurface *wlr_subsurface) { - struct roots_subsurface *subsurface = - calloc(1, sizeof(struct roots_subsurface)); - if (subsurface == NULL) { - return NULL; - } - subsurface->wlr_subsurface = wlr_subsurface; - view_child_init(&subsurface->view_child, &subsurface_impl, - view, wlr_subsurface->surface); - subsurface->destroy.notify = subsurface_handle_destroy; - wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); - subsurface->map.notify = subsurface_handle_map; - wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); - subsurface->unmap.notify = subsurface_handle_unmap; - wl_signal_add(&wlr_subsurface->events.unmap, &subsurface->unmap); - return subsurface; -} - -static void view_handle_new_subsurface(struct wl_listener *listener, - void *data) { - struct roots_view *view = wl_container_of(listener, view, new_subsurface); - struct wlr_subsurface *wlr_subsurface = data; - subsurface_create(view, wlr_subsurface); -} - -void view_map(struct roots_view *view, struct wlr_surface *surface) { - assert(view->wlr_surface == NULL); - - view->wlr_surface = surface; - - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &view->wlr_surface->subsurfaces, - parent_link) { - subsurface_create(view, subsurface); - } - - view->new_subsurface.notify = view_handle_new_subsurface; - wl_signal_add(&view->wlr_surface->events.new_subsurface, - &view->new_subsurface); - - wl_list_insert(&view->desktop->views, &view->link); - view_damage_whole(view); - input_update_cursor_focus(view->desktop->server->input); -} - -void view_unmap(struct roots_view *view) { - assert(view->wlr_surface != NULL); - - wl_signal_emit(&view->events.unmap, view); - - view_damage_whole(view); - wl_list_remove(&view->link); - - wl_list_remove(&view->new_subsurface.link); - - struct roots_view_child *child, *tmp; - wl_list_for_each_safe(child, tmp, &view->children, link) { - view_child_destroy(child); - } - - if (view->fullscreen_output != NULL) { - output_damage_whole(view->fullscreen_output); - view->fullscreen_output->fullscreen_view = NULL; - view->fullscreen_output = NULL; - } - - view->wlr_surface = NULL; - view->box.width = view->box.height = 0; - - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_destroy(view->toplevel_handle); - view->toplevel_handle = NULL; - } -} - -void view_initial_focus(struct roots_view *view) { - struct roots_input *input = view->desktop->server->input; - // 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_set_focus(seat, view); - } -} - -void view_setup(struct roots_view *view) { - view_initial_focus(view); - - if (view->fullscreen_output == NULL && !view->maximized) { - view_center(view); - } - - view_create_foreign_toplevel_handle(view); - view_update_output(view, NULL); -} - -void view_apply_damage(struct roots_view *view) { - struct roots_output *output; - wl_list_for_each(output, &view->desktop->outputs, link) { - output_damage_from_view(output, view); - } -} - -void view_damage_whole(struct roots_view *view) { - struct roots_output *output; - wl_list_for_each(output, &view->desktop->outputs, link) { - output_damage_whole_view(output, view); - } -} - -void view_for_each_surface(struct roots_view *view, - wlr_surface_iterator_func_t iterator, void *user_data) { - if (view->impl->for_each_surface) { - view->impl->for_each_surface(view, iterator, user_data); - } else if (view->wlr_surface) { - wlr_surface_for_each_surface(view->wlr_surface, iterator, user_data); - } -} - -void view_update_position(struct roots_view *view, int x, int y) { - if (view->box.x == x && view->box.y == y) { - return; - } - - view_damage_whole(view); - view->box.x = x; - view->box.y = y; - view_damage_whole(view); -} - -void view_update_size(struct roots_view *view, int width, int height) { - if (view->box.width == width && view->box.height == height) { - return; - } - - view_damage_whole(view); - view->box.width = width; - view->box.height = height; - view_damage_whole(view); -} - -void view_update_decorated(struct roots_view *view, bool decorated) { - if (view->decorated == decorated) { - return; - } - - view_damage_whole(view); - view->decorated = decorated; - if (decorated) { - view->border_width = 4; - view->titlebar_height = 12; - } else { - view->border_width = 0; - view->titlebar_height = 0; - } - view_damage_whole(view); -} - -void view_set_title(struct roots_view *view, const char *title) { - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, title); - } -} - -void view_set_app_id(struct roots_view *view, const char *app_id) { - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, app_id); - } -} - -static void handle_toplevel_handle_request_maximize(struct wl_listener *listener, - void *data) { - struct roots_view *view = wl_container_of(listener, view, - toplevel_handle_request_maximize); - struct wlr_foreign_toplevel_handle_v1_maximized_event *event = data; - view_maximize(view, event->maximized); -} - -static void handle_toplevel_handle_request_activate(struct wl_listener *listener, - void *data) { - struct roots_view *view = - wl_container_of(listener, view, toplevel_handle_request_activate); - struct wlr_foreign_toplevel_handle_v1_activated_event *event = data; - - struct roots_seat *seat; - wl_list_for_each(seat, &view->desktop->server->input->seats, link) { - if (event->seat == seat->seat) { - roots_seat_set_focus(seat, view); - } - } -} - -static void handle_toplevel_handle_request_fullscreen(struct wl_listener *listener, - void *data) { - struct roots_view *view = - wl_container_of(listener, view, toplevel_handle_request_fullscreen); - struct wlr_foreign_toplevel_handle_v1_fullscreen_event *event = data; - view_set_fullscreen(view, event->fullscreen, event->output); -} - -static void handle_toplevel_handle_request_close(struct wl_listener *listener, - void *data) { - struct roots_view *view = - wl_container_of(listener, view, toplevel_handle_request_close); - view_close(view); -} - -void view_create_foreign_toplevel_handle(struct roots_view *view) { - view->toplevel_handle = - wlr_foreign_toplevel_handle_v1_create( - view->desktop->foreign_toplevel_manager_v1); - - view->toplevel_handle_request_maximize.notify = - handle_toplevel_handle_request_maximize; - wl_signal_add(&view->toplevel_handle->events.request_maximize, - &view->toplevel_handle_request_maximize); - view->toplevel_handle_request_activate.notify = - handle_toplevel_handle_request_activate; - wl_signal_add(&view->toplevel_handle->events.request_activate, - &view->toplevel_handle_request_activate); - view->toplevel_handle_request_fullscreen.notify = - handle_toplevel_handle_request_fullscreen; - wl_signal_add(&view->toplevel_handle->events.request_fullscreen, - &view->toplevel_handle_request_fullscreen); - view->toplevel_handle_request_close.notify = - handle_toplevel_handle_request_close; - wl_signal_add(&view->toplevel_handle->events.request_close, - &view->toplevel_handle_request_close); -} diff --git a/rootston/virtual_keyboard.c b/rootston/virtual_keyboard.c deleted file mode 100644 index e862caf4..00000000 --- a/rootston/virtual_keyboard.c +++ /dev/null @@ -1,21 +0,0 @@ -#define _POSIX_C_SOURCE 199309L - -#include -#include -#include "rootston/virtual_keyboard.h" -#include "rootston/seat.h" - -void handle_virtual_keyboard(struct wl_listener *listener, void *data) { - struct roots_desktop *desktop = - wl_container_of(listener, desktop, virtual_keyboard_new); - struct wlr_virtual_keyboard_v1 *keyboard = data; - - struct roots_seat *seat = input_seat_from_wlr_seat(desktop->server->input, - keyboard->seat); - if (!seat) { - wlr_log(WLR_ERROR, "could not find roots seat"); - return; - } - - roots_seat_add_device(seat, &keyboard->input_device); -} diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c deleted file mode 100644 index 7b565392..00000000 --- a/rootston/xdg_shell.c +++ /dev/null @@ -1,572 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/cursor.h" -#include "rootston/desktop.h" -#include "rootston/input.h" -#include "rootston/server.h" -#include "rootston/view.h" - -static const struct roots_view_child_interface popup_impl; - -static void popup_destroy(struct roots_view_child *child) { - assert(child->impl == &popup_impl); - struct roots_xdg_popup *popup = (struct roots_xdg_popup *)child; - wl_list_remove(&popup->destroy.link); - wl_list_remove(&popup->new_popup.link); - wl_list_remove(&popup->map.link); - wl_list_remove(&popup->unmap.link); - free(popup); -} - -static const struct roots_view_child_interface popup_impl = { - .destroy = popup_destroy, -}; - -static void popup_handle_destroy(struct wl_listener *listener, void *data) { - struct roots_xdg_popup *popup = - wl_container_of(listener, popup, destroy); - view_child_destroy(&popup->view_child); -} - -static void popup_handle_map(struct wl_listener *listener, void *data) { - struct roots_xdg_popup *popup = wl_container_of(listener, popup, map); - view_damage_whole(popup->view_child.view); - input_update_cursor_focus(popup->view_child.view->desktop->server->input); -} - -static void popup_handle_unmap(struct wl_listener *listener, void *data) { - struct roots_xdg_popup *popup = wl_container_of(listener, popup, unmap); - view_damage_whole(popup->view_child.view); -} - -static struct roots_xdg_popup *popup_create(struct roots_view *view, - struct wlr_xdg_popup *wlr_popup); - -static void popup_handle_new_popup(struct wl_listener *listener, void *data) { - struct roots_xdg_popup *popup = - wl_container_of(listener, popup, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - popup_create(popup->view_child.view, wlr_popup); -} - -static void popup_unconstrain(struct roots_xdg_popup *popup) { - // get the output of the popup's positioner anchor point and convert it to - // the toplevel parent's coordinate system and then pass it to - // wlr_xdg_popup_v6_unconstrain_from_box - - // TODO: unconstrain popups for rotated windows - if (popup->view_child.view->rotation != 0.0) { - return; - } - - struct roots_view *view = popup->view_child.view; - struct wlr_output_layout *layout = view->desktop->layout; - struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; - - int anchor_lx, anchor_ly; - wlr_xdg_popup_get_anchor_point(wlr_popup, &anchor_lx, &anchor_ly); - - int popup_lx, popup_ly; - wlr_xdg_popup_get_toplevel_coords(wlr_popup, wlr_popup->geometry.x, - wlr_popup->geometry.y, &popup_lx, &popup_ly); - popup_lx += view->box.x; - popup_ly += view->box.y; - - anchor_lx += popup_lx; - anchor_ly += popup_ly; - - double dest_x = 0, dest_y = 0; - wlr_output_layout_closest_point(layout, NULL, anchor_lx, anchor_ly, - &dest_x, &dest_y); - - struct wlr_output *output = - wlr_output_layout_output_at(layout, dest_x, dest_y); - if (output == NULL) { - return; - } - - struct wlr_box *output_box = - wlr_output_layout_get_box(view->desktop->layout, output); - - // the output box expressed in the coordinate system of the toplevel parent - // of the popup - struct wlr_box output_toplevel_sx_box = { - .x = output_box->x - view->box.x, - .y = output_box->y - view->box.y, - .width = output_box->width, - .height = output_box->height, - }; - - wlr_xdg_popup_unconstrain_from_box( - popup->wlr_popup, &output_toplevel_sx_box); -} - -static struct roots_xdg_popup *popup_create(struct roots_view *view, - struct wlr_xdg_popup *wlr_popup) { - struct roots_xdg_popup *popup = - calloc(1, sizeof(struct roots_xdg_popup)); - if (popup == NULL) { - return NULL; - } - popup->wlr_popup = wlr_popup; - view_child_init(&popup->view_child, &popup_impl, - view, wlr_popup->base->surface); - popup->destroy.notify = popup_handle_destroy; - wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); - popup->map.notify = popup_handle_map; - wl_signal_add(&wlr_popup->base->events.map, &popup->map); - popup->unmap.notify = popup_handle_unmap; - wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap); - popup->new_popup.notify = popup_handle_new_popup; - wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); - - popup_unconstrain(popup); - - return popup; -} - - -static void get_size(struct roots_view *view, struct wlr_box *box) { - struct wlr_xdg_surface *xdg_surface = - roots_xdg_surface_from_view(view)->xdg_surface; - - struct wlr_box geo_box; - wlr_xdg_surface_get_geometry(xdg_surface, &geo_box); - box->width = geo_box.width; - box->height = geo_box.height; -} - -static void activate(struct roots_view *view, bool active) { - struct wlr_xdg_surface *xdg_surface = - roots_xdg_surface_from_view(view)->xdg_surface; - if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - wlr_xdg_toplevel_set_activated(xdg_surface, active); - } -} - -static void apply_size_constraints(struct wlr_xdg_surface *xdg_surface, - uint32_t width, uint32_t height, uint32_t *dest_width, - uint32_t *dest_height) { - *dest_width = width; - *dest_height = height; - - struct wlr_xdg_toplevel_state *state = &xdg_surface->toplevel->current; - if (width < state->min_width) { - *dest_width = state->min_width; - } else if (state->max_width > 0 && - width > state->max_width) { - *dest_width = state->max_width; - } - if (height < state->min_height) { - *dest_height = state->min_height; - } else if (state->max_height > 0 && - height > state->max_height) { - *dest_height = state->max_height; - } -} - -static void resize(struct roots_view *view, uint32_t width, uint32_t height) { - struct wlr_xdg_surface *xdg_surface = - roots_xdg_surface_from_view(view)->xdg_surface; - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - return; - } - - uint32_t constrained_width, constrained_height; - apply_size_constraints(xdg_surface, width, height, &constrained_width, - &constrained_height); - - wlr_xdg_toplevel_set_size(xdg_surface, constrained_width, - constrained_height); -} - -static void move_resize(struct roots_view *view, double x, double y, - uint32_t width, uint32_t height) { - struct roots_xdg_surface *xdg_surface = - roots_xdg_surface_from_view(view); - struct wlr_xdg_surface *wlr_xdg_surface = xdg_surface->xdg_surface; - if (wlr_xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - return; - } - - bool update_x = x != view->box.x; - bool update_y = y != view->box.y; - - uint32_t constrained_width, constrained_height; - apply_size_constraints(wlr_xdg_surface, width, height, &constrained_width, - &constrained_height); - - if (update_x) { - x = x + width - constrained_width; - } - if (update_y) { - y = y + height - constrained_height; - } - - view->pending_move_resize.update_x = update_x; - view->pending_move_resize.update_y = update_y; - view->pending_move_resize.x = x; - view->pending_move_resize.y = y; - view->pending_move_resize.width = constrained_width; - view->pending_move_resize.height = constrained_height; - - uint32_t serial = wlr_xdg_toplevel_set_size(wlr_xdg_surface, - constrained_width, constrained_height); - if (serial > 0) { - xdg_surface->pending_move_resize_configure_serial = serial; - } else if (xdg_surface->pending_move_resize_configure_serial == 0) { - view_update_position(view, x, y); - } -} - -static void maximize(struct roots_view *view, bool maximized) { - struct wlr_xdg_surface *xdg_surface = - roots_xdg_surface_from_view(view)->xdg_surface; - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - return; - } - - wlr_xdg_toplevel_set_maximized(xdg_surface, maximized); -} - -static void set_fullscreen(struct roots_view *view, bool fullscreen) { - struct wlr_xdg_surface *xdg_surface = - roots_xdg_surface_from_view(view)->xdg_surface; - if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - return; - } - - wlr_xdg_toplevel_set_fullscreen(xdg_surface, fullscreen); -} - -static void close(struct roots_view *view) { - struct wlr_xdg_surface *xdg_surface = - roots_xdg_surface_from_view(view)->xdg_surface; - struct wlr_xdg_popup *popup = NULL; - wl_list_for_each(popup, &xdg_surface->popups, link) { - wlr_xdg_popup_destroy(popup->base); - } - wlr_xdg_toplevel_send_close(xdg_surface); -} - -static void for_each_surface(struct roots_view *view, - wlr_surface_iterator_func_t iterator, void *user_data) { - struct wlr_xdg_surface *xdg_surface = - roots_xdg_surface_from_view(view)->xdg_surface; - wlr_xdg_surface_for_each_surface(xdg_surface, iterator, user_data); -} - -static void destroy(struct roots_view *view) { - struct roots_xdg_surface *roots_xdg_surface = - roots_xdg_surface_from_view(view); - wl_list_remove(&roots_xdg_surface->surface_commit.link); - wl_list_remove(&roots_xdg_surface->destroy.link); - wl_list_remove(&roots_xdg_surface->new_popup.link); - wl_list_remove(&roots_xdg_surface->map.link); - wl_list_remove(&roots_xdg_surface->unmap.link); - wl_list_remove(&roots_xdg_surface->request_move.link); - wl_list_remove(&roots_xdg_surface->request_resize.link); - wl_list_remove(&roots_xdg_surface->request_maximize.link); - wl_list_remove(&roots_xdg_surface->request_fullscreen.link); - wl_list_remove(&roots_xdg_surface->set_title.link); - wl_list_remove(&roots_xdg_surface->set_app_id.link); - roots_xdg_surface->xdg_surface->data = NULL; - free(roots_xdg_surface); -} - -static const struct roots_view_interface view_impl = { - .activate = activate, - .resize = resize, - .move_resize = move_resize, - .maximize = maximize, - .set_fullscreen = set_fullscreen, - .close = close, - .for_each_surface = for_each_surface, - .destroy = destroy, -}; - -static void handle_request_move(struct wl_listener *listener, void *data) { - struct roots_xdg_surface *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, request_move); - struct roots_view *view = &roots_xdg_surface->view; - struct roots_input *input = view->desktop->server->input; - struct wlr_xdg_toplevel_move_event *e = data; - 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; - } - roots_seat_begin_move(seat, view); -} - -static void handle_request_resize(struct wl_listener *listener, void *data) { - struct roots_xdg_surface *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, request_resize); - struct roots_view *view = &roots_xdg_surface->view; - struct roots_input *input = view->desktop->server->input; - struct wlr_xdg_toplevel_resize_event *e = data; - // 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; - } - roots_seat_begin_resize(seat, view, e->edges); -} - -static void handle_request_maximize(struct wl_listener *listener, void *data) { - struct roots_xdg_surface *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, request_maximize); - struct roots_view *view = &roots_xdg_surface->view; - struct wlr_xdg_surface *surface = roots_xdg_surface->xdg_surface; - - if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - return; - } - - view_maximize(view, surface->toplevel->client_pending.maximized); -} - -static void handle_request_fullscreen(struct wl_listener *listener, - void *data) { - struct roots_xdg_surface *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, request_fullscreen); - struct roots_view *view = &roots_xdg_surface->view; - struct wlr_xdg_surface *surface = roots_xdg_surface->xdg_surface; - struct wlr_xdg_toplevel_set_fullscreen_event *e = data; - - if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - return; - } - - view_set_fullscreen(view, e->fullscreen, e->output); -} - -static void handle_set_title(struct wl_listener *listener, void *data) { - struct roots_xdg_surface *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, set_title); - - view_set_title(&roots_xdg_surface->view, - roots_xdg_surface->xdg_surface->toplevel->title); -} - -static void handle_set_app_id(struct wl_listener *listener, void *data) { - struct roots_xdg_surface *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, set_app_id); - - view_set_app_id(&roots_xdg_surface->view, - roots_xdg_surface->xdg_surface->toplevel->app_id); -} - -static void handle_surface_commit(struct wl_listener *listener, void *data) { - struct roots_xdg_surface *roots_surface = - wl_container_of(listener, roots_surface, surface_commit); - struct roots_view *view = &roots_surface->view; - struct wlr_xdg_surface *surface = roots_surface->xdg_surface; - - if (!surface->mapped) { - return; - } - - view_apply_damage(view); - - struct wlr_box size; - get_size(view, &size); - view_update_size(view, size.width, size.height); - - uint32_t pending_serial = - roots_surface->pending_move_resize_configure_serial; - if (pending_serial > 0 && pending_serial >= surface->configure_serial) { - double x = view->box.x; - double y = view->box.y; - if (view->pending_move_resize.update_x) { - x = view->pending_move_resize.x + view->pending_move_resize.width - - size.width; - } - if (view->pending_move_resize.update_y) { - y = view->pending_move_resize.y + view->pending_move_resize.height - - size.height; - } - view_update_position(view, x, y); - - if (pending_serial == surface->configure_serial) { - roots_surface->pending_move_resize_configure_serial = 0; - } - } -} - -static void handle_new_popup(struct wl_listener *listener, void *data) { - struct roots_xdg_surface *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, new_popup); - struct wlr_xdg_popup *wlr_popup = data; - popup_create(&roots_xdg_surface->view, wlr_popup); -} - -static void handle_map(struct wl_listener *listener, void *data) { - struct roots_xdg_surface *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, map); - struct roots_view *view = &roots_xdg_surface->view; - - struct wlr_box box; - get_size(view, &box); - view->box.width = box.width; - view->box.height = box.height; - - view_map(view, roots_xdg_surface->xdg_surface->surface); - view_setup(view); - - wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, - roots_xdg_surface->xdg_surface->toplevel->title ?: "none"); - wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, - roots_xdg_surface->xdg_surface->toplevel->app_id ?: "none"); -} - -static void handle_unmap(struct wl_listener *listener, void *data) { - struct roots_xdg_surface *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, unmap); - view_unmap(&roots_xdg_surface->view); -} - -static void handle_destroy(struct wl_listener *listener, void *data) { - struct roots_xdg_surface *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, destroy); - view_destroy(&roots_xdg_surface->view); -} - -void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { - struct wlr_xdg_surface *surface = data; - assert(surface->role != WLR_XDG_SURFACE_ROLE_NONE); - - if (surface->role == WLR_XDG_SURFACE_ROLE_POPUP) { - wlr_log(WLR_DEBUG, "new xdg popup"); - return; - } - - struct roots_desktop *desktop = - wl_container_of(listener, desktop, xdg_shell_surface); - - wlr_log(WLR_DEBUG, "new xdg toplevel: title=%s, app_id=%s", - surface->toplevel->title, surface->toplevel->app_id); - wlr_xdg_surface_ping(surface); - - struct roots_xdg_surface *roots_surface = - calloc(1, sizeof(struct roots_xdg_surface)); - if (!roots_surface) { - return; - } - - view_init(&roots_surface->view, &view_impl, ROOTS_XDG_SHELL_VIEW, desktop); - roots_surface->xdg_surface = surface; - surface->data = roots_surface; - - view_maximize(&roots_surface->view, surface->toplevel->client_pending.maximized); - view_set_fullscreen(&roots_surface->view, surface->toplevel->client_pending.fullscreen, - surface->toplevel->client_pending.fullscreen_output); - - roots_surface->surface_commit.notify = handle_surface_commit; - wl_signal_add(&surface->surface->events.commit, - &roots_surface->surface_commit); - roots_surface->destroy.notify = handle_destroy; - wl_signal_add(&surface->events.destroy, &roots_surface->destroy); - roots_surface->map.notify = handle_map; - wl_signal_add(&surface->events.map, &roots_surface->map); - roots_surface->unmap.notify = handle_unmap; - wl_signal_add(&surface->events.unmap, &roots_surface->unmap); - roots_surface->request_move.notify = handle_request_move; - wl_signal_add(&surface->toplevel->events.request_move, - &roots_surface->request_move); - roots_surface->request_resize.notify = handle_request_resize; - wl_signal_add(&surface->toplevel->events.request_resize, - &roots_surface->request_resize); - roots_surface->request_maximize.notify = handle_request_maximize; - wl_signal_add(&surface->toplevel->events.request_maximize, - &roots_surface->request_maximize); - roots_surface->request_fullscreen.notify = handle_request_fullscreen; - wl_signal_add(&surface->toplevel->events.request_fullscreen, - &roots_surface->request_fullscreen); - roots_surface->set_title.notify = handle_set_title; - wl_signal_add(&surface->toplevel->events.set_title, &roots_surface->set_title); - roots_surface->set_app_id.notify = handle_set_app_id; - wl_signal_add(&surface->toplevel->events.set_app_id, - &roots_surface->set_app_id); - roots_surface->new_popup.notify = handle_new_popup; - wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); -} - - -static void decoration_handle_destroy(struct wl_listener *listener, - void *data) { - struct roots_xdg_toplevel_decoration *decoration = - wl_container_of(listener, decoration, destroy); - - decoration->surface->xdg_toplevel_decoration = NULL; - view_update_decorated(&decoration->surface->view, false); - wl_list_remove(&decoration->destroy.link); - wl_list_remove(&decoration->request_mode.link); - wl_list_remove(&decoration->surface_commit.link); - free(decoration); -} - -static void decoration_handle_request_mode(struct wl_listener *listener, - void *data) { - struct roots_xdg_toplevel_decoration *decoration = - wl_container_of(listener, decoration, request_mode); - - enum wlr_xdg_toplevel_decoration_v1_mode mode = - decoration->wlr_decoration->client_pending_mode; - if (mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_NONE) { - mode = WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; - } - wlr_xdg_toplevel_decoration_v1_set_mode(decoration->wlr_decoration, mode); -} - -static void decoration_handle_surface_commit(struct wl_listener *listener, - void *data) { - struct roots_xdg_toplevel_decoration *decoration = - wl_container_of(listener, decoration, surface_commit); - - bool decorated = decoration->wlr_decoration->current_mode == - WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; - view_update_decorated(&decoration->surface->view, decorated); -} - -void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data) { - struct wlr_xdg_toplevel_decoration_v1 *wlr_decoration = data; - - wlr_log(WLR_DEBUG, "new xdg toplevel decoration"); - - struct roots_xdg_surface *xdg_surface = wlr_decoration->surface->data; - assert(xdg_surface != NULL); - struct wlr_xdg_surface *wlr_xdg_surface = xdg_surface->xdg_surface; - - struct roots_xdg_toplevel_decoration *decoration = - calloc(1, sizeof(struct roots_xdg_toplevel_decoration)); - if (decoration == NULL) { - return; - } - decoration->wlr_decoration = wlr_decoration; - decoration->surface = xdg_surface; - xdg_surface->xdg_toplevel_decoration = decoration; - - decoration->destroy.notify = decoration_handle_destroy; - wl_signal_add(&wlr_decoration->events.destroy, &decoration->destroy); - decoration->request_mode.notify = decoration_handle_request_mode; - wl_signal_add(&wlr_decoration->events.request_mode, - &decoration->request_mode); - decoration->surface_commit.notify = decoration_handle_surface_commit; - wl_signal_add(&wlr_xdg_surface->surface->events.commit, - &decoration->surface_commit); - - decoration_handle_request_mode(&decoration->request_mode, wlr_decoration); -} - -struct roots_xdg_surface *roots_xdg_surface_from_view(struct roots_view *view) { - assert(view->impl == &view_impl); - return (struct roots_xdg_surface *)view; -} diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c deleted file mode 100644 index 5830d344..00000000 --- a/rootston/xdg_shell_v6.c +++ /dev/null @@ -1,504 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/desktop.h" -#include "rootston/input.h" -#include "rootston/server.h" - -static const struct roots_view_child_interface popup_impl; - -static void popup_destroy(struct roots_view_child *child) { - assert(child->impl == &popup_impl); - struct roots_xdg_popup_v6 *popup = (struct roots_xdg_popup_v6 *)child; - wl_list_remove(&popup->destroy.link); - wl_list_remove(&popup->new_popup.link); - wl_list_remove(&popup->map.link); - wl_list_remove(&popup->unmap.link); - free(popup); -} - -static const struct roots_view_child_interface popup_impl = { - .destroy = popup_destroy, -}; - -static void popup_handle_destroy(struct wl_listener *listener, void *data) { - struct roots_xdg_popup_v6 *popup = - wl_container_of(listener, popup, destroy); - view_child_destroy(&popup->view_child); -} - -static void popup_handle_map(struct wl_listener *listener, void *data) { - struct roots_xdg_popup_v6 *popup = - wl_container_of(listener, popup, map); - view_damage_whole(popup->view_child.view); - input_update_cursor_focus(popup->view_child.view->desktop->server->input); -} - -static void popup_handle_unmap(struct wl_listener *listener, void *data) { - struct roots_xdg_popup_v6 *popup = - wl_container_of(listener, popup, unmap); - view_damage_whole(popup->view_child.view); -} - -static struct roots_xdg_popup_v6 *popup_create(struct roots_view *view, - struct wlr_xdg_popup_v6 *wlr_popup); - -static void popup_handle_new_popup(struct wl_listener *listener, void *data) { - struct roots_xdg_popup_v6 *popup = - wl_container_of(listener, popup, new_popup); - struct wlr_xdg_popup_v6 *wlr_popup = data; - popup_create(popup->view_child.view, wlr_popup); -} - -static void popup_unconstrain(struct roots_xdg_popup_v6 *popup) { - // get the output of the popup's positioner anchor point and convert it to - // the toplevel parent's coordinate system and then pass it to - // wlr_xdg_popup_v6_unconstrain_from_box - - // TODO: unconstrain popups for rotated windows - if (popup->view_child.view->rotation != 0.0) { - return; - } - - struct roots_view *view = popup->view_child.view; - struct wlr_output_layout *layout = view->desktop->layout; - struct wlr_xdg_popup_v6 *wlr_popup = popup->wlr_popup; - - int anchor_lx, anchor_ly; - wlr_xdg_popup_v6_get_anchor_point(wlr_popup, &anchor_lx, &anchor_ly); - - int popup_lx, popup_ly; - wlr_xdg_popup_v6_get_toplevel_coords(wlr_popup, wlr_popup->geometry.x, - wlr_popup->geometry.y, &popup_lx, &popup_ly); - popup_lx += view->box.x; - popup_ly += view->box.y; - - anchor_lx += popup_lx; - anchor_ly += popup_ly; - - double dest_x = 0, dest_y = 0; - wlr_output_layout_closest_point(layout, NULL, anchor_lx, anchor_ly, - &dest_x, &dest_y); - - struct wlr_output *output = - wlr_output_layout_output_at(layout, dest_x, dest_y); - if (output == NULL) { - return; - } - - struct wlr_box *output_box = - wlr_output_layout_get_box(view->desktop->layout, output); - - // the output box expressed in the coordinate system of the toplevel parent - // of the popup - struct wlr_box output_toplevel_sx_box = { - .x = output_box->x - view->box.x, - .y = output_box->y - view->box.y, - .width = output_box->width, - .height = output_box->height, - }; - - wlr_xdg_popup_v6_unconstrain_from_box(popup->wlr_popup, &output_toplevel_sx_box); -} - -static struct roots_xdg_popup_v6 *popup_create(struct roots_view *view, - struct wlr_xdg_popup_v6 *wlr_popup) { - struct roots_xdg_popup_v6 *popup = - calloc(1, sizeof(struct roots_xdg_popup_v6)); - if (popup == NULL) { - return NULL; - } - popup->wlr_popup = wlr_popup; - view_child_init(&popup->view_child, &popup_impl, - view, wlr_popup->base->surface); - popup->destroy.notify = popup_handle_destroy; - wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); - popup->map.notify = popup_handle_map; - wl_signal_add(&wlr_popup->base->events.map, &popup->map); - popup->unmap.notify = popup_handle_unmap; - wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap); - popup->new_popup.notify = popup_handle_new_popup; - wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup); - - popup_unconstrain(popup); - - return popup; -} - - -static void get_size(struct roots_view *view, struct wlr_box *box) { - struct wlr_xdg_surface_v6 *surface = - roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; - - struct wlr_box geo_box; - wlr_xdg_surface_v6_get_geometry(surface, &geo_box); - box->width = geo_box.width; - box->height = geo_box.height; -} - -static void activate(struct roots_view *view, bool active) { - struct wlr_xdg_surface_v6 *surface = - roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; - if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { - wlr_xdg_toplevel_v6_set_activated(surface, active); - } -} - -static void apply_size_constraints(struct wlr_xdg_surface_v6 *surface, - uint32_t width, uint32_t height, uint32_t *dest_width, - uint32_t *dest_height) { - *dest_width = width; - *dest_height = height; - - struct wlr_xdg_toplevel_v6_state *state = &surface->toplevel->current; - if (width < state->min_width) { - *dest_width = state->min_width; - } else if (state->max_width > 0 && - width > state->max_width) { - *dest_width = state->max_width; - } - if (height < state->min_height) { - *dest_height = state->min_height; - } else if (state->max_height > 0 && - height > state->max_height) { - *dest_height = state->max_height; - } -} - -static void resize(struct roots_view *view, uint32_t width, uint32_t height) { - struct wlr_xdg_surface_v6 *surface = - roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; - if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { - return; - } - - uint32_t constrained_width, constrained_height; - apply_size_constraints(surface, width, height, &constrained_width, - &constrained_height); - - wlr_xdg_toplevel_v6_set_size(surface, constrained_width, - constrained_height); -} - -static void move_resize(struct roots_view *view, double x, double y, - uint32_t width, uint32_t height) { - struct roots_xdg_surface_v6 *roots_surface = - roots_xdg_surface_v6_from_view(view); - struct wlr_xdg_surface_v6 *surface = roots_surface->xdg_surface_v6; - if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { - return; - } - - bool update_x = x != view->box.x; - bool update_y = y != view->box.y; - - uint32_t constrained_width, constrained_height; - apply_size_constraints(surface, width, height, &constrained_width, - &constrained_height); - - if (update_x) { - x = x + width - constrained_width; - } - if (update_y) { - y = y + height - constrained_height; - } - - view->pending_move_resize.update_x = update_x; - view->pending_move_resize.update_y = update_y; - view->pending_move_resize.x = x; - view->pending_move_resize.y = y; - view->pending_move_resize.width = constrained_width; - view->pending_move_resize.height = constrained_height; - - uint32_t serial = wlr_xdg_toplevel_v6_set_size(surface, constrained_width, - constrained_height); - if (serial > 0) { - roots_surface->pending_move_resize_configure_serial = serial; - } else if (roots_surface->pending_move_resize_configure_serial == 0) { - view_update_position(view, x, y); - } -} - -static void maximize(struct roots_view *view, bool maximized) { - struct wlr_xdg_surface_v6 *surface = - roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; - if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { - return; - } - - wlr_xdg_toplevel_v6_set_maximized(surface, maximized); -} - -static void set_fullscreen(struct roots_view *view, bool fullscreen) { - struct wlr_xdg_surface_v6 *surface = - roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; - if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { - return; - } - - wlr_xdg_toplevel_v6_set_fullscreen(surface, fullscreen); -} - -static void close(struct roots_view *view) { - struct wlr_xdg_surface_v6 *surface = - roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; - struct wlr_xdg_popup_v6 *popup = NULL; - wl_list_for_each(popup, &surface->popups, link) { - wlr_xdg_surface_v6_send_close(popup->base); - } - wlr_xdg_surface_v6_send_close(surface); -} - -static void for_each_surface(struct roots_view *view, - wlr_surface_iterator_func_t iterator, void *user_data) { - struct wlr_xdg_surface_v6 *surface = - roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; - wlr_xdg_surface_v6_for_each_surface(surface, iterator, user_data); -} - -static void destroy(struct roots_view *view) { - struct roots_xdg_surface_v6 *roots_xdg_surface = - roots_xdg_surface_v6_from_view(view); - wl_list_remove(&roots_xdg_surface->surface_commit.link); - wl_list_remove(&roots_xdg_surface->destroy.link); - wl_list_remove(&roots_xdg_surface->new_popup.link); - wl_list_remove(&roots_xdg_surface->map.link); - wl_list_remove(&roots_xdg_surface->unmap.link); - wl_list_remove(&roots_xdg_surface->request_move.link); - wl_list_remove(&roots_xdg_surface->request_resize.link); - wl_list_remove(&roots_xdg_surface->request_maximize.link); - wl_list_remove(&roots_xdg_surface->request_fullscreen.link); - wl_list_remove(&roots_xdg_surface->set_title.link); - wl_list_remove(&roots_xdg_surface->set_app_id.link); - free(roots_xdg_surface); -} - -static const struct roots_view_interface view_impl = { - .activate = activate, - .resize = resize, - .move_resize = move_resize, - .maximize = maximize, - .set_fullscreen = set_fullscreen, - .close = close, - .for_each_surface = for_each_surface, - .destroy = destroy, -}; - -static void handle_request_move(struct wl_listener *listener, void *data) { - struct roots_xdg_surface_v6 *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, request_move); - 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; - 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; - } - roots_seat_begin_move(seat, view); -} - -static void handle_request_resize(struct wl_listener *listener, void *data) { - struct roots_xdg_surface_v6 *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, request_resize); - 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; - // 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; - } - 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 = roots_xdg_surface->xdg_surface_v6; - - if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { - return; - } - - view_maximize(view, surface->toplevel->client_pending.maximized); -} - -static void handle_request_fullscreen(struct wl_listener *listener, - void *data) { - struct roots_xdg_surface_v6 *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, request_fullscreen); - struct roots_view *view = &roots_xdg_surface->view; - struct wlr_xdg_surface_v6 *surface = roots_xdg_surface->xdg_surface_v6; - struct wlr_xdg_toplevel_v6_set_fullscreen_event *e = data; - - if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { - return; - } - - view_set_fullscreen(view, e->fullscreen, e->output); -} - -static void handle_set_title(struct wl_listener *listener, void *data) { - struct roots_xdg_surface_v6 *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, set_title); - - view_set_title(&roots_xdg_surface->view, - roots_xdg_surface->xdg_surface_v6->toplevel->title); -} - -static void handle_set_app_id(struct wl_listener *listener, void *data) { - struct roots_xdg_surface_v6 *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, set_app_id); - - view_set_app_id(&roots_xdg_surface->view, - roots_xdg_surface->xdg_surface_v6->toplevel->app_id); -} - -static void handle_surface_commit(struct wl_listener *listener, void *data) { - struct roots_xdg_surface_v6 *roots_surface = - wl_container_of(listener, roots_surface, surface_commit); - struct roots_view *view = &roots_surface->view; - struct wlr_xdg_surface_v6 *surface = roots_surface->xdg_surface_v6; - - if (!surface->mapped) { - return; - } - - view_apply_damage(view); - - struct wlr_box size; - get_size(view, &size); - view_update_size(view, size.width, size.height); - - uint32_t pending_serial = - roots_surface->pending_move_resize_configure_serial; - if (pending_serial > 0 && pending_serial >= surface->configure_serial) { - double x = view->box.x; - double y = view->box.y; - if (view->pending_move_resize.update_x) { - x = view->pending_move_resize.x + view->pending_move_resize.width - - size.width; - } - if (view->pending_move_resize.update_y) { - y = view->pending_move_resize.y + view->pending_move_resize.height - - size.height; - } - view_update_position(view, x, y); - - if (pending_serial == surface->configure_serial) { - roots_surface->pending_move_resize_configure_serial = 0; - } - } -} - -static void handle_new_popup(struct wl_listener *listener, void *data) { - struct roots_xdg_surface_v6 *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, new_popup); - struct wlr_xdg_popup_v6 *wlr_popup = data; - popup_create(&roots_xdg_surface->view, wlr_popup); -} - -static void handle_map(struct wl_listener *listener, void *data) { - struct roots_xdg_surface_v6 *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, map); - struct roots_view *view = &roots_xdg_surface->view; - - struct wlr_box box; - get_size(view, &box); - view->box.width = box.width; - view->box.height = box.height; - - view_map(view, roots_xdg_surface->xdg_surface_v6->surface); - view_setup(view); - - wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, - roots_xdg_surface->xdg_surface_v6->toplevel->title ?: "none"); - wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, - roots_xdg_surface->xdg_surface_v6->toplevel->app_id ?: "none"); -} - -static void handle_unmap(struct wl_listener *listener, void *data) { - struct roots_xdg_surface_v6 *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, unmap); - view_unmap(&roots_xdg_surface->view); -} - -static void handle_destroy(struct wl_listener *listener, void *data) { - struct roots_xdg_surface_v6 *roots_xdg_surface = - wl_container_of(listener, roots_xdg_surface, destroy); - view_destroy(&roots_xdg_surface->view); -} - -void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { - struct wlr_xdg_surface_v6 *surface = data; - assert(surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE); - - if (surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { - wlr_log(WLR_DEBUG, "new xdg popup"); - return; - } - - struct roots_desktop *desktop = - wl_container_of(listener, desktop, xdg_shell_v6_surface); - - wlr_log(WLR_DEBUG, "new xdg toplevel: title=%s, app_id=%s", - surface->toplevel->title, surface->toplevel->app_id); - wlr_xdg_surface_v6_ping(surface); - - struct roots_xdg_surface_v6 *roots_surface = - calloc(1, sizeof(struct roots_xdg_surface_v6)); - if (!roots_surface) { - return; - } - - view_init(&roots_surface->view, &view_impl, ROOTS_XDG_SHELL_V6_VIEW, desktop); - roots_surface->xdg_surface_v6 = surface; - - view_maximize(&roots_surface->view, surface->toplevel->client_pending.maximized); - view_set_fullscreen(&roots_surface->view, surface->toplevel->client_pending.fullscreen, - surface->toplevel->client_pending.fullscreen_output); - - roots_surface->surface_commit.notify = handle_surface_commit; - wl_signal_add(&surface->surface->events.commit, - &roots_surface->surface_commit); - roots_surface->destroy.notify = handle_destroy; - wl_signal_add(&surface->events.destroy, &roots_surface->destroy); - roots_surface->map.notify = handle_map; - wl_signal_add(&surface->events.map, &roots_surface->map); - roots_surface->unmap.notify = handle_unmap; - wl_signal_add(&surface->events.unmap, &roots_surface->unmap); - roots_surface->request_move.notify = handle_request_move; - wl_signal_add(&surface->toplevel->events.request_move, - &roots_surface->request_move); - roots_surface->request_resize.notify = handle_request_resize; - wl_signal_add(&surface->toplevel->events.request_resize, - &roots_surface->request_resize); - roots_surface->request_maximize.notify = handle_request_maximize; - wl_signal_add(&surface->toplevel->events.request_maximize, - &roots_surface->request_maximize); - roots_surface->request_fullscreen.notify = handle_request_fullscreen; - wl_signal_add(&surface->toplevel->events.request_fullscreen, - &roots_surface->request_fullscreen); - roots_surface->set_title.notify = handle_set_title; - wl_signal_add(&surface->toplevel->events.set_title, - &roots_surface->set_title); - roots_surface->set_app_id.notify = handle_set_app_id; - wl_signal_add(&surface->toplevel->events.set_app_id, - &roots_surface->set_app_id); - roots_surface->new_popup.notify = handle_new_popup; - wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); -} - -struct roots_xdg_surface_v6 *roots_xdg_surface_v6_from_view( - struct roots_view *view) { - assert(view->impl == &view_impl); - return (struct roots_xdg_surface_v6 *)view; -} diff --git a/rootston/xwayland.c b/rootston/xwayland.c deleted file mode 100644 index 7dc637ce..00000000 --- a/rootston/xwayland.c +++ /dev/null @@ -1,355 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "rootston/server.h" - -static void activate(struct roots_view *view, bool active) { - struct wlr_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view)->xwayland_surface; - wlr_xwayland_surface_activate(xwayland_surface, active); -} - -static void move(struct roots_view *view, double x, double y) { - struct wlr_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view)->xwayland_surface; - view_update_position(view, x, y); - wlr_xwayland_surface_configure(xwayland_surface, x, y, - xwayland_surface->width, xwayland_surface->height); -} - -static void apply_size_constraints( - struct wlr_xwayland_surface *xwayland_surface, uint32_t width, - uint32_t height, uint32_t *dest_width, uint32_t *dest_height) { - *dest_width = width; - *dest_height = height; - - struct wlr_xwayland_surface_size_hints *size_hints = - xwayland_surface->size_hints; - if (size_hints != NULL) { - if (width < (uint32_t)size_hints->min_width) { - *dest_width = size_hints->min_width; - } else if (size_hints->max_width > 0 && - width > (uint32_t)size_hints->max_width) { - *dest_width = size_hints->max_width; - } - if (height < (uint32_t)size_hints->min_height) { - *dest_height = size_hints->min_height; - } else if (size_hints->max_height > 0 && - height > (uint32_t)size_hints->max_height) { - *dest_height = size_hints->max_height; - } - } -} - -static void resize(struct roots_view *view, uint32_t width, uint32_t height) { - struct wlr_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view)->xwayland_surface; - - uint32_t constrained_width, constrained_height; - apply_size_constraints(xwayland_surface, width, height, &constrained_width, - &constrained_height); - - wlr_xwayland_surface_configure(xwayland_surface, xwayland_surface->x, - xwayland_surface->y, constrained_width, constrained_height); -} - -static void move_resize(struct roots_view *view, double x, double y, - uint32_t width, uint32_t height) { - struct wlr_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view)->xwayland_surface; - - bool update_x = x != view->box.x; - bool update_y = y != view->box.y; - - uint32_t constrained_width, constrained_height; - apply_size_constraints(xwayland_surface, width, height, &constrained_width, - &constrained_height); - - if (update_x) { - x = x + width - constrained_width; - } - if (update_y) { - y = y + height - constrained_height; - } - - view->pending_move_resize.update_x = update_x; - view->pending_move_resize.update_y = update_y; - view->pending_move_resize.x = x; - view->pending_move_resize.y = y; - view->pending_move_resize.width = constrained_width; - view->pending_move_resize.height = constrained_height; - - wlr_xwayland_surface_configure(xwayland_surface, x, y, constrained_width, - constrained_height); -} - -static void close(struct roots_view *view) { - struct wlr_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view)->xwayland_surface; - wlr_xwayland_surface_close(xwayland_surface); -} - -static void maximize(struct roots_view *view, bool maximized) { - struct wlr_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view)->xwayland_surface; - wlr_xwayland_surface_set_maximized(xwayland_surface, maximized); -} - -static void set_fullscreen(struct roots_view *view, bool fullscreen) { - struct wlr_xwayland_surface *xwayland_surface = - roots_xwayland_surface_from_view(view)->xwayland_surface; - wlr_xwayland_surface_set_fullscreen(xwayland_surface, fullscreen); -} - -static void destroy(struct roots_view *view) { - struct roots_xwayland_surface *roots_surface = - roots_xwayland_surface_from_view(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->set_title.link); - wl_list_remove(&roots_surface->set_class.link); - wl_list_remove(&roots_surface->map.link); - wl_list_remove(&roots_surface->unmap.link); - free(roots_surface); -} - -static const struct roots_view_interface view_impl = { - .activate = activate, - .resize = resize, - .move = move, - .move_resize = move_resize, - .maximize = maximize, - .set_fullscreen = set_fullscreen, - .close = close, - .destroy = destroy, -}; - -static void handle_destroy(struct wl_listener *listener, void *data) { - struct roots_xwayland_surface *roots_surface = - wl_container_of(listener, roots_surface, destroy); - view_destroy(&roots_surface->view); -} - -static void handle_request_configure(struct wl_listener *listener, void *data) { - struct roots_xwayland_surface *roots_surface = - wl_container_of(listener, roots_surface, request_configure); - struct wlr_xwayland_surface *xwayland_surface = - roots_surface->xwayland_surface; - struct wlr_xwayland_surface_configure_event *event = data; - - view_update_position(&roots_surface->view, event->x, event->y); - - wlr_xwayland_surface_configure(xwayland_surface, event->x, event->y, - event->width, event->height); -} - -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; - 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; -} - -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_seat *seat = guess_seat_for_view(view); - - if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { - return; - } - - 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_seat *seat = guess_seat_for_view(view); - struct wlr_xwayland_resize_event *e = data; - - if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { - return; - } - 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 = - roots_surface->xwayland_surface; - - bool maximized = xwayland_surface->maximized_vert && - xwayland_surface->maximized_horz; - view_maximize(view, maximized); -} - -static void handle_request_fullscreen(struct wl_listener *listener, - void *data) { - struct roots_xwayland_surface *roots_surface = - wl_container_of(listener, roots_surface, request_fullscreen); - struct roots_view *view = &roots_surface->view; - struct wlr_xwayland_surface *xwayland_surface = - roots_surface->xwayland_surface; - - view_set_fullscreen(view, xwayland_surface->fullscreen, NULL); -} - -static void handle_set_title(struct wl_listener *listener, void *data) { - struct roots_xwayland_surface *roots_surface = - wl_container_of(listener, roots_surface, set_title); - - view_set_title(&roots_surface->view, - roots_surface->xwayland_surface->title); -} - -static void handle_set_class(struct wl_listener *listener, void *data) { - struct roots_xwayland_surface *roots_surface = - wl_container_of(listener, roots_surface, set_class); - - view_set_app_id(&roots_surface->view, - roots_surface->xwayland_surface->class); -} - -static void handle_surface_commit(struct wl_listener *listener, void *data) { - struct roots_xwayland_surface *roots_surface = - wl_container_of(listener, roots_surface, surface_commit); - struct roots_view *view = &roots_surface->view; - struct wlr_surface *wlr_surface = view->wlr_surface; - - view_apply_damage(view); - - int width = wlr_surface->current.width; - int height = wlr_surface->current.height; - view_update_size(view, width, height); - - double x = view->box.x; - double y = view->box.y; - if (view->pending_move_resize.update_x) { - x = view->pending_move_resize.x + view->pending_move_resize.width - - width; - view->pending_move_resize.update_x = false; - } - if (view->pending_move_resize.update_y) { - y = view->pending_move_resize.y + view->pending_move_resize.height - - height; - view->pending_move_resize.update_y = false; - } - view_update_position(view, x, y); -} - -static void handle_map(struct wl_listener *listener, void *data) { - struct roots_xwayland_surface *roots_surface = - wl_container_of(listener, roots_surface, map); - struct wlr_xwayland_surface *surface = data; - struct roots_view *view = &roots_surface->view; - - view->box.x = surface->x; - view->box.y = surface->y; - view->box.width = surface->surface->current.width; - view->box.height = surface->surface->current.height; - - roots_surface->surface_commit.notify = handle_surface_commit; - wl_signal_add(&surface->surface->events.commit, - &roots_surface->surface_commit); - - view_map(view, surface->surface); - - if (!surface->override_redirect) { - if (surface->decorations == WLR_XWAYLAND_SURFACE_DECORATIONS_ALL) { - view->decorated = true; - view->border_width = 4; - view->titlebar_height = 12; - } - - view_setup(view); - - wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, - roots_surface->xwayland_surface->title ?: "none"); - wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, - roots_surface->xwayland_surface->class ?: "none"); - } else { - view_initial_focus(view); - } -} - -static void handle_unmap(struct wl_listener *listener, void *data) { - struct roots_xwayland_surface *roots_surface = - wl_container_of(listener, roots_surface, unmap); - struct roots_view *view = &roots_surface->view; - - wl_list_remove(&roots_surface->surface_commit.link); - view_unmap(view); -} - -void handle_xwayland_surface(struct wl_listener *listener, void *data) { - struct roots_desktop *desktop = - wl_container_of(listener, desktop, xwayland_surface); - - struct wlr_xwayland_surface *surface = data; - wlr_log(WLR_DEBUG, "new xwayland surface: title=%s, class=%s, instance=%s", - surface->title, surface->class, surface->instance); - wlr_xwayland_surface_ping(surface); - - struct roots_xwayland_surface *roots_surface = - calloc(1, sizeof(struct roots_xwayland_surface)); - if (roots_surface == NULL) { - return; - } - - view_init(&roots_surface->view, &view_impl, ROOTS_XWAYLAND_VIEW, desktop); - roots_surface->view.box.x = surface->x; - roots_surface->view.box.y = surface->y; - roots_surface->xwayland_surface = surface; - - 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 = handle_map; - wl_signal_add(&surface->events.map, &roots_surface->map); - roots_surface->unmap.notify = handle_unmap; - wl_signal_add(&surface->events.unmap, &roots_surface->unmap); - 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); - roots_surface->request_maximize.notify = handle_request_maximize; - wl_signal_add(&surface->events.request_maximize, - &roots_surface->request_maximize); - roots_surface->request_fullscreen.notify = handle_request_fullscreen; - wl_signal_add(&surface->events.request_fullscreen, - &roots_surface->request_fullscreen); - roots_surface->set_title.notify = handle_set_title; - wl_signal_add(&surface->events.set_title, &roots_surface->set_title); - roots_surface->set_class.notify = handle_set_class; - wl_signal_add(&surface->events.set_class, - &roots_surface->set_class); -} - -struct roots_xwayland_surface *roots_xwayland_surface_from_view( - struct roots_view *view) { - assert(view->impl == &view_impl); - return (struct roots_xwayland_surface *)view; -}