foot/wayland.h

455 lines
11 KiB
C
Raw Normal View History

#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <uchar.h>
2019-10-27 15:57:23 +01:00
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
2019-10-27 15:57:23 +01:00
/* Wayland protocols */
#include <presentation-time.h>
#include <primary-selection-unstable-v1.h>
#include <text-input-unstable-v3.h>
#include <xdg-decoration-unstable-v1.h>
#include <xdg-output-unstable-v1.h>
#include <xdg-shell.h>
#if defined(HAVE_XDG_ACTIVATION)
#include <xdg-activation-v1.h>
#endif
#include <fcft/fcft.h>
#include <tllist.h>
#include "fdm.h"
/* Forward declarations */
struct terminal;
/* Mime-types we support when dealing with data offers (e.g. copy-paste, or DnD) */
enum data_offer_mime_type {
DATA_OFFER_MIME_UNSET,
DATA_OFFER_MIME_TEXT_PLAIN,
DATA_OFFER_MIME_TEXT_UTF8,
DATA_OFFER_MIME_URI_LIST,
DATA_OFFER_MIME_TEXT_TEXT,
DATA_OFFER_MIME_TEXT_STRING,
DATA_OFFER_MIME_TEXT_UTF8_STRING,
};
struct wl_window;
struct wl_clipboard {
struct wl_window *window; /* For DnD */
struct wl_data_source *data_source;
struct wl_data_offer *data_offer;
enum data_offer_mime_type mime_type;
char *text;
uint32_t serial;
};
struct wl_primary {
struct zwp_primary_selection_source_v1 *data_source;
struct zwp_primary_selection_offer_v1 *data_offer;
enum data_offer_mime_type mime_type;
char *text;
uint32_t serial;
};
/* Maps a mouse button to its "owning" surface */
struct button_tracker {
int button;
int surf_kind; /* TODO: this is really an "enum term_surface" */
bool send_to_client; /* Only valid when surface is the main grid surface */
};
struct rect {
int x;
int y;
int width;
int height;
};
struct seat {
struct wayland *wayl;
struct wl_seat *wl_seat;
uint32_t wl_name;
char *name;
/* Focused terminals */
struct terminal *kbd_focus;
struct terminal *mouse_focus;
struct terminal *ime_focus;
/* Keyboard state */
struct wl_keyboard *wl_keyboard;
struct {
uint32_t serial;
struct xkb_context *xkb;
struct xkb_keymap *xkb_keymap;
struct xkb_state *xkb_state;
struct xkb_compose_table *xkb_compose_table;
struct xkb_compose_state *xkb_compose_state;
struct {
int fd;
bool dont_re_repeat;
int32_t delay;
int32_t rate;
uint32_t key;
} repeat;
xkb_mod_index_t mod_shift;
xkb_mod_index_t mod_alt;
xkb_mod_index_t mod_ctrl;
xkb_mod_index_t mod_super;
xkb_mod_index_t mod_caps;
xkb_mod_index_t mod_num;
xkb_mod_mask_t bind_significant;
xkb_mod_mask_t kitty_significant;
xkb_keycode_t key_arrow_up;
xkb_keycode_t key_arrow_down;
/* Enabled modifiers */
bool shift;
bool alt;
bool ctrl;
bool super;
} kbd;
/* Pointer state */
struct wl_pointer *wl_pointer;
struct {
uint32_t serial;
struct wl_surface *surface;
struct wl_cursor_theme *theme;
struct wl_cursor *cursor;
int scale;
bool hidden;
const char *xcursor;
struct wl_callback *xcursor_callback;
bool xcursor_pending;
} pointer;
struct {
int x;
int y;
int col;
int row;
/* Mouse buttons currently being pressed, and their "owning" surfaces */
tll(struct button_tracker) buttons;
/* Double- and triple click state */
int count;
int last_released_button;
struct timespec last_time;
/* We used a discrete axis event in the current pointer frame */
double aggregated[2];
bool have_discrete;
} mouse;
/* Clipboard */
struct wl_data_device *data_device;
struct zwp_primary_selection_device_v1 *primary_selection_device;
struct wl_clipboard clipboard;
struct wl_primary primary;
2020-12-03 18:36:56 +01:00
#if defined(FOOT_IME_ENABLED) && FOOT_IME_ENABLED
/* Input Method Editor */
struct zwp_text_input_v3 *wl_text_input;
struct {
struct {
struct rect pending;
struct rect sent;
} cursor_rect;
struct {
struct {
char *text;
int32_t cursor_begin;
int32_t cursor_end;
} pending;
char32_t *text;
struct cell *cells;
int count;
struct {
bool hidden;
int start; /* Cell index, inclusive */
int end; /* Cell index, exclusive */
} cursor;
} preedit;
struct {
struct {
char *text;
} pending;
} commit;
struct {
struct {
uint32_t before_length;
uint32_t after_length;
} pending;
} surrounding;
uint32_t serial;
} ime;
2020-12-03 18:36:56 +01:00
#endif
struct {
bool active;
int count;
char32_t character;
} unicode_mode;
};
enum csd_surface {
CSD_SURF_TITLE,
CSD_SURF_LEFT,
CSD_SURF_RIGHT,
CSD_SURF_TOP,
CSD_SURF_BOTTOM,
CSD_SURF_MINIMIZE,
CSD_SURF_MAXIMIZE,
CSD_SURF_CLOSE,
CSD_SURF_COUNT,
};
struct monitor {
struct wayland *wayl;
struct wl_output *output;
struct zxdg_output_v1 *xdg;
uint32_t wl_name;
int x;
int y;
struct {
/* Physical size, in mm */
struct {
int width;
int height;
} mm;
/* Physical size, in pixels */
struct {
int width;
int height;
} px_real;
/* Scaled size, in pixels */
struct {
int width;
int height;
} px_scaled;
} dim;
struct {
/* PPI, based on physical size */
struct {
int x;
int y;
} real;
/* PPI, logical, based on scaled size */
struct {
int x;
int y;
} scaled;
} ppi;
float dpi;
int scale;
float refresh;
enum wl_output_subpixel subpixel;
enum wl_output_transform transform;
/* From wl_output */
char *make;
char *model;
/* From xdg_output */
char *name;
char *description;
float inch; /* e.g. 24" */
bool use_output_release;
};
struct wl_surf_subsurf {
struct wl_surface *surf;
struct wl_subsurface *sub;
};
struct wl_url {
const struct url *url;
struct wl_surf_subsurf surf;
};
enum csd_mode {CSD_UNKNOWN, CSD_NO, CSD_YES};
#if defined(HAVE_XDG_ACTIVATION)
typedef void (*activation_token_cb_t)(const char *token, void *data);
/*
* This context holds data used both in the token::done callback, and
* when cleaning up created, by not-yet-done tokens in
* wayl_win_destroy().
*/
struct xdg_activation_token_context {
struct wl_window *win; /* Need for win->xdg_tokens */
struct xdg_activation_token_v1 *xdg_token; /* Used to match token in done() */
activation_token_cb_t cb; /* User provided callback */
void *cb_data; /* Callback user pointer */
};
#endif
struct wayland;
struct wl_window {
struct terminal *term;
struct wl_surface *surface;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
#if defined(HAVE_XDG_ACTIVATION)
tll(struct xdg_activation_token_context *) xdg_tokens;
bool urgency_token_is_pending;
#endif
bool unmapped;
struct zxdg_toplevel_decoration_v1 *xdg_toplevel_decoration;
enum csd_mode csd_mode;
2020-02-23 14:17:48 +01:00
struct {
struct wl_surf_subsurf surface[CSD_SURF_COUNT];
struct fcft_font *font;
int move_timeout_fd;
uint32_t serial;
2020-02-23 14:17:48 +01:00
} csd;
struct {
bool maximize:1;
bool minimize:1;
} wm_capabilities;
struct wl_surf_subsurf search;
struct wl_surf_subsurf scrollback_indicator;
struct wl_surf_subsurf render_timer;
render: implement ‘flash’ and search mode’s ‘dimming’ with a sub-surface Search mode and ‘flash’ (OSC-555) both achieves similar visual effects: flash tints the entire window yellow, and search mode dims it (except the search match). But, they do so in completely different ways. Search mode is detected in render_cell(), and the colors are then dimmed there. Flash is implemented by blending a yellow, semi-transparent color on top of the rendered grid. This patch replaces those two implementations with a single one. We add a new sub-surface, called the ‘overlay’. In normal mode, it’s unmapped. When either search mode, or flash, is enabled, we enable it, and fill it with a semi-transparent color. Yellow for ‘flash’, and “black” (i.e. no color) for search mode. The compositor then blends it with the grid. Hopefully on the GPU, meaning it’ll be faster than if we blend in software. There are more performance benefits however. By using a separate surface, we can do much better damage tracking. The normal grid rendering code no longer have to care about neither search mode, nor flash. Thus, we get rid of a couple of ‘if’ statements in render_cell(), which is nice. But more importantly, we can drop full grid repaints in a couple of circumstances: * Entering/exiting search mode * Every frame while flash is active Now, when rendering the search mode overlay, we do want to do some damage tracking, also of the overlay. This, since search mode doesn’t dim the *entire* window. The search match is *not* dimmed. This is implemented by punching a hole in the overlay sub-surface. That is, we make part of it *fully* transparent. The basic idea is to set a clip region that excludes the search match, and then dim the rest of the overlay. It’s slightly more complicated than that however, if we want to reuse the last frame’s overlay buffer (i.e we don’t want to re-render the *entire* overlay every frame). In short, we need to: * Clear (punch hole) in areas that are part of this frame’s search match, but not the last frame’s (since those parts are _already_ cleared). * Dim the areas that were part of the last frame’s search match, but aren’t anymore (the rest of the overlay should already be dimmed). To do this, we save the last frame’s “holes” (as a pixman region). Then, when rendering the next frame, we first calculate the new frame’s “holes” region. The region to clear is “this frame’s holes minus last frame’s holes” The region to dim is “last frame’s holes minus this frames holes”. Finally, we compute the bounding box of all modified cells by taking the union of the two diff regions mentioned above. This allows us to limit the buffer damage sent to the compositor.
2022-04-16 17:49:46 +02:00
struct wl_surf_subsurf overlay;
2019-10-27 16:01:03 +01:00
struct wl_callback *frame_callback;
tll(const struct monitor *) on_outputs; /* Outputs we're mapped on */
tll(struct wl_url) urls;
bool is_configured;
bool is_fullscreen;
2020-02-26 13:23:00 +01:00
bool is_maximized;
2021-01-10 15:40:11 +01:00
bool is_resizing;
bool is_tiled_top;
bool is_tiled_bottom;
bool is_tiled_left;
bool is_tiled_right;
bool is_tiled; /* At least one of is_tiled_{top,bottom,left,right} is true */
struct {
int width;
int height;
bool is_activated:1;
bool is_fullscreen:1;
bool is_maximized:1;
bool is_resizing:1;
bool is_tiled_top:1;
bool is_tiled_bottom:1;
bool is_tiled_left:1;
bool is_tiled_right:1;
enum csd_mode csd_mode;
} configure;
int resize_timeout_fd;
};
struct terminal;
struct wayland {
struct fdm *fdm;
key-binding: new API, for handling sets of key bindings Up until now, our Wayland seats have been tracking key bindings. This makes sense, since the seat’s keymap determines how the key bindings are resolved. However, tying bindings to the seat/keymap alone isn’t enough, since we also depend on the current configuration (i.e. user settings) when resolving a key binding. This means configurations that doesn’t match the wayland object’s configuration, currently don’t resolve key bindings correctly. This applies to footclients where the user has overridden key bindings on the command line (e.g. --override key-bindings.foo=bar). Thus, to correctly resolve key bindings, each set of key bindings must be tied *both* to a seat/keymap, *and* a configuration. This patch introduces a key-binding manager, with an API to add/remove/lookup, and load/unload keymaps from sets of key bindings. In the API, sets are tied to a seat and terminal instance, since this makes the most sense (we need to instantiate, or incref a set whenever a new terminal instance is created). Internally, the set is tied to a seat and the terminal’s configuration. Sets are *added* when a new seat is added, and when a new terminal instance is created. Since there can only be one instance of each seat, sets are always removed when a seat is removed. Terminals on the other hand can re-use the same configuration (and typically do). Thus, sets ref-count the configuration. In other words, when instantiating a new terminal, we may not have to instantiate a new set of key bindings, but can often be incref:ed instead. Whenever the keymap changes on a seat, all key bindings sets associated with that seat reloads (re-resolves) their key bindings. Closes #931
2022-04-17 15:39:51 +02:00
struct key_binding_manager *key_binding_manager;
int fd;
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_subcompositor *sub_compositor;
struct wl_shm *shm;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct xdg_wm_base *shell;
struct zxdg_decoration_manager_v1 *xdg_decoration_manager;
struct wl_data_device_manager *data_device_manager;
struct zwp_primary_selection_device_manager_v1 *primary_selection_device_manager;
2019-10-27 17:07:44 +01:00
#if defined(HAVE_XDG_ACTIVATION)
struct xdg_activation_v1 *xdg_activation;
#endif
bool presentation_timings;
struct wp_presentation *presentation;
uint32_t presentation_clock_id;
2020-12-03 18:36:56 +01:00
#if defined(FOOT_IME_ENABLED) && FOOT_IME_ENABLED
struct zwp_text_input_manager_v3 *text_input_manager;
2020-12-03 18:36:56 +01:00
#endif
bool have_argb8888;
tll(struct monitor) monitors; /* All available outputs */
tll(struct seat) seats;
tll(struct terminal *) terms;
};
2019-10-27 15:57:23 +01:00
struct wayland *wayl_init(
struct fdm *fdm, struct key_binding_manager *key_binding_manager,
bool presentation_timings);
2019-10-27 15:57:23 +01:00
void wayl_destroy(struct wayland *wayl);
2019-10-27 16:01:03 +01:00
bool wayl_reload_xcursor_theme(struct seat *seat, int new_scale);
void wayl_flush(struct wayland *wayl);
void wayl_roundtrip(struct wayland *wayl);
struct wl_window *wayl_win_init(struct terminal *term, const char *token);
2019-10-27 16:01:03 +01:00
void wayl_win_destroy(struct wl_window *win);
bool wayl_win_set_urgent(struct wl_window *win);
bool wayl_win_csd_titlebar_visible(const struct wl_window *win);
bool wayl_win_csd_borders_visible(const struct wl_window *win);
bool wayl_win_subsurface_new(
struct wl_window *win, struct wl_surf_subsurf *surf,
bool allow_pointer_input);
bool wayl_win_subsurface_new_with_custom_parent(
struct wl_window *win, struct wl_surface *parent,
struct wl_surf_subsurf *surf, bool allow_pointer_input);
void wayl_win_subsurface_destroy(struct wl_surf_subsurf *surf);
#if defined(HAVE_XDG_ACTIVATION)
bool wayl_get_activation_token(
struct wayland *wayl, struct seat *seat, uint32_t serial,
struct wl_window *win, activation_token_cb_t cb, void *cb_data);
#endif