mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-25 01:40:19 -05:00
wayland: implement wayl_init()
Wayland instantiation is now done by the wayland backend, not in main.
This commit is contained in:
parent
1adab32906
commit
61cc8c3c55
6 changed files with 569 additions and 526 deletions
509
main.c
509
main.c
|
|
@ -33,371 +33,17 @@
|
|||
#include "fdm.h"
|
||||
#include "font.h"
|
||||
#include "grid.h"
|
||||
#include "input.h"
|
||||
#include "render.h"
|
||||
#include "selection.h"
|
||||
#include "shm.h"
|
||||
#include "slave.h"
|
||||
#include "terminal.h"
|
||||
#include "tokenize.h"
|
||||
#include "version.h"
|
||||
#include "render.h"
|
||||
#include "vt.h"
|
||||
|
||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
static void
|
||||
shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
|
||||
{
|
||||
struct wayland *wayl = data;
|
||||
if (format == WL_SHM_FORMAT_ARGB8888)
|
||||
wayl->have_argb8888 = true;
|
||||
}
|
||||
|
||||
static const struct wl_shm_listener shm_listener = {
|
||||
.format = &shm_format,
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
|
||||
{
|
||||
LOG_DBG("wm base ping");
|
||||
xdg_wm_base_pong(shell, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
||||
.ping = &xdg_wm_base_ping,
|
||||
};
|
||||
|
||||
static void
|
||||
seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
||||
enum wl_seat_capability caps)
|
||||
{
|
||||
struct wayland *wayl = data;
|
||||
|
||||
if (wayl->keyboard != NULL) {
|
||||
wl_keyboard_release(wayl->keyboard);
|
||||
wayl->keyboard = NULL;
|
||||
}
|
||||
|
||||
if (wayl->pointer.pointer != NULL) {
|
||||
wl_pointer_release(wayl->pointer.pointer);
|
||||
wayl->pointer.pointer = NULL;
|
||||
}
|
||||
|
||||
if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
|
||||
wayl->keyboard = wl_seat_get_keyboard(wl_seat);
|
||||
wl_keyboard_add_listener(wayl->keyboard, &keyboard_listener, wayl);
|
||||
}
|
||||
|
||||
if (caps & WL_SEAT_CAPABILITY_POINTER) {
|
||||
wayl->pointer.pointer = wl_seat_get_pointer(wl_seat);
|
||||
wl_pointer_add_listener(wayl->pointer.pointer, &pointer_listener, wayl);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_seat_listener seat_listener = {
|
||||
.capabilities = seat_handle_capabilities,
|
||||
.name = seat_handle_name,
|
||||
};
|
||||
|
||||
static void
|
||||
output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y,
|
||||
int32_t physical_width, int32_t physical_height,
|
||||
int32_t subpixel, const char *make, const char *model,
|
||||
int32_t transform)
|
||||
{
|
||||
struct monitor *mon = data;
|
||||
mon->width_mm = physical_width;
|
||||
mon->height_mm = physical_height;
|
||||
}
|
||||
|
||||
static void
|
||||
output_mode(void *data, struct wl_output *wl_output, uint32_t flags,
|
||||
int32_t width, int32_t height, int32_t refresh)
|
||||
{
|
||||
if ((flags & WL_OUTPUT_MODE_CURRENT) == 0)
|
||||
return;
|
||||
|
||||
struct monitor *mon = data;
|
||||
mon->refresh = (float)refresh / 1000;
|
||||
}
|
||||
|
||||
static void
|
||||
output_done(void *data, struct wl_output *wl_output)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
output_scale(void *data, struct wl_output *wl_output, int32_t factor)
|
||||
{
|
||||
struct monitor *mon = data;
|
||||
struct terminal *term = mon->wayl->term;
|
||||
|
||||
mon->scale = factor;
|
||||
|
||||
render_resize(term, term->width / term->scale, term->height / term->scale);
|
||||
render_reload_cursor_theme(term);
|
||||
}
|
||||
|
||||
static const struct wl_output_listener output_listener = {
|
||||
.geometry = &output_geometry,
|
||||
.mode = &output_mode,
|
||||
.done = &output_done,
|
||||
.scale = &output_scale,
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_output_handle_logical_position(
|
||||
void *data, struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y)
|
||||
{
|
||||
struct monitor *mon = data;
|
||||
mon->x = x;
|
||||
mon->y = y;
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output,
|
||||
int32_t width, int32_t height)
|
||||
{
|
||||
struct monitor *mon = data;
|
||||
mon->width_px = width;
|
||||
mon->height_px = height;
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output,
|
||||
const char *name)
|
||||
{
|
||||
struct monitor *mon = data;
|
||||
mon->name = strdup(name);
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output,
|
||||
const char *description)
|
||||
{
|
||||
}
|
||||
|
||||
static struct zxdg_output_v1_listener xdg_output_listener = {
|
||||
.logical_position = xdg_output_handle_logical_position,
|
||||
.logical_size = xdg_output_handle_logical_size,
|
||||
.done = xdg_output_handle_done,
|
||||
.name = xdg_output_handle_name,
|
||||
.description = xdg_output_handle_description,
|
||||
};
|
||||
|
||||
static void
|
||||
handle_global(void *data, struct wl_registry *registry,
|
||||
uint32_t name, const char *interface, uint32_t version)
|
||||
{
|
||||
LOG_DBG("global: %s, version=%u", interface, version);
|
||||
struct wayland *wayl = data;
|
||||
|
||||
if (strcmp(interface, wl_compositor_interface.name) == 0) {
|
||||
wayl->compositor = wl_registry_bind(
|
||||
wayl->registry, name, &wl_compositor_interface, 4);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, wl_subcompositor_interface.name) == 0) {
|
||||
wayl->sub_compositor = wl_registry_bind(
|
||||
wayl->registry, name, &wl_subcompositor_interface, 1);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, wl_shm_interface.name) == 0) {
|
||||
wayl->shm = wl_registry_bind(
|
||||
wayl->registry, name, &wl_shm_interface, 1);
|
||||
wl_shm_add_listener(wayl->shm, &shm_listener, wayl);
|
||||
wl_display_roundtrip(wayl->display);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
|
||||
wayl->shell = wl_registry_bind(
|
||||
wayl->registry, name, &xdg_wm_base_interface, 1);
|
||||
xdg_wm_base_add_listener(wayl->shell, &xdg_wm_base_listener, wayl);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0)
|
||||
wayl->xdg_decoration_manager = wl_registry_bind(
|
||||
wayl->registry, name, &zxdg_decoration_manager_v1_interface, 1);
|
||||
|
||||
else if (strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
wayl->seat = wl_registry_bind(
|
||||
wayl->registry, name, &wl_seat_interface, 5);
|
||||
wl_seat_add_listener(wayl->seat, &seat_listener, wayl);
|
||||
wl_display_roundtrip(wayl->display);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
|
||||
wayl->xdg_output_manager = wl_registry_bind(
|
||||
wayl->registry, name, &zxdg_output_manager_v1_interface, min(version, 2));
|
||||
}
|
||||
|
||||
else if (strcmp(interface, wl_output_interface.name) == 0) {
|
||||
struct wl_output *output = wl_registry_bind(
|
||||
wayl->registry, name, &wl_output_interface, 3);
|
||||
|
||||
tll_push_back(
|
||||
wayl->monitors, ((struct monitor){.wayl = wayl, .output = output}));
|
||||
|
||||
struct monitor *mon = &tll_back(wayl->monitors);
|
||||
wl_output_add_listener(output, &output_listener, mon);
|
||||
|
||||
mon->xdg = zxdg_output_manager_v1_get_xdg_output(
|
||||
wayl->xdg_output_manager, mon->output);
|
||||
zxdg_output_v1_add_listener(mon->xdg, &xdg_output_listener, mon);
|
||||
wl_display_roundtrip(wayl->display);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) {
|
||||
wayl->data_device_manager = wl_registry_bind(
|
||||
wayl->registry, name, &wl_data_device_manager_interface, 1);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name) == 0) {
|
||||
wayl->primary_selection_device_manager = wl_registry_bind(
|
||||
wayl->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
surface_enter(void *data, struct wl_surface *wl_surface,
|
||||
struct wl_output *wl_output)
|
||||
{
|
||||
struct wayland *wayl = data;
|
||||
struct terminal *term = wayl_terminal_from_surface(wayl, wl_surface);
|
||||
|
||||
tll_foreach(wayl->monitors, it) {
|
||||
if (it->item.output == wl_output) {
|
||||
LOG_DBG("mapped on %s", it->item.name);
|
||||
tll_push_back(term->window.on_outputs, &it->item);
|
||||
|
||||
/* Resize, since scale-to-use may have changed */
|
||||
render_resize(term, term->width / term->scale, term->height / term->scale);
|
||||
render_reload_cursor_theme(term);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERR("mapped on unknown output");
|
||||
}
|
||||
|
||||
static void
|
||||
surface_leave(void *data, struct wl_surface *wl_surface,
|
||||
struct wl_output *wl_output)
|
||||
{
|
||||
struct wayland *wayl = data;
|
||||
struct terminal *term = wayl_terminal_from_surface(wayl, wl_surface);
|
||||
|
||||
tll_foreach(term->window.on_outputs, it) {
|
||||
if (it->item->output != wl_output)
|
||||
continue;
|
||||
|
||||
LOG_DBG("unmapped from %s", it->item->name);
|
||||
tll_remove(term->window.on_outputs, it);
|
||||
|
||||
/* Resize, since scale-to-use may have changed */
|
||||
render_resize(term, term->width / term->scale, term->height / term->scale);
|
||||
render_reload_cursor_theme(term);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERR("unmapped from unknown output");
|
||||
}
|
||||
|
||||
static const struct wl_surface_listener surface_listener = {
|
||||
.enter = &surface_enter,
|
||||
.leave = &surface_leave,
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
|
||||
int32_t width, int32_t height, struct wl_array *states)
|
||||
{
|
||||
LOG_DBG("xdg-toplevel: configure: %dx%d", width, height);
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
struct wayland *wayl = data;
|
||||
struct terminal *term = wayl_terminal_from_xdg_toplevel(wayl, xdg_toplevel);
|
||||
render_resize(term, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
|
||||
{
|
||||
struct wayland *wayl = data;
|
||||
struct terminal *term = wayl_terminal_from_xdg_toplevel(wayl, xdg_toplevel);
|
||||
LOG_DBG("xdg-toplevel: close");
|
||||
|
||||
term->quit = true;
|
||||
wl_display_roundtrip(wayl->display);
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||
.configure = &xdg_toplevel_configure,
|
||||
.close = &xdg_toplevel_close,
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_surface_configure(void *data, struct xdg_surface *xdg_surface,
|
||||
uint32_t serial)
|
||||
{
|
||||
//LOG_DBG("xdg-surface: configure");
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
.configure = &xdg_surface_configure,
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_toplevel_decoration_configure(void *data,
|
||||
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
|
||||
uint32_t mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE:
|
||||
LOG_ERR("unimplemented: client-side decorations");
|
||||
break;
|
||||
|
||||
case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE:
|
||||
LOG_DBG("using server-side decorations");
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("unimplemented: unknown XDG toplevel decoration mode: %u", mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener = {
|
||||
.configure = &xdg_toplevel_decoration_configure,
|
||||
};
|
||||
|
||||
static void
|
||||
handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
|
||||
{
|
||||
LOG_WARN("global removed: %u", name);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
.global = &handle_global,
|
||||
.global_remove = &handle_global_remove,
|
||||
};
|
||||
|
||||
static bool
|
||||
fdm_wayl(struct fdm *fdm, int fd, int events, void *data)
|
||||
{
|
||||
|
|
@ -470,7 +116,7 @@ fdm_ptmx(struct fdm *fdm, int fd, int events, void *data)
|
|||
* ourselves we just received keyboard input, and in
|
||||
* this case *not* delay rendering?
|
||||
*/
|
||||
if (term->window.frame_callback == NULL) {
|
||||
if (term->window->frame_callback == NULL) {
|
||||
/* First timeout - reset each time we receive input. */
|
||||
timerfd_settime(
|
||||
term->delayed_render_timer.lower_fd, 0,
|
||||
|
|
@ -491,6 +137,7 @@ fdm_ptmx(struct fdm *fdm, int fd, int events, void *data)
|
|||
return !(events & EPOLLHUP);
|
||||
}
|
||||
|
||||
#include "input.h"
|
||||
static bool
|
||||
fdm_repeat(struct fdm *fdm, int fd, int events, void *data)
|
||||
{
|
||||
|
|
@ -727,16 +374,6 @@ main(int argc, char *const *argv)
|
|||
setlocale(LC_ALL, "");
|
||||
setenv("TERM", conf.term, 1);
|
||||
|
||||
struct fdm *fdm = NULL;
|
||||
|
||||
struct wayland wayl = {
|
||||
.kbd = {
|
||||
.repeat = {
|
||||
.fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
struct terminal term = {
|
||||
.quit = false,
|
||||
.ptmx = posix_openpt(O_RDWR | O_NOCTTY),
|
||||
|
|
@ -799,7 +436,6 @@ main(int argc, char *const *argv)
|
|||
.normal = {.damage = tll_init(), .scroll_damage = tll_init()},
|
||||
.alt = {.damage = tll_init(), .scroll_damage = tll_init()},
|
||||
.grid = &term.normal,
|
||||
.wl = &wayl,
|
||||
.render = {
|
||||
.scrollback_lines = conf.scrollback_lines,
|
||||
.workers = {
|
||||
|
|
@ -840,6 +476,18 @@ main(int argc, char *const *argv)
|
|||
memcpy(term.colors.table, term.colors.default_table, sizeof(term.colors.table));
|
||||
}
|
||||
|
||||
struct fdm *fdm = NULL;
|
||||
struct wayland *wayl = NULL;
|
||||
|
||||
if ((fdm = fdm_init()) == NULL)
|
||||
goto out;
|
||||
|
||||
if ((wayl = wayl_init(fdm)) == NULL)
|
||||
goto out;
|
||||
|
||||
term.wl = wayl;
|
||||
wayl->term = &term;
|
||||
|
||||
if (term.ptmx == -1) {
|
||||
LOG_ERR("failed to open pseudo terminal");
|
||||
goto out;
|
||||
|
|
@ -897,133 +545,19 @@ main(int argc, char *const *argv)
|
|||
term.cell_height = (int)ceil(term.fextents.height);
|
||||
LOG_INFO("cell width=%d, height=%d", term.cell_width, term.cell_height);
|
||||
|
||||
term.wl->term = &term;
|
||||
term.wl->display = wl_display_connect(NULL);
|
||||
if (term.wl->display == NULL) {
|
||||
LOG_ERR("failed to connect to wayland; no compositor running?");
|
||||
goto out;
|
||||
}
|
||||
|
||||
term.wl->registry = wl_display_get_registry(term.wl->display);
|
||||
if (term.wl->registry == NULL) {
|
||||
LOG_ERR("failed to get wayland registry");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl_registry_add_listener(term.wl->registry, ®istry_listener, term.wl);
|
||||
wl_display_roundtrip(term.wl->display);
|
||||
|
||||
if (term.wl->compositor == NULL) {
|
||||
LOG_ERR("no compositor");
|
||||
goto out;
|
||||
}
|
||||
if (term.wl->shm == NULL) {
|
||||
LOG_ERR("no shared memory buffers interface");
|
||||
goto out;
|
||||
}
|
||||
if (term.wl->shell == NULL) {
|
||||
LOG_ERR("no XDG shell interface");
|
||||
goto out;
|
||||
}
|
||||
if (!term.wl->have_argb8888) {
|
||||
LOG_ERR("compositor does not support ARGB surfaces");
|
||||
goto out;
|
||||
}
|
||||
if (term.wl->seat == NULL) {
|
||||
LOG_ERR("no seat available");
|
||||
goto out;
|
||||
}
|
||||
if (term.wl->data_device_manager == NULL) {
|
||||
LOG_ERR("no clipboard available "
|
||||
"(wl_data_device_manager not implemented by server)");
|
||||
goto out;
|
||||
}
|
||||
if (term.wl->primary_selection_device_manager == NULL)
|
||||
LOG_WARN("no primary selection available");
|
||||
|
||||
tll_foreach(term.wl->monitors, it) {
|
||||
LOG_INFO("%s: %dx%d+%dx%d (scale=%d, refresh=%.2fHz)",
|
||||
it->item.name, it->item.width_px, it->item.height_px,
|
||||
it->item.x, it->item.y, it->item.scale, it->item.refresh);
|
||||
}
|
||||
|
||||
/* Clipboard */
|
||||
term.wl->data_device = wl_data_device_manager_get_data_device(
|
||||
term.wl->data_device_manager, term.wl->seat);
|
||||
wl_data_device_add_listener(term.wl->data_device, &data_device_listener, term.wl);
|
||||
|
||||
/* Primary selection */
|
||||
if (term.wl->primary_selection_device_manager != NULL) {
|
||||
term.wl->primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(
|
||||
term.wl->primary_selection_device_manager, term.wl->seat);
|
||||
zwp_primary_selection_device_v1_add_listener(
|
||||
term.wl->primary_selection_device, &primary_selection_device_listener, term.wl);
|
||||
}
|
||||
|
||||
/* Cursor */
|
||||
unsigned cursor_size = 24;
|
||||
const char *cursor_theme = getenv("XCURSOR_THEME");
|
||||
|
||||
{
|
||||
const char *env_cursor_size = getenv("XCURSOR_SIZE");
|
||||
if (env_cursor_size != NULL) {
|
||||
unsigned size;
|
||||
if (sscanf(env_cursor_size, "%u", &size) == 1)
|
||||
cursor_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: theme is (re)loaded on scale and output changes */
|
||||
LOG_INFO("cursor theme: %s, size: %u", cursor_theme, cursor_size);
|
||||
term.wl->pointer.size = cursor_size;
|
||||
term.wl->pointer.theme_name = cursor_theme != NULL ? strdup(cursor_theme) : NULL;
|
||||
|
||||
term.wl->pointer.surface = wl_compositor_create_surface(term.wl->compositor);
|
||||
if (term.wl->pointer.surface == NULL) {
|
||||
LOG_ERR("failed to create cursor surface");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Main window */
|
||||
term.window.surface = wl_compositor_create_surface(term.wl->compositor);
|
||||
if (term.window.surface == NULL) {
|
||||
LOG_ERR("failed to create wayland surface");
|
||||
term.window = wayl_win_init(wayl);
|
||||
if (term.window == NULL)
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl_surface_add_listener(term.window.surface, &surface_listener, term.wl);
|
||||
|
||||
term.window.xdg_surface = xdg_wm_base_get_xdg_surface(term.wl->shell, term.window.surface);
|
||||
xdg_surface_add_listener(term.window.xdg_surface, &xdg_surface_listener, term.wl);
|
||||
|
||||
term.window.xdg_toplevel = xdg_surface_get_toplevel(term.window.xdg_surface);
|
||||
xdg_toplevel_add_listener(term.window.xdg_toplevel, &xdg_toplevel_listener, term.wl);
|
||||
|
||||
xdg_toplevel_set_app_id(term.window.xdg_toplevel, "foot");
|
||||
term_set_window_title(&term, "foot");
|
||||
|
||||
/* Request server-side decorations */
|
||||
term.window.xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
|
||||
term.wl->xdg_decoration_manager, term.window.xdg_toplevel);
|
||||
zxdg_toplevel_decoration_v1_set_mode(
|
||||
term.window.xdg_toplevel_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
zxdg_toplevel_decoration_v1_add_listener(
|
||||
term.window.xdg_toplevel_decoration, &xdg_toplevel_decoration_listener, term.wl);
|
||||
|
||||
/* Scrollback search box */
|
||||
term.window.search_surface = wl_compositor_create_surface(term.wl->compositor);
|
||||
term.window.search_sub_surface = wl_subcompositor_get_subsurface(
|
||||
term.wl->sub_compositor, term.window.search_surface, term.window.surface);
|
||||
wl_subsurface_set_desync(term.window.search_sub_surface);
|
||||
|
||||
wl_surface_commit(term.window.surface);
|
||||
wl_display_roundtrip(term.wl->display);
|
||||
|
||||
if (conf.width == -1) {
|
||||
assert(conf.height == -1);
|
||||
conf.width = 80 * term.cell_width;
|
||||
conf.height = 24 * term.cell_height;
|
||||
}
|
||||
|
||||
conf.width = max(conf.width, term.cell_width);
|
||||
conf.height = max(conf.height, term.cell_height);
|
||||
render_resize(&term, conf.width, conf.height);
|
||||
|
|
@ -1116,9 +650,6 @@ main(int argc, char *const *argv)
|
|||
}
|
||||
}
|
||||
|
||||
if ((fdm = fdm_init()) == NULL)
|
||||
goto out;
|
||||
|
||||
fdm_add(fdm, wl_display_get_fd(term.wl->display), EPOLLIN, &fdm_wayl, term.wl);
|
||||
fdm_add(fdm, term.ptmx, EPOLLIN, &fdm_ptmx, &term);
|
||||
fdm_add(fdm, term.wl->kbd.repeat.fd, EPOLLIN, &fdm_repeat, term.wl);
|
||||
|
|
@ -1163,8 +694,8 @@ out:
|
|||
|
||||
shm_fini();
|
||||
|
||||
wayl_win_destroy(&term.window);
|
||||
wayl_destroy(&wayl);
|
||||
wayl_win_destroy(term.window);
|
||||
wayl_destroy(wayl);
|
||||
|
||||
free(term.vt.osc.data);
|
||||
for (int row = 0; row < term.normal.num_rows; row++)
|
||||
|
|
|
|||
56
render.c
56
render.c
|
|
@ -331,7 +331,7 @@ grid_render_scroll(struct terminal *term, struct buffer *buf,
|
|||
height * buf->stride);
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window.surface, term->x_margin, dst_y, term->width - term->x_margin, height);
|
||||
term->window->surface, term->x_margin, dst_y, term->width - term->x_margin, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -357,7 +357,7 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf,
|
|||
height * buf->stride);
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window.surface, term->x_margin, dst_y, term->width - term->x_margin, height);
|
||||
term->window->surface, term->x_margin, dst_y, term->width - term->x_margin, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -441,7 +441,7 @@ grid_render(struct terminal *term)
|
|||
assert(term->height > 0);
|
||||
|
||||
struct buffer *buf = shm_get_buffer(term->wl->shm, term->width, term->height, 1 + term->render.workers.count);
|
||||
wl_surface_attach(term->window.surface, buf->wl_buf, 0, 0);
|
||||
wl_surface_attach(term->window->surface, buf->wl_buf, 0, 0);
|
||||
pixman_image_t *pix = buf->pix;
|
||||
|
||||
bool all_clean = tll_length(term->grid->scroll_damage) == 0;
|
||||
|
|
@ -489,13 +489,13 @@ grid_render(struct terminal *term)
|
|||
{0, bmargin, term->width, bmargin_height}}); /* Bottom */
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window.surface, 0, 0, term->width, term->y_margin);
|
||||
term->window->surface, 0, 0, term->width, term->y_margin);
|
||||
wl_surface_damage_buffer(
|
||||
term->window.surface, 0, 0, term->x_margin, term->height);
|
||||
term->window->surface, 0, 0, term->x_margin, term->height);
|
||||
wl_surface_damage_buffer(
|
||||
term->window.surface, rmargin, 0, rmargin_width, term->height);
|
||||
term->window->surface, rmargin, 0, rmargin_width, term->height);
|
||||
wl_surface_damage_buffer(
|
||||
term->window.surface, 0, bmargin, term->width, bmargin_height);
|
||||
term->window->surface, 0, bmargin, term->width, bmargin_height);
|
||||
|
||||
/* Force a full grid refresh */
|
||||
term_damage_view(term);
|
||||
|
|
@ -516,7 +516,7 @@ grid_render(struct terminal *term)
|
|||
render_cell(term, pix, cell, at.col, at.row, false);
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window.surface,
|
||||
term->window->surface,
|
||||
term->x_margin + at.col * term->cell_width,
|
||||
term->y_margin + at.row * term->cell_height,
|
||||
term->cell_width, term->cell_height);
|
||||
|
|
@ -569,7 +569,7 @@ grid_render(struct terminal *term)
|
|||
all_clean = false;
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window.surface,
|
||||
term->window->surface,
|
||||
term->x_margin, term->y_margin + r * term->cell_height,
|
||||
term->width - term->x_margin, term->cell_height);
|
||||
}
|
||||
|
|
@ -592,7 +592,7 @@ grid_render(struct terminal *term)
|
|||
all_clean = false;
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window.surface,
|
||||
term->window->surface,
|
||||
term->x_margin, term->y_margin + r * term->cell_height,
|
||||
term->width - term->x_margin, term->cell_height);
|
||||
}
|
||||
|
|
@ -674,7 +674,7 @@ grid_render(struct terminal *term)
|
|||
term, pix, cell, term->cursor.col, view_aligned_row, true);
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window.surface,
|
||||
term->window->surface,
|
||||
term->x_margin + term->cursor.col * term->cell_width,
|
||||
term->y_margin + view_aligned_row * term->cell_height,
|
||||
cols_updated * term->cell_width, term->cell_height);
|
||||
|
|
@ -694,18 +694,18 @@ grid_render(struct terminal *term)
|
|||
1, &(pixman_rectangle16_t){0, 0, term->width, term->height});
|
||||
|
||||
wl_surface_damage_buffer(
|
||||
term->window.surface, 0, 0, term->width, term->height);
|
||||
term->window->surface, 0, 0, term->width, term->height);
|
||||
}
|
||||
|
||||
assert(term->grid->offset >= 0 && term->grid->offset < term->grid->num_rows);
|
||||
assert(term->grid->view >= 0 && term->grid->view < term->grid->num_rows);
|
||||
|
||||
assert(term->window.frame_callback == NULL);
|
||||
term->window.frame_callback = wl_surface_frame(term->window.surface);
|
||||
wl_callback_add_listener(term->window.frame_callback, &frame_listener, term);
|
||||
assert(term->window->frame_callback == NULL);
|
||||
term->window->frame_callback = wl_surface_frame(term->window->surface);
|
||||
wl_callback_add_listener(term->window->frame_callback, &frame_listener, term);
|
||||
|
||||
wl_surface_set_buffer_scale(term->window.surface, term->scale);
|
||||
wl_surface_commit(term->window.surface);
|
||||
wl_surface_set_buffer_scale(term->window->surface, term->scale);
|
||||
wl_surface_commit(term->window->surface);
|
||||
|
||||
#if TIME_FRAME_RENDERING
|
||||
struct timeval end_time;
|
||||
|
|
@ -723,16 +723,16 @@ frame_callback(void *data, struct wl_callback *wl_callback, uint32_t callback_da
|
|||
{
|
||||
struct terminal *term = data;
|
||||
|
||||
assert(term->window.frame_callback == wl_callback);
|
||||
assert(term->window->frame_callback == wl_callback);
|
||||
wl_callback_destroy(wl_callback);
|
||||
term->window.frame_callback = NULL;
|
||||
term->window->frame_callback = NULL;
|
||||
grid_render(term);
|
||||
}
|
||||
|
||||
void
|
||||
render_search_box(struct terminal *term)
|
||||
{
|
||||
assert(term->window.search_sub_surface != NULL);
|
||||
assert(term->window->search_sub_surface != NULL);
|
||||
|
||||
/* TODO: at least sway allows the subsurface to extend outside the
|
||||
* main window. Do we want that? */
|
||||
|
|
@ -780,13 +780,13 @@ render_search_box(struct terminal *term)
|
|||
draw_bar(term, buf->pix, font, &fg, x, y);
|
||||
|
||||
wl_subsurface_set_position(
|
||||
term->window.search_sub_surface,
|
||||
term->window->search_sub_surface,
|
||||
term->width - width - margin, term->height - height - margin);
|
||||
|
||||
wl_surface_damage_buffer(term->window.search_surface, 0, 0, width, height);
|
||||
wl_surface_attach(term->window.search_surface, buf->wl_buf, 0, 0);
|
||||
wl_surface_set_buffer_scale(term->window.search_surface, scale);
|
||||
wl_surface_commit(term->window.search_surface);
|
||||
wl_surface_damage_buffer(term->window->search_surface, 0, 0, width, height);
|
||||
wl_surface_attach(term->window->search_surface, buf->wl_buf, 0, 0);
|
||||
wl_surface_set_buffer_scale(term->window->search_surface, scale);
|
||||
wl_surface_commit(term->window->search_surface);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -818,7 +818,7 @@ void
|
|||
render_resize(struct terminal *term, int width, int height)
|
||||
{
|
||||
int scale = -1;
|
||||
tll_foreach(term->window.on_outputs, it) {
|
||||
tll_foreach(term->window->on_outputs, it) {
|
||||
if (it->item->scale > scale)
|
||||
scale = it->item->scale;
|
||||
}
|
||||
|
|
@ -939,7 +939,7 @@ render_resize(struct terminal *term, int width, int height)
|
|||
void
|
||||
render_set_title(struct terminal *term, const char *title)
|
||||
{
|
||||
xdg_toplevel_set_title(term->window.xdg_toplevel, title);
|
||||
xdg_toplevel_set_title(term->window->xdg_toplevel, title);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
@ -1000,6 +1000,6 @@ render_update_cursor_surface(struct terminal *term)
|
|||
void
|
||||
render_refresh(struct terminal *term)
|
||||
{
|
||||
if (term->window.frame_callback == NULL)
|
||||
if (term->window->frame_callback == NULL)
|
||||
grid_render(term);
|
||||
}
|
||||
|
|
|
|||
4
search.c
4
search.c
|
|
@ -19,8 +19,8 @@
|
|||
static void
|
||||
search_cancel_keep_selection(struct terminal *term)
|
||||
{
|
||||
wl_surface_attach(term->window.search_surface, NULL, 0, 0);
|
||||
wl_surface_commit(term->window.search_surface);
|
||||
wl_surface_attach(term->window->search_surface, NULL, 0, 0);
|
||||
wl_surface_commit(term->window->search_surface);
|
||||
|
||||
free(term->search.buf);
|
||||
term->search.buf = NULL;
|
||||
|
|
|
|||
|
|
@ -247,7 +247,7 @@ struct terminal {
|
|||
} fextents;
|
||||
|
||||
struct wayland *wl;
|
||||
struct wl_window window;
|
||||
struct wl_window *window;
|
||||
|
||||
struct {
|
||||
int scrollback_lines;
|
||||
|
|
|
|||
518
wayland.c
518
wayland.c
|
|
@ -1,5 +1,8 @@
|
|||
#include "wayland.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/timerfd.h>
|
||||
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-cursor.h>
|
||||
#include <xdg-shell.h>
|
||||
|
|
@ -14,10 +17,471 @@
|
|||
|
||||
#include "tllist.h"
|
||||
#include "terminal.h"
|
||||
#include "input.h"
|
||||
#include "render.h"
|
||||
#include "selection.h"
|
||||
|
||||
void
|
||||
wayl_init(struct wayland *wayl)
|
||||
#define min(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define max(x, y) ((x) > (y) ? (x) : (y))
|
||||
|
||||
static void
|
||||
shm_format(void *data, struct wl_shm *wl_shm, uint32_t format)
|
||||
{
|
||||
struct wayland *wayl = data;
|
||||
if (format == WL_SHM_FORMAT_ARGB8888)
|
||||
wayl->have_argb8888 = true;
|
||||
}
|
||||
|
||||
static const struct wl_shm_listener shm_listener = {
|
||||
.format = &shm_format,
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
|
||||
{
|
||||
LOG_DBG("wm base ping");
|
||||
xdg_wm_base_pong(shell, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
||||
.ping = &xdg_wm_base_ping,
|
||||
};
|
||||
|
||||
static void
|
||||
seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
||||
enum wl_seat_capability caps)
|
||||
{
|
||||
struct wayland *wayl = data;
|
||||
|
||||
if (wayl->keyboard != NULL) {
|
||||
wl_keyboard_release(wayl->keyboard);
|
||||
wayl->keyboard = NULL;
|
||||
}
|
||||
|
||||
if (wayl->pointer.pointer != NULL) {
|
||||
wl_pointer_release(wayl->pointer.pointer);
|
||||
wayl->pointer.pointer = NULL;
|
||||
}
|
||||
|
||||
if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
|
||||
wayl->keyboard = wl_seat_get_keyboard(wl_seat);
|
||||
wl_keyboard_add_listener(wayl->keyboard, &keyboard_listener, wayl);
|
||||
}
|
||||
|
||||
if (caps & WL_SEAT_CAPABILITY_POINTER) {
|
||||
wayl->pointer.pointer = wl_seat_get_pointer(wl_seat);
|
||||
wl_pointer_add_listener(wayl->pointer.pointer, &pointer_listener, wayl);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_seat_listener seat_listener = {
|
||||
.capabilities = seat_handle_capabilities,
|
||||
.name = seat_handle_name,
|
||||
};
|
||||
|
||||
static void
|
||||
output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y,
|
||||
int32_t physical_width, int32_t physical_height,
|
||||
int32_t subpixel, const char *make, const char *model,
|
||||
int32_t transform)
|
||||
{
|
||||
struct monitor *mon = data;
|
||||
mon->width_mm = physical_width;
|
||||
mon->height_mm = physical_height;
|
||||
}
|
||||
|
||||
static void
|
||||
output_mode(void *data, struct wl_output *wl_output, uint32_t flags,
|
||||
int32_t width, int32_t height, int32_t refresh)
|
||||
{
|
||||
if ((flags & WL_OUTPUT_MODE_CURRENT) == 0)
|
||||
return;
|
||||
|
||||
struct monitor *mon = data;
|
||||
mon->refresh = (float)refresh / 1000;
|
||||
}
|
||||
|
||||
static void
|
||||
output_done(void *data, struct wl_output *wl_output)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
output_scale(void *data, struct wl_output *wl_output, int32_t factor)
|
||||
{
|
||||
struct monitor *mon = data;
|
||||
|
||||
mon->scale = factor;
|
||||
|
||||
struct terminal *term = mon->wayl->term;
|
||||
if (term != NULL) {
|
||||
render_resize(term, term->width / term->scale, term->height / term->scale);
|
||||
render_reload_cursor_theme(term);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_output_listener output_listener = {
|
||||
.geometry = &output_geometry,
|
||||
.mode = &output_mode,
|
||||
.done = &output_done,
|
||||
.scale = &output_scale,
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_output_handle_logical_position(
|
||||
void *data, struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y)
|
||||
{
|
||||
struct monitor *mon = data;
|
||||
mon->x = x;
|
||||
mon->y = y;
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output,
|
||||
int32_t width, int32_t height)
|
||||
{
|
||||
struct monitor *mon = data;
|
||||
mon->width_px = width;
|
||||
mon->height_px = height;
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output,
|
||||
const char *name)
|
||||
{
|
||||
struct monitor *mon = data;
|
||||
mon->name = strdup(name);
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output,
|
||||
const char *description)
|
||||
{
|
||||
}
|
||||
|
||||
static struct zxdg_output_v1_listener xdg_output_listener = {
|
||||
.logical_position = xdg_output_handle_logical_position,
|
||||
.logical_size = xdg_output_handle_logical_size,
|
||||
.done = xdg_output_handle_done,
|
||||
.name = xdg_output_handle_name,
|
||||
.description = xdg_output_handle_description,
|
||||
};
|
||||
|
||||
static void
|
||||
handle_global(void *data, struct wl_registry *registry,
|
||||
uint32_t name, const char *interface, uint32_t version)
|
||||
{
|
||||
LOG_DBG("global: %s, version=%u", interface, version);
|
||||
struct wayland *wayl = data;
|
||||
|
||||
if (strcmp(interface, wl_compositor_interface.name) == 0) {
|
||||
wayl->compositor = wl_registry_bind(
|
||||
wayl->registry, name, &wl_compositor_interface, 4);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, wl_subcompositor_interface.name) == 0) {
|
||||
wayl->sub_compositor = wl_registry_bind(
|
||||
wayl->registry, name, &wl_subcompositor_interface, 1);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, wl_shm_interface.name) == 0) {
|
||||
wayl->shm = wl_registry_bind(
|
||||
wayl->registry, name, &wl_shm_interface, 1);
|
||||
wl_shm_add_listener(wayl->shm, &shm_listener, wayl);
|
||||
wl_display_roundtrip(wayl->display);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
|
||||
wayl->shell = wl_registry_bind(
|
||||
wayl->registry, name, &xdg_wm_base_interface, 1);
|
||||
xdg_wm_base_add_listener(wayl->shell, &xdg_wm_base_listener, wayl);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, zxdg_decoration_manager_v1_interface.name) == 0)
|
||||
wayl->xdg_decoration_manager = wl_registry_bind(
|
||||
wayl->registry, name, &zxdg_decoration_manager_v1_interface, 1);
|
||||
|
||||
else if (strcmp(interface, wl_seat_interface.name) == 0) {
|
||||
wayl->seat = wl_registry_bind(
|
||||
wayl->registry, name, &wl_seat_interface, 5);
|
||||
wl_seat_add_listener(wayl->seat, &seat_listener, wayl);
|
||||
wl_display_roundtrip(wayl->display);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0) {
|
||||
wayl->xdg_output_manager = wl_registry_bind(
|
||||
wayl->registry, name, &zxdg_output_manager_v1_interface, min(version, 2));
|
||||
}
|
||||
|
||||
else if (strcmp(interface, wl_output_interface.name) == 0) {
|
||||
struct wl_output *output = wl_registry_bind(
|
||||
wayl->registry, name, &wl_output_interface, 3);
|
||||
|
||||
tll_push_back(
|
||||
wayl->monitors, ((struct monitor){.wayl = wayl, .output = output}));
|
||||
|
||||
struct monitor *mon = &tll_back(wayl->monitors);
|
||||
wl_output_add_listener(output, &output_listener, mon);
|
||||
|
||||
mon->xdg = zxdg_output_manager_v1_get_xdg_output(
|
||||
wayl->xdg_output_manager, mon->output);
|
||||
zxdg_output_v1_add_listener(mon->xdg, &xdg_output_listener, mon);
|
||||
wl_display_roundtrip(wayl->display);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) {
|
||||
wayl->data_device_manager = wl_registry_bind(
|
||||
wayl->registry, name, &wl_data_device_manager_interface, 1);
|
||||
}
|
||||
|
||||
else if (strcmp(interface, zwp_primary_selection_device_manager_v1_interface.name) == 0) {
|
||||
wayl->primary_selection_device_manager = wl_registry_bind(
|
||||
wayl->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
surface_enter(void *data, struct wl_surface *wl_surface,
|
||||
struct wl_output *wl_output)
|
||||
{
|
||||
struct wayland *wayl = data;
|
||||
struct terminal *term = wayl_terminal_from_surface(wayl, wl_surface);
|
||||
|
||||
tll_foreach(wayl->monitors, it) {
|
||||
if (it->item.output == wl_output) {
|
||||
LOG_DBG("mapped on %s", it->item.name);
|
||||
tll_push_back(term->window->on_outputs, &it->item);
|
||||
|
||||
/* Resize, since scale-to-use may have changed */
|
||||
render_resize(term, term->width / term->scale, term->height / term->scale);
|
||||
render_reload_cursor_theme(term);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERR("mapped on unknown output");
|
||||
}
|
||||
|
||||
static void
|
||||
surface_leave(void *data, struct wl_surface *wl_surface,
|
||||
struct wl_output *wl_output)
|
||||
{
|
||||
struct wayland *wayl = data;
|
||||
struct terminal *term = wayl_terminal_from_surface(wayl, wl_surface);
|
||||
|
||||
tll_foreach(term->window->on_outputs, it) {
|
||||
if (it->item->output != wl_output)
|
||||
continue;
|
||||
|
||||
LOG_DBG("unmapped from %s", it->item->name);
|
||||
tll_remove(term->window->on_outputs, it);
|
||||
|
||||
/* Resize, since scale-to-use may have changed */
|
||||
render_resize(term, term->width / term->scale, term->height / term->scale);
|
||||
render_reload_cursor_theme(term);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_ERR("unmapped from unknown output");
|
||||
}
|
||||
|
||||
static const struct wl_surface_listener surface_listener = {
|
||||
.enter = &surface_enter,
|
||||
.leave = &surface_leave,
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
|
||||
int32_t width, int32_t height, struct wl_array *states)
|
||||
{
|
||||
LOG_DBG("xdg-toplevel: configure: %dx%d", width, height);
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
struct wayland *wayl = data;
|
||||
struct terminal *term = wayl_terminal_from_xdg_toplevel(wayl, xdg_toplevel);
|
||||
render_resize(term, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
xdg_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
|
||||
{
|
||||
struct wayland *wayl = data;
|
||||
struct terminal *term = wayl_terminal_from_xdg_toplevel(wayl, xdg_toplevel);
|
||||
LOG_DBG("xdg-toplevel: close");
|
||||
|
||||
term->quit = true;
|
||||
wl_display_roundtrip(wayl->display);
|
||||
}
|
||||
|
||||
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
||||
.configure = &xdg_toplevel_configure,
|
||||
.close = &xdg_toplevel_close,
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_surface_configure(void *data, struct xdg_surface *xdg_surface,
|
||||
uint32_t serial)
|
||||
{
|
||||
//LOG_DBG("xdg-surface: configure");
|
||||
xdg_surface_ack_configure(xdg_surface, serial);
|
||||
}
|
||||
|
||||
static const struct xdg_surface_listener xdg_surface_listener = {
|
||||
.configure = &xdg_surface_configure,
|
||||
};
|
||||
|
||||
static void
|
||||
xdg_toplevel_decoration_configure(void *data,
|
||||
struct zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1,
|
||||
uint32_t mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE:
|
||||
LOG_ERR("unimplemented: client-side decorations");
|
||||
break;
|
||||
|
||||
case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE:
|
||||
LOG_DBG("using server-side decorations");
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_ERR("unimplemented: unknown XDG toplevel decoration mode: %u", mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct zxdg_toplevel_decoration_v1_listener xdg_toplevel_decoration_listener = {
|
||||
.configure = &xdg_toplevel_decoration_configure,
|
||||
};
|
||||
|
||||
static void
|
||||
handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
|
||||
{
|
||||
LOG_WARN("global removed: %u", name);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
.global = &handle_global,
|
||||
.global_remove = &handle_global_remove,
|
||||
};
|
||||
|
||||
struct wayland *
|
||||
wayl_init(struct fdm *fdm)
|
||||
{
|
||||
struct wayland *wayl = calloc(1, sizeof(*wayl));
|
||||
wayl->fdm = fdm;
|
||||
|
||||
wayl->display = wl_display_connect(NULL);
|
||||
if (wayl->display == NULL) {
|
||||
LOG_ERR("failed to connect to wayland; no compositor running?");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wayl->registry = wl_display_get_registry(wayl->display);
|
||||
if (wayl->registry == NULL) {
|
||||
LOG_ERR("failed to get wayland registry");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl_registry_add_listener(wayl->registry, ®istry_listener, wayl);
|
||||
wl_display_roundtrip(wayl->display);
|
||||
|
||||
if (wayl->compositor == NULL) {
|
||||
LOG_ERR("no compositor");
|
||||
goto out;
|
||||
}
|
||||
if (wayl->shm == NULL) {
|
||||
LOG_ERR("no shared memory buffers interface");
|
||||
goto out;
|
||||
}
|
||||
if (wayl->shell == NULL) {
|
||||
LOG_ERR("no XDG shell interface");
|
||||
goto out;
|
||||
}
|
||||
if (!wayl->have_argb8888) {
|
||||
LOG_ERR("compositor does not support ARGB surfaces");
|
||||
goto out;
|
||||
}
|
||||
if (wayl->seat == NULL) {
|
||||
LOG_ERR("no seat available");
|
||||
goto out;
|
||||
}
|
||||
if (wayl->data_device_manager == NULL) {
|
||||
LOG_ERR("no clipboard available "
|
||||
"(wl_data_device_manager not implemented by server)");
|
||||
goto out;
|
||||
}
|
||||
if (wayl->primary_selection_device_manager == NULL)
|
||||
LOG_WARN("no primary selection available");
|
||||
|
||||
tll_foreach(wayl->monitors, it) {
|
||||
LOG_INFO("%s: %dx%d+%dx%d (scale=%d, refresh=%.2fHz)",
|
||||
it->item.name, it->item.width_px, it->item.height_px,
|
||||
it->item.x, it->item.y, it->item.scale, it->item.refresh);
|
||||
}
|
||||
|
||||
/* Clipboard */
|
||||
wayl->data_device = wl_data_device_manager_get_data_device(
|
||||
wayl->data_device_manager, wayl->seat);
|
||||
wl_data_device_add_listener(wayl->data_device, &data_device_listener, wayl);
|
||||
|
||||
/* Primary selection */
|
||||
if (wayl->primary_selection_device_manager != NULL) {
|
||||
wayl->primary_selection_device = zwp_primary_selection_device_manager_v1_get_device(
|
||||
wayl->primary_selection_device_manager, wayl->seat);
|
||||
zwp_primary_selection_device_v1_add_listener(
|
||||
wayl->primary_selection_device, &primary_selection_device_listener, wayl);
|
||||
}
|
||||
|
||||
/* Cursor */
|
||||
unsigned cursor_size = 24;
|
||||
const char *cursor_theme = getenv("XCURSOR_THEME");
|
||||
|
||||
{
|
||||
const char *env_cursor_size = getenv("XCURSOR_SIZE");
|
||||
if (env_cursor_size != NULL) {
|
||||
unsigned size;
|
||||
if (sscanf(env_cursor_size, "%u", &size) == 1)
|
||||
cursor_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: theme is (re)loaded on scale and output changes */
|
||||
LOG_INFO("cursor theme: %s, size: %u", cursor_theme, cursor_size);
|
||||
wayl->pointer.size = cursor_size;
|
||||
wayl->pointer.theme_name = cursor_theme != NULL ? strdup(cursor_theme) : NULL;
|
||||
|
||||
wayl->pointer.surface = wl_compositor_create_surface(wayl->compositor);
|
||||
if (wayl->pointer.surface == NULL) {
|
||||
LOG_ERR("failed to create cursor surface");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wayl->kbd.repeat.fd = timerfd_create(CLOCK_BOOTTIME, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||
if (wayl->kbd.repeat.fd == -1) {
|
||||
LOG_ERRNO("failed to create keyboard repeat timer FD");
|
||||
goto out;
|
||||
}
|
||||
|
||||
return wayl;
|
||||
|
||||
out:
|
||||
if (wayl != NULL)
|
||||
wayl_destroy(wayl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -93,6 +557,52 @@ wayl_destroy(struct wayland *wayl)
|
|||
wl_display_disconnect(wayl->display);
|
||||
}
|
||||
|
||||
struct wl_window *
|
||||
wayl_win_init(struct wayland *wayl)
|
||||
{
|
||||
struct wl_window *win = calloc(1, sizeof(*win));
|
||||
|
||||
win->surface = wl_compositor_create_surface(wayl->compositor);
|
||||
if (win->surface == NULL) {
|
||||
LOG_ERR("failed to create wayland surface");
|
||||
goto out;
|
||||
}
|
||||
|
||||
wl_surface_add_listener(win->surface, &surface_listener, wayl);
|
||||
|
||||
win->xdg_surface = xdg_wm_base_get_xdg_surface(wayl->shell, win->surface);
|
||||
xdg_surface_add_listener(win->xdg_surface, &xdg_surface_listener, wayl);
|
||||
|
||||
win->xdg_toplevel = xdg_surface_get_toplevel(win->xdg_surface);
|
||||
xdg_toplevel_add_listener(win->xdg_toplevel, &xdg_toplevel_listener, wayl);
|
||||
|
||||
xdg_toplevel_set_app_id(win->xdg_toplevel, "foot");
|
||||
|
||||
/* Request server-side decorations */
|
||||
win->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
|
||||
wayl->xdg_decoration_manager, win->xdg_toplevel);
|
||||
zxdg_toplevel_decoration_v1_set_mode(
|
||||
win->xdg_toplevel_decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
|
||||
zxdg_toplevel_decoration_v1_add_listener(
|
||||
win->xdg_toplevel_decoration, &xdg_toplevel_decoration_listener, wayl);
|
||||
|
||||
/* Scrollback search box */
|
||||
win->search_surface = wl_compositor_create_surface(wayl->compositor);
|
||||
win->search_sub_surface = wl_subcompositor_get_subsurface(
|
||||
wayl->sub_compositor, win->search_surface, win->surface);
|
||||
wl_subsurface_set_desync(win->search_sub_surface);
|
||||
|
||||
wl_surface_commit(win->surface);
|
||||
wl_display_roundtrip(wayl->display);
|
||||
|
||||
return win;
|
||||
|
||||
out:
|
||||
if (win != NULL)
|
||||
wayl_win_destroy(win);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
wayl_win_destroy(struct wl_window *win)
|
||||
{
|
||||
|
|
@ -116,7 +626,7 @@ wayl_win_destroy(struct wl_window *win)
|
|||
struct terminal *
|
||||
wayl_terminal_from_surface(struct wayland *wayl, struct wl_surface *surface)
|
||||
{
|
||||
assert(surface == wayl->term->window.surface);
|
||||
assert(surface == wayl->term->window->surface);
|
||||
return wayl->term;
|
||||
}
|
||||
|
||||
|
|
@ -124,6 +634,6 @@ struct terminal *
|
|||
wayl_terminal_from_xdg_toplevel(struct wayland *wayl,
|
||||
struct xdg_toplevel *toplevel)
|
||||
{
|
||||
assert(toplevel == wayl->term->window.xdg_toplevel);
|
||||
assert(toplevel == wayl->term->window->xdg_toplevel);
|
||||
return wayl->term;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <primary-selection-unstable-v1.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "fdm.h"
|
||||
#include "tllist.h"
|
||||
|
||||
struct monitor {
|
||||
|
|
@ -89,6 +90,7 @@ struct wl_window {
|
|||
|
||||
struct terminal;
|
||||
struct wayland {
|
||||
struct fdm *fdm;
|
||||
struct wl_display *display;
|
||||
struct wl_registry *registry;
|
||||
struct wl_compositor *compositor;
|
||||
|
|
@ -149,8 +151,7 @@ struct wayland {
|
|||
struct terminal *moused;
|
||||
};
|
||||
|
||||
/* TODO: return allocated pointer */
|
||||
void wayl_init(struct wayland *wayl);
|
||||
struct wayland *wayl_init(struct fdm *fdm);
|
||||
void wayl_destroy(struct wayland *wayl);
|
||||
|
||||
struct terminal *wayl_terminal_from_surface(
|
||||
|
|
@ -160,4 +161,5 @@ struct terminal *wayl_terminal_from_xdg_surface(
|
|||
struct terminal *wayl_terminal_from_xdg_toplevel(
|
||||
struct wayland *wayl, struct xdg_toplevel *toplevel);
|
||||
|
||||
struct wl_window *wayl_win_init(struct wayland *wayl);
|
||||
void wayl_win_destroy(struct wl_window *win);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue