/*! * @file Mw/LowLevel/Wayland.h * @brief Wayland Backend * @warning This is used internally. */ #ifndef __MW_LOWLEVEL_WAYLAND_H__ #define __MW_LOWLEVEL_WAYLAND_H__ #include #include #include #include #include #include #include #include MWDECL int MwLLWaylandCallInit(void); #define CSD_BORDER_FRAME_LEFT 5 #define CSD_BORDER_FRAME_RIGHT 5 #define CSD_BORDER_FRAME_TOP 24 #define CSD_BORDER_FRAME_BOTTOM 5 struct _MwLLWayland; #include #if WAYLAND_LOAD_OPENGL #include #include #endif typedef struct wayland_call_table { void* lib; void* xkb_lib; void* cairo_lib; #ifdef USE_DBUS MwLLDBusFuncTable dbus; MwBool has_dbus; #endif int (*wl_display_dispatch)(struct wl_display* display); int (*wl_display_dispatch_pending)(struct wl_display* display); void (*wl_display_disconnect)(struct wl_display* display); void (*wl_display_cancel_read)(struct wl_display* display); int (*wl_display_prepare_read)(struct wl_display* display); int (*wl_display_read_events)(struct wl_display* display); int (*wl_display_flush)(struct wl_display* display); int (*wl_display_get_fd)(struct wl_display* display); int (*wl_display_roundtrip)(struct wl_display* display); int (*wl_proxy_add_listener)(struct wl_proxy* proxy, void (**implementation)(void), void* data); void (*wl_proxy_destroy)(struct wl_proxy* proxy); void (*wl_log_set_handler_client)(wl_log_func_t handler); struct wl_proxy* (*wl_proxy_marshal_flags)(struct wl_proxy* proxy, uint32_t opcode, const struct wl_interface* interface, uint32_t version, uint32_t flags, ...); struct wl_display* (*wl_display_connect)(const char* name); uint32_t (*wl_proxy_get_version)(struct wl_proxy* proxy); struct wl_display* (*wl_display_connect_to_fd)(int fd); int (*wl_display_get_error)(struct wl_display* display); struct xkb_context* (*xkb_context_new)(enum xkb_context_flags flags); void (*xkb_context_unref)(struct xkb_context* context); struct xkb_state* (*xkb_state_new)(struct xkb_keymap* keymap); void (*xkb_state_unref)(struct xkb_state* state); struct xkb_keymap* (*xkb_keymap_new_from_string)(struct xkb_context* context, const char* string, enum xkb_keymap_format format, enum xkb_keymap_compile_flags flags); xkb_level_index_t (*xkb_keymap_num_levels_for_key)(struct xkb_keymap* keymap, xkb_keycode_t key, xkb_layout_index_t layout); int (*xkb_keymap_key_get_syms_by_level)(struct xkb_keymap* keymap, xkb_keycode_t key, xkb_layout_index_t layout, xkb_level_index_t level, const xkb_keysym_t** syms_out); xkb_layout_index_t (*xkb_state_key_get_layout)(struct xkb_state* state, xkb_keycode_t key); void (*xkb_keymap_unref)(struct xkb_keymap* keymap); void (*cairo_set_line_width)(cairo_t* cr, double width); void (*cairo_scale)(cairo_t* cr, double sx, double sy); cairo_t* (*cairo_create)(cairo_surface_t* target); void (*cairo_move_to)(cairo_t* cr, double x, double y); void (*cairo_rectangle)(cairo_t* cr, double x, double y, double width, double height); void (*cairo_new_path)(cairo_t* cr); void (*cairo_set_line_cap)(cairo_t* cr, cairo_line_cap_t line_cap); void (*cairo_set_source_rgba)(cairo_t* cr, double red, double green, double blue, double alpha); void (*cairo_set_source_rgb)(cairo_t* cr, double red, double green, double blue); void (*cairo_reset_clip)(cairo_t* cr); unsigned char* (*cairo_image_surface_get_data)(cairo_surface_t* surface); void (*cairo_line_to)(cairo_t* cr, double x, double y); void (*cairo_surface_destroy)(cairo_surface_t* surface); cairo_surface_t* (*cairo_image_surface_create_for_data)(unsigned char* data, cairo_format_t format, int width, int height, int stride); cairo_surface_t* (*cairo_image_surface_create)(cairo_format_t format, int width, int height); void (*cairo_destroy)(cairo_t* cr); cairo_pattern_t* (*cairo_get_source)(cairo_t* cr); void (*cairo_close_path)(cairo_t* cr); void (*cairo_paint)(cairo_t* cr); void (*cairo_surface_flush)(cairo_surface_t* surface); void (*cairo_clip)(cairo_t* cr); void (*cairo_save)(cairo_t* cr); void (*cairo_restore)(cairo_t* cr); void (*cairo_surface_mark_dirty)(cairo_surface_t* surface); void (*cairo_stroke)(cairo_t* cr); void (*cairo_set_source_surface)(cairo_t* cr, cairo_surface_t* surface, double x, double y); void (*cairo_fill)(cairo_t* cr); void (*cairo_pattern_set_filter)(cairo_pattern_t* pattern, cairo_filter_t filter); void (*cairo_set_antialias)(cairo_t*, cairo_antialias_t); void (*cairo_set_operator)(cairo_t* cr, cairo_operator_t op); } wayland_call_table_t; extern wayland_call_table_t wl_call_tbl; extern MwBool MwWaylandAlwaysRender; /* defined inline right here so that it doesn't conflict with the other macros */ MwInline int wayland_load_funcs() { #ifdef __APPLE__ wl_call_tbl.lib = MwDynamicOpen("libwayland-client.dylib"); #else wl_call_tbl.lib = MwDynamicOpen("libwayland-client.so"); #endif if(!wl_call_tbl.lib) { printf("(libwayland-client not found, falling back to X11)\n"); return 1; } #ifdef __APPLE__ wl_call_tbl.xkb_lib = MwDynamicOpen("libxkbcommon.dylib"); #else wl_call_tbl.xkb_lib = MwDynamicOpen("libxkbcommon.so"); #endif if(!wl_call_tbl.xkb_lib) { printf("(libxkbcommon not found, cannot use Wayland backend.)\n"); return 1; } #ifdef __APPLE__ wl_call_tbl.cairo_lib = MwDynamicOpen("libcairo.dylib"); #else wl_call_tbl.cairo_lib = MwDynamicOpen("libcairo.so"); #endif if(!wl_call_tbl.cairo_lib) { printf("(libcairo not found, cannot use Wayland backend.)\n"); return 1; } #define WAYLAND_FUNC(x) \ wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.lib, #x); \ if(!wl_call_tbl.x) { \ printf("WARNING: Could use Wayland backend if " #x " was found.\n"); \ return 1; \ }; WAYLAND_FUNC(wl_display_dispatch) WAYLAND_FUNC(wl_display_dispatch_pending) WAYLAND_FUNC(wl_display_disconnect) WAYLAND_FUNC(wl_display_cancel_read) WAYLAND_FUNC(wl_display_prepare_read) WAYLAND_FUNC(wl_display_read_events) WAYLAND_FUNC(wl_display_flush) WAYLAND_FUNC(wl_display_get_fd) WAYLAND_FUNC(wl_display_roundtrip) WAYLAND_FUNC(wl_proxy_add_listener) WAYLAND_FUNC(wl_proxy_destroy) WAYLAND_FUNC(wl_log_set_handler_client) WAYLAND_FUNC(wl_proxy_marshal_flags) WAYLAND_FUNC(wl_display_connect) WAYLAND_FUNC(wl_proxy_get_version) WAYLAND_FUNC(wl_display_connect_to_fd) WAYLAND_FUNC(wl_display_get_error) #undef WAYLAND_FUNC #define XKB_FUNC(x) \ wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.xkb_lib, #x); \ if(!wl_call_tbl.x) { \ printf("WARNING: Could use Wayland backend if " #x " was found. Do you have libxkbcommon?\n"); \ return 1; \ }; XKB_FUNC(xkb_state_unref) XKB_FUNC(xkb_context_new) XKB_FUNC(xkb_context_unref) XKB_FUNC(xkb_state_new) XKB_FUNC(xkb_keymap_new_from_string) XKB_FUNC(xkb_keymap_unref) XKB_FUNC(xkb_keymap_num_levels_for_key) XKB_FUNC(xkb_keymap_key_get_syms_by_level) XKB_FUNC(xkb_state_key_get_layout) #undef XKB_FUNC #define CAIRO_FUNC(x) \ wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.cairo_lib, #x); \ if(!wl_call_tbl.x) { \ printf("WARNING: Could use Wayland backend if " #x " was found. Do you have libcairo?\n"); \ return 1; \ }; CAIRO_FUNC(cairo_set_line_width); CAIRO_FUNC(cairo_scale); CAIRO_FUNC(cairo_create); CAIRO_FUNC(cairo_move_to); CAIRO_FUNC(cairo_rectangle); CAIRO_FUNC(cairo_new_path); CAIRO_FUNC(cairo_set_line_cap); CAIRO_FUNC(cairo_set_antialias); CAIRO_FUNC(cairo_set_source_rgba); CAIRO_FUNC(cairo_set_source_rgb); CAIRO_FUNC(cairo_reset_clip); CAIRO_FUNC(cairo_image_surface_get_data); CAIRO_FUNC(cairo_line_to); CAIRO_FUNC(cairo_surface_destroy); CAIRO_FUNC(cairo_image_surface_create_for_data); CAIRO_FUNC(cairo_image_surface_create); CAIRO_FUNC(cairo_destroy); CAIRO_FUNC(cairo_get_source); CAIRO_FUNC(cairo_close_path); CAIRO_FUNC(cairo_paint); CAIRO_FUNC(cairo_surface_flush); CAIRO_FUNC(cairo_clip); CAIRO_FUNC(cairo_save); CAIRO_FUNC(cairo_restore); CAIRO_FUNC(cairo_surface_mark_dirty); CAIRO_FUNC(cairo_stroke); CAIRO_FUNC(cairo_set_source_surface); CAIRO_FUNC(cairo_fill); CAIRO_FUNC(cairo_set_operator); CAIRO_FUNC(cairo_pattern_set_filter); #undef CAIRO_FUNC #ifdef USE_DBUS wl_call_tbl.has_dbus = MwLLDBusFuncSetup(&wl_call_tbl.dbus); #endif return 0; } #define wl_display_dispatch wl_call_tbl.wl_display_dispatch #define wl_display_dispatch_pending wl_call_tbl.wl_display_dispatch_pending #define wl_display_disconnect wl_call_tbl.wl_display_disconnect #define wl_display_cancel_read wl_call_tbl.wl_display_cancel_read #define wl_display_prepare_read wl_call_tbl.wl_display_prepare_read #define wl_display_read_events wl_call_tbl.wl_display_read_events #define wl_display_flush wl_call_tbl.wl_display_flush #define wl_display_get_fd wl_call_tbl.wl_display_get_fd #define wl_display_roundtrip wl_call_tbl.wl_display_roundtrip #define wl_proxy_add_listener wl_call_tbl.wl_proxy_add_listener #define wl_proxy_destroy wl_call_tbl.wl_proxy_destroy #define wl_log_set_handler_client wl_call_tbl.wl_log_set_handler_client #define wl_proxy_marshal_flags wl_call_tbl.wl_proxy_marshal_flags #define wl_display_connect wl_call_tbl.wl_display_connect #define wl_proxy_get_version wl_call_tbl.wl_proxy_get_version #define wl_display_connect_to_fd wl_call_tbl.wl_display_connect_to_fd #define wl_display_get_error wl_call_tbl.wl_display_get_error #define xkb_state_unref wl_call_tbl.xkb_state_unref #define xkb_context_new wl_call_tbl.xkb_context_new #define xkb_context_unref wl_call_tbl.xkb_context_unref #define xkb_state_new wl_call_tbl.xkb_state_new #define xkb_keymap_new_from_string wl_call_tbl.xkb_keymap_new_from_string #define xkb_keymap_unref wl_call_tbl.xkb_keymap_unref #define xkb_keymap_num_levels_for_key wl_call_tbl.xkb_keymap_num_levels_for_key #define xkb_keymap_key_get_syms_by_level wl_call_tbl.xkb_keymap_key_get_syms_by_level #define xkb_state_key_get_layout wl_call_tbl.xkb_state_key_get_layout #define cairo_set_line_width wl_call_tbl.cairo_set_line_width #define cairo_scale wl_call_tbl.cairo_scale #define cairo_create wl_call_tbl.cairo_create #define cairo_move_to wl_call_tbl.cairo_move_to #define cairo_rectangle wl_call_tbl.cairo_rectangle #define cairo_new_path wl_call_tbl.cairo_new_path #define cairo_set_line_cap wl_call_tbl.cairo_set_line_cap #define cairo_set_antialias wl_call_tbl.cairo_set_antialias #define cairo_set_source_rgba wl_call_tbl.cairo_set_source_rgba #define cairo_set_source_rgb wl_call_tbl.cairo_set_source_rgb #define cairo_reset_clip wl_call_tbl.cairo_reset_clip #define cairo_image_surface_get_data wl_call_tbl.cairo_image_surface_get_data #define cairo_line_to wl_call_tbl.cairo_line_to #define cairo_surface_destroy wl_call_tbl.cairo_surface_destroy #define cairo_image_surface_create_for_data wl_call_tbl.cairo_image_surface_create_for_data #define cairo_image_surface_create wl_call_tbl.cairo_image_surface_create #define cairo_destroy wl_call_tbl.cairo_destroy #define cairo_get_source wl_call_tbl.cairo_get_source #define cairo_close_path wl_call_tbl.cairo_close_path #define cairo_paint wl_call_tbl.cairo_paint #define cairo_surface_flush wl_call_tbl.cairo_surface_flush #define cairo_clip wl_call_tbl.cairo_clip #define cairo_save wl_call_tbl.cairo_save #define cairo_restore wl_call_tbl.cairo_restore #define cairo_surface_mark_dirty wl_call_tbl.cairo_surface_mark_dirty #define cairo_stroke wl_call_tbl.cairo_stroke #define cairo_set_source_surface wl_call_tbl.cairo_set_source_surface #define cairo_fill wl_call_tbl.cairo_fill #define cairo_set_operator wl_call_tbl.cairo_set_operator #define cairo_pattern_set_filter wl_call_tbl.cairo_pattern_set_filter #ifndef WL_PROTOCOLS_DEFINED #define WL_PROTOCOLS_DEFINED #include "Wayland/wayland-core-protocol.h" #include "Wayland/xdg-shell-client-protocol.h" #include "Wayland/viewporter-client-protocol.h" #include "Wayland/xdg-decoration-client-protocol.h" #include "Wayland/cursor-shape-client-protocol.h" #include "Wayland/primary-selection-client-protocol.h" #include "Wayland/pointer-constraints-client-protocol.h" #include "Wayland/relative-pointer-client-protocol.h" #include "Wayland/xdg-toplevel-icon-client-protocol.h" #endif typedef struct wayland_protocol { void* listener; void* context; } wayland_protocol_t; typedef wayland_protocol_t*(wl_setup_func)(MwU32, struct _MwLLWayland*); typedef void(wl_destroy_func)(struct _MwLLWayland* wayland, wayland_protocol_t* data); typedef struct wayland_protocol_callback_table { wl_setup_func* setup; wl_destroy_func* destroy; } wayland_protocol_callback_table_t; struct _MwLLWaylandTopLevel { struct xdg_surface* xdg_surface; struct xdg_toplevel* xdg_top_level; struct xdg_toplevel_listener xdg_toplevel_listener; struct xdg_surface_listener xdg_surface_listener; MwBool compositor_created; MwBool xdg_wm_base_created; MwBool xdg_surface_created; struct wl_subsurface* ssurface; struct wl_subcompositor* scompositor; }; struct _MwLLWaylandSublevel { struct wl_subsurface* subsurface; struct wl_subcompositor* subcompositor; MwLL parent; struct xdg_surface* xdg_surface; }; struct _MwLLWaylandPopup { struct xdg_surface* xdg_surface; struct xdg_popup* xdg_popup; struct xdg_positioner* xdg_positioner; struct xdg_surface_listener xdg_surface_listener; struct xdg_wm_base* xdg_wm_base; MwLL topmost_parent; }; /* Shared set of anything needed for a shm buffer. */ struct _MwLLWaylandShmBuffer { struct wl_shm* shm; struct wl_shm_pool* shm_pool; struct wl_buffer* shm_buffer; struct wl_shm_pool* shm_pool_back; struct wl_buffer* shm_buffer_back; struct wl_surface* surface; struct wl_output* output; MwU8* buf; MwU8* buf_back; MwU64 buf_size; int fd; int fd_back; MwBool setup; }; enum _MwLLWaylandType { MwLL_WAYLAND_UNKNOWN = 0, MwLL_WAYLAND_TOPLEVEL, MwLL_WAYLAND_SUBLEVEL, MwLL_WAYLAND_POPUP, }; typedef struct wl_clipboard_device_context { struct { struct wl_data_device* wl; struct zwp_primary_selection_device_v1* zwp; } device; struct { struct wl_data_offer* wl; struct zwp_primary_selection_offer_v1* zwp; } offer; MwLL ll; // struct wl_seat* seat; } wl_clipboard_device_context_t; struct _MwLLWayland { struct _MwLLCommon common; union { /* Pointer for data that's only loaded if the widget is a toplevel */ struct _MwLLWaylandTopLevel* toplevel; /* Pointer for data that's only loaded if the widget is a sublevel */ struct _MwLLWaylandSublevel* sublevel; /* Pointer for data that's only loaded if the widget is a popup */ struct _MwLLWaylandPopup* popup; }; enum _MwLLWaylandType type; enum _MwLLWaylandType type_to_be; MwRect clipping_rect; MwBool detatching; MwPoint detach_point; MwBool did_initial_resize; MwBool is_toplevel; /* Map of Wayland interfaces to their relevant setup functions. */ struct { char* key; wayland_protocol_callback_table_t* value; }* wl_protocol_setup_map; /* Map of Wayland interfaces to any information we keep about them once we've registered them. */ struct { char* key; wayland_protocol_t* value; }* wl_protocol_map; MwBool has_decorations; char title[256]; struct xkb_context* xkb_context; struct xkb_keymap* xkb_keymap; struct xkb_state* xkb_state; struct wl_display* display; struct wl_registry* registry; struct wl_compositor* compositor; struct wl_registry_listener registry_listener; struct wl_region* o_region; struct wl_region* region; struct wl_output* output; struct wp_viewport* vp; MwBool do_lock_pointer; struct zwp_pointer_constraints_v1* pointer_constraints; struct zwp_relative_pointer_manager_v1* relative_pointer_manager; struct zwp_relative_pointer_v1* relative_pointer; struct zwp_locked_pointer_v1* locked_pointer; MwBool pointer_constrained; MwBool valid; #ifdef USE_DBUS MwLLDBusContext dbus; #endif MwBool dark_theme_detection; MwU32 dark_theme; /* clipboard related stuff. * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ struct { struct wl_data_device_manager* wl; struct zwp_primary_selection_device_manager_v1* zwp; } clipboard_manager; union { struct wl_data_source* wl; struct zwp_primary_selection_source_v1* zwp; } clipboard_source; char* clipboard_buffer; MwBool supports_zwp; MwBool zwp_setup; uint32_t clipboard_serial; wl_clipboard_device_context_t** clipboard_devices_wl; wl_clipboard_device_context_t** clipboard_devices_zwp; struct wl_pointer* pointer; MwU32 pointer_serial; struct wl_seat* pointer_seat; struct wl_keyboard* keyboard; MwU32 keyboard_serial; MwU64 events_pending; MwU32 mod_state; MwBool configured; /* Whether or not xdg_toplevel_configure has run once */ MwBool held_down; MwI32 x, y; MwI32 ox, oy; MwU32 ww, wh; /* Window position */ MwPoint cur_mouse_pos; /* Currently known mouse position */ int resizing; int setting_wh; MwU32 mw, mh; /* Monitor width and height as advertised by wl_output.mode */ MwLL parent; MwBool force_render; MwBool did_event_loop_early; MwBool dispatching_resize; struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer backbuffer; struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer* icon; pthread_mutex_t eventsMutex; int cancelEvent; int numCallbacksRunning; uint32_t last_time; MwBool moving; cairo_surface_t* front_cs; cairo_surface_t* back_cs; cairo_t* front_cairo; cairo_t* back_cairo; /* The cairo to actually use for draw operations. Typically is front_cairo, but MwLLBeginDraw can change this to the back_cairo so it can be used to draw window decorations. */ cairo_t* selected_cairo; }; struct _MwLLWaylandColor { struct _MwLLCommonColor common; }; struct _MwLLWaylandPixmap { struct _MwLLCommonPixmap common; cairo_surface_t* cs; }; #endif