2020-09-11 01:25:28 -07:00
|
|
|
#include "proto/virtual-keyboard-unstable-v1-client-protocol.h"
|
|
|
|
#include "proto/wlr-layer-shell-unstable-v1-client-protocol.h"
|
2023-09-06 09:28:09 +02:00
|
|
|
#include "proto/xdg-shell-client-protocol.h"
|
2023-09-08 23:22:56 +02:00
|
|
|
#include "proto/fractional-scale-v1-client-protocol.h"
|
|
|
|
#include "proto/viewporter-client-protocol.h"
|
2023-09-18 14:58:39 +00:00
|
|
|
#include <errno.h>
|
2020-09-11 01:25:28 -07:00
|
|
|
#include <linux/input-event-codes.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/mman.h>
|
2022-07-05 12:54:32 -04:00
|
|
|
#include <sys/signalfd.h>
|
2023-09-08 23:22:56 +02:00
|
|
|
#include <poll.h>
|
2021-09-19 14:23:51 +02:00
|
|
|
#include <unistd.h>
|
2023-08-29 14:23:19 +02:00
|
|
|
#include <wayland-client-protocol.h>
|
2020-09-11 01:25:28 -07:00
|
|
|
#include <wayland-client.h>
|
2021-08-24 09:53:34 +02:00
|
|
|
#include <wchar.h>
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
#include "keyboard.h"
|
2023-09-08 23:22:56 +02:00
|
|
|
#include "config.h"
|
2020-09-11 01:25:28 -07:00
|
|
|
|
|
|
|
/* lazy die macro */
|
|
|
|
#define die(...) \
|
2023-09-08 22:56:50 +02:00
|
|
|
fprintf(stderr, __VA_ARGS__); \
|
|
|
|
exit(1)
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-10-23 13:59:31 +02:00
|
|
|
/* array size */
|
|
|
|
#define countof(x) (sizeof(x) / sizeof(*x))
|
|
|
|
|
2020-09-11 01:25:28 -07:00
|
|
|
/* client state */
|
|
|
|
static const char *namespace = "wlroots";
|
|
|
|
static struct wl_display *display;
|
|
|
|
static struct wl_compositor *compositor;
|
|
|
|
static struct wl_seat *seat;
|
|
|
|
static struct wl_pointer *pointer;
|
|
|
|
static struct wl_touch *touch;
|
2023-09-06 09:28:09 +02:00
|
|
|
static struct wl_region *empty_region;
|
2020-09-11 01:25:28 -07:00
|
|
|
static struct zwlr_layer_shell_v1 *layer_shell;
|
|
|
|
static struct zwlr_layer_surface_v1 *layer_surface;
|
2023-09-06 09:28:09 +02:00
|
|
|
static struct xdg_wm_base *wm_base;
|
|
|
|
static struct xdg_surface *popup_xdg_surface;
|
|
|
|
static struct xdg_popup *popup_xdg_popup;
|
|
|
|
static struct xdg_positioner *popup_xdg_positioner;
|
2020-09-11 01:25:28 -07:00
|
|
|
static struct zwp_virtual_keyboard_manager_v1 *vkbd_mgr;
|
2023-09-07 21:31:47 +02:00
|
|
|
static struct wp_fractional_scale_v1 *wfs_draw_surf;
|
|
|
|
static struct wp_fractional_scale_manager_v1 *wfs_mgr;
|
|
|
|
static struct wp_viewport *draw_surf_viewport, *popup_draw_surf_viewport;
|
|
|
|
static struct wp_viewporter *viewporter;
|
2024-03-28 20:39:10 +09:00
|
|
|
static bool popup_xdg_surface_configured;
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-08-26 18:15:28 +09:00
|
|
|
struct Output {
|
2023-09-08 22:56:50 +02:00
|
|
|
uint32_t name;
|
|
|
|
uint32_t w, h;
|
|
|
|
double scale;
|
|
|
|
struct wl_output *data;
|
2023-08-26 18:15:28 +09:00
|
|
|
};
|
2023-09-07 21:31:49 +02:00
|
|
|
static struct Output *current_output;
|
2023-08-26 18:15:28 +09:00
|
|
|
|
|
|
|
#define WL_OUTPUTS_LIMIT 8
|
|
|
|
static struct Output wl_outputs[WL_OUTPUTS_LIMIT];
|
2023-09-08 22:42:07 +02:00
|
|
|
static int wl_outputs_size;
|
2023-08-26 18:15:28 +09:00
|
|
|
|
2020-09-11 01:25:28 -07:00
|
|
|
/* drawing */
|
|
|
|
static struct drw draw_ctx;
|
2023-09-06 09:28:09 +02:00
|
|
|
static struct drwsurf draw_surf, popup_draw_surf;
|
2020-09-11 01:25:28 -07:00
|
|
|
|
|
|
|
/* layer surface parameters */
|
2024-11-25 12:31:19 +01:00
|
|
|
static uint32_t layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY;
|
2020-09-11 01:25:28 -07:00
|
|
|
static uint32_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM |
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
|
|
|
|
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
|
|
|
|
|
|
|
/* application state */
|
|
|
|
static bool run_display = true;
|
|
|
|
static int cur_x = -1, cur_y = -1;
|
2021-12-02 11:03:41 -05:00
|
|
|
static bool cur_press = false;
|
2021-08-26 09:16:47 +02:00
|
|
|
static struct kbd keyboard;
|
2021-08-26 19:45:17 +02:00
|
|
|
static uint32_t height, normal_height, landscape_height;
|
2024-04-15 20:38:02 +02:00
|
|
|
static int rounding = DEFAULT_ROUNDING;
|
2022-01-15 22:56:10 +01:00
|
|
|
static bool hidden = false;
|
2020-09-11 01:25:28 -07:00
|
|
|
|
|
|
|
/* event handler prototypes */
|
|
|
|
static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
uint32_t serial, struct wl_surface *surface,
|
|
|
|
wl_fixed_t surface_x, wl_fixed_t surface_y);
|
|
|
|
static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
uint32_t serial, struct wl_surface *surface);
|
|
|
|
static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
uint32_t time, wl_fixed_t surface_x,
|
|
|
|
wl_fixed_t surface_y);
|
|
|
|
static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
uint32_t serial, uint32_t time, uint32_t button,
|
|
|
|
uint32_t state);
|
2023-08-29 14:23:19 +02:00
|
|
|
static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
|
2023-09-08 22:42:07 +02:00
|
|
|
uint32_t time, uint32_t axis, wl_fixed_t value);
|
2020-09-11 01:25:28 -07:00
|
|
|
|
|
|
|
static void wl_touch_down(void *data, struct wl_touch *wl_touch,
|
|
|
|
uint32_t serial, uint32_t time,
|
|
|
|
struct wl_surface *surface, int32_t id, wl_fixed_t x,
|
|
|
|
wl_fixed_t y);
|
|
|
|
static void wl_touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial,
|
|
|
|
uint32_t time, int32_t id);
|
|
|
|
static void wl_touch_motion(void *data, struct wl_touch *wl_touch,
|
|
|
|
uint32_t time, int32_t id, wl_fixed_t x,
|
|
|
|
wl_fixed_t y);
|
|
|
|
static void wl_touch_frame(void *data, struct wl_touch *wl_touch);
|
|
|
|
static void wl_touch_cancel(void *data, struct wl_touch *wl_touch);
|
|
|
|
static void wl_touch_shape(void *data, struct wl_touch *wl_touch, int32_t id,
|
|
|
|
wl_fixed_t major, wl_fixed_t minor);
|
|
|
|
static void wl_touch_orientation(void *data, struct wl_touch *wl_touch,
|
|
|
|
int32_t id, wl_fixed_t orientation);
|
|
|
|
|
|
|
|
static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
|
|
|
enum wl_seat_capability caps);
|
|
|
|
static void seat_handle_name(void *data, struct wl_seat *wl_seat,
|
|
|
|
const char *name);
|
|
|
|
|
2023-08-26 18:15:28 +09:00
|
|
|
static void wl_surface_enter(void *data, struct wl_surface *wl_surface,
|
|
|
|
struct wl_output *wl_output);
|
2023-11-10 20:27:40 +01:00
|
|
|
static void wl_surface_leave(void *data, struct wl_surface *wl_surface,
|
|
|
|
struct wl_output *wl_output);
|
2023-08-26 18:15:28 +09:00
|
|
|
|
2020-09-11 01:25:28 -07:00
|
|
|
static void handle_global(void *data, struct wl_registry *registry,
|
|
|
|
uint32_t name, const char *interface,
|
|
|
|
uint32_t version);
|
|
|
|
static void handle_global_remove(void *data, struct wl_registry *registry,
|
|
|
|
uint32_t name);
|
|
|
|
|
|
|
|
static void layer_surface_configure(void *data,
|
|
|
|
struct zwlr_layer_surface_v1 *surface,
|
|
|
|
uint32_t serial, uint32_t w, uint32_t h);
|
|
|
|
static void layer_surface_closed(void *data,
|
|
|
|
struct zwlr_layer_surface_v1 *surface);
|
2023-09-18 11:59:33 +02:00
|
|
|
static void flip_landscape();
|
2024-03-03 12:52:21 +01:00
|
|
|
static void show();
|
2020-09-11 01:25:28 -07:00
|
|
|
|
|
|
|
/* event handlers */
|
|
|
|
static const struct wl_pointer_listener pointer_listener = {
|
2023-09-08 22:56:50 +02:00
|
|
|
.enter = wl_pointer_enter,
|
|
|
|
.leave = wl_pointer_leave,
|
|
|
|
.motion = wl_pointer_motion,
|
|
|
|
.button = wl_pointer_button,
|
|
|
|
.axis = wl_pointer_axis,
|
2020-09-11 01:25:28 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct wl_touch_listener touch_listener = {
|
2023-09-08 22:56:50 +02:00
|
|
|
.down = wl_touch_down,
|
|
|
|
.up = wl_touch_up,
|
|
|
|
.motion = wl_touch_motion,
|
|
|
|
.frame = wl_touch_frame,
|
|
|
|
.cancel = wl_touch_cancel,
|
|
|
|
.shape = wl_touch_shape,
|
|
|
|
.orientation = wl_touch_orientation,
|
2020-09-11 01:25:28 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct wl_seat_listener seat_listener = {
|
2023-09-08 22:56:50 +02:00
|
|
|
.capabilities = seat_handle_capabilities,
|
|
|
|
.name = seat_handle_name,
|
2020-09-11 01:25:28 -07:00
|
|
|
};
|
|
|
|
|
2023-08-26 18:15:28 +09:00
|
|
|
static const struct wl_surface_listener surface_listener = {
|
2023-09-08 22:56:50 +02:00
|
|
|
.enter = wl_surface_enter,
|
2023-11-10 20:27:40 +01:00
|
|
|
.leave = wl_surface_leave,
|
2023-08-26 18:15:28 +09:00
|
|
|
};
|
|
|
|
|
2020-09-11 01:25:28 -07:00
|
|
|
static const struct wl_registry_listener registry_listener = {
|
2023-09-08 22:56:50 +02:00
|
|
|
.global = handle_global,
|
|
|
|
.global_remove = handle_global_remove,
|
2020-09-11 01:25:28 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
|
2023-09-08 22:56:50 +02:00
|
|
|
.configure = layer_surface_configure,
|
|
|
|
.closed = layer_surface_closed,
|
2020-09-11 01:25:28 -07:00
|
|
|
};
|
|
|
|
|
2021-08-22 23:14:47 +02:00
|
|
|
/* configuration, allows nested code to access above variables */
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
char *
|
|
|
|
estrdup(const char *s)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
char *p;
|
2021-08-24 13:08:49 +02:00
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
if (!(p = strdup(s))) {
|
|
|
|
fprintf(stderr, "strdup:");
|
|
|
|
exit(6);
|
|
|
|
}
|
2021-08-24 13:08:49 +02:00
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
return p;
|
2021-08-24 13:08:49 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_touch_down(void *data, struct wl_touch *wl_touch, uint32_t serial,
|
|
|
|
uint32_t time, struct wl_surface *surface, int32_t id,
|
|
|
|
wl_fixed_t x, wl_fixed_t y)
|
|
|
|
{
|
2024-03-28 20:39:10 +09:00
|
|
|
if(!popup_xdg_surface_configured) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
struct key *next_key;
|
|
|
|
uint32_t touch_x, touch_y;
|
|
|
|
|
|
|
|
touch_x = wl_fixed_to_int(x);
|
|
|
|
touch_y = wl_fixed_to_int(y);
|
|
|
|
|
|
|
|
kbd_unpress_key(&keyboard, time);
|
|
|
|
|
|
|
|
next_key = kbd_get_key(&keyboard, touch_x, touch_y);
|
|
|
|
if (next_key) {
|
|
|
|
kbd_press_key(&keyboard, next_key, time);
|
|
|
|
} else if (keyboard.compose) {
|
|
|
|
keyboard.compose = 0;
|
|
|
|
kbd_switch_layout(&keyboard, keyboard.prevlayout,
|
|
|
|
keyboard.last_abc_index);
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_touch_up(void *data, struct wl_touch *wl_touch, uint32_t serial,
|
|
|
|
uint32_t time, int32_t id)
|
|
|
|
{
|
2024-03-28 20:39:10 +09:00
|
|
|
if(!popup_xdg_surface_configured) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
kbd_release_key(&keyboard, time);
|
2020-09-11 01:25:28 -07:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_touch_motion(void *data, struct wl_touch *wl_touch, uint32_t time,
|
|
|
|
int32_t id, wl_fixed_t x, wl_fixed_t y)
|
|
|
|
{
|
2024-03-28 20:39:10 +09:00
|
|
|
if(!popup_xdg_surface_configured) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
uint32_t touch_x, touch_y;
|
2021-12-02 11:03:41 -05:00
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
touch_x = wl_fixed_to_int(x);
|
|
|
|
touch_y = wl_fixed_to_int(y);
|
2021-12-02 11:03:41 -05:00
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
kbd_motion_key(&keyboard, time, touch_x, touch_y);
|
2020-09-11 01:25:28 -07:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_touch_frame(void *data, struct wl_touch *wl_touch)
|
|
|
|
{
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_touch_cancel(void *data, struct wl_touch *wl_touch)
|
|
|
|
{
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_touch_shape(void *data, struct wl_touch *wl_touch, int32_t id,
|
|
|
|
wl_fixed_t major, wl_fixed_t minor)
|
|
|
|
{
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_touch_orientation(void *data, struct wl_touch *wl_touch, int32_t id,
|
|
|
|
wl_fixed_t orientation)
|
|
|
|
{
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
|
|
|
struct wl_surface *surface, wl_fixed_t surface_x,
|
|
|
|
wl_fixed_t surface_y)
|
|
|
|
{
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
|
|
|
struct wl_surface *surface)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
cur_x = cur_y = -1;
|
2020-09-11 01:25:28 -07:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, uint32_t time,
|
|
|
|
wl_fixed_t surface_x, wl_fixed_t surface_y)
|
|
|
|
{
|
2024-03-28 20:39:10 +09:00
|
|
|
if(!popup_xdg_surface_configured) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
cur_x = wl_fixed_to_int(surface_x);
|
|
|
|
cur_y = wl_fixed_to_int(surface_y);
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
if (cur_press) {
|
|
|
|
kbd_motion_key(&keyboard, time, cur_x, cur_y);
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
|
|
|
|
uint32_t time, uint32_t button, uint32_t state)
|
|
|
|
{
|
2024-03-28 20:39:10 +09:00
|
|
|
if(!popup_xdg_surface_configured) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
struct key *next_key;
|
|
|
|
cur_press = state == WL_POINTER_BUTTON_STATE_PRESSED;
|
|
|
|
|
|
|
|
if (cur_press) {
|
|
|
|
kbd_unpress_key(&keyboard, time);
|
|
|
|
} else {
|
|
|
|
kbd_release_key(&keyboard, time);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cur_press && cur_x >= 0 && cur_y >= 0) {
|
|
|
|
next_key = kbd_get_key(&keyboard, cur_x, cur_y);
|
|
|
|
if (next_key) {
|
|
|
|
kbd_press_key(&keyboard, next_key, time);
|
|
|
|
} else if (keyboard.compose) {
|
|
|
|
keyboard.compose = 0;
|
|
|
|
kbd_switch_layout(&keyboard, keyboard.prevlayout,
|
|
|
|
keyboard.last_abc_index);
|
|
|
|
}
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, uint32_t time,
|
|
|
|
uint32_t axis, wl_fixed_t value)
|
|
|
|
{
|
2024-03-28 20:39:10 +09:00
|
|
|
if(!popup_xdg_surface_configured) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
kbd_next_layer(&keyboard, NULL, (value >= 0));
|
|
|
|
drwsurf_flip(keyboard.surf);
|
2023-08-29 14:23:19 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
|
|
|
|
enum wl_seat_capability caps)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
if ((caps & WL_SEAT_CAPABILITY_POINTER)) {
|
|
|
|
if (pointer == NULL) {
|
|
|
|
pointer = wl_seat_get_pointer(wl_seat);
|
|
|
|
wl_pointer_add_listener(pointer, &pointer_listener, NULL);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (pointer != NULL) {
|
|
|
|
wl_pointer_destroy(pointer);
|
|
|
|
pointer = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((caps & WL_SEAT_CAPABILITY_TOUCH)) {
|
|
|
|
if (touch == NULL) {
|
|
|
|
touch = wl_seat_get_touch(wl_seat);
|
|
|
|
wl_touch_add_listener(touch, &touch_listener, NULL);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (touch != NULL) {
|
|
|
|
wl_touch_destroy(touch);
|
|
|
|
touch = NULL;
|
|
|
|
}
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name)
|
|
|
|
{
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
wl_surface_enter(void *data, struct wl_surface *wl_surface,
|
|
|
|
struct wl_output *wl_output)
|
|
|
|
{
|
2023-10-30 01:16:17 +09:00
|
|
|
struct Output *old_output = current_output;
|
2023-10-30 01:33:26 +09:00
|
|
|
for (int i = 0; i < wl_outputs_size; i += 1) {
|
2023-09-08 22:56:50 +02:00
|
|
|
if (wl_outputs[i].data == wl_output) {
|
|
|
|
current_output = &wl_outputs[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-10-30 01:16:17 +09:00
|
|
|
if (current_output == old_output) {
|
|
|
|
return;
|
|
|
|
}
|
2023-09-07 21:31:49 +02:00
|
|
|
|
2023-09-18 11:59:33 +02:00
|
|
|
keyboard.preferred_scale = current_output->scale;
|
2023-11-04 14:32:29 +01:00
|
|
|
flip_landscape();
|
2023-08-26 18:15:28 +09:00
|
|
|
}
|
|
|
|
|
2023-11-10 20:27:40 +01:00
|
|
|
void
|
|
|
|
wl_surface_leave(void *data, struct wl_surface *wl_surface,
|
|
|
|
struct wl_output *wl_output) {
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
static void
|
|
|
|
display_handle_geometry(void *data, struct wl_output *wl_output, int x, int y,
|
|
|
|
int physical_width, int physical_height, int subpixel,
|
|
|
|
const char *make, const char *model, int transform)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
struct Output *output = data;
|
|
|
|
|
|
|
|
// Swap width and height on rotated displays
|
|
|
|
if (transform % 2 != 0) {
|
|
|
|
int tmp = physical_width;
|
|
|
|
physical_width = physical_height;
|
|
|
|
physical_height = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
output->w = physical_width;
|
|
|
|
output->h = physical_height;
|
|
|
|
|
|
|
|
if (current_output == output) {
|
2023-09-18 11:59:33 +02:00
|
|
|
flip_landscape();
|
2023-09-08 22:56:50 +02:00
|
|
|
};
|
2021-08-24 20:13:37 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
static void
|
|
|
|
display_handle_done(void *data, struct wl_output *wl_output)
|
|
|
|
{
|
|
|
|
}
|
2021-08-24 20:13:37 +02:00
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
static void
|
|
|
|
display_handle_scale(void *data, struct wl_output *wl_output, int32_t scale)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
struct Output *output = data;
|
|
|
|
output->scale = scale;
|
2023-09-07 21:31:49 +02:00
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
if (current_output == output) {
|
2023-09-18 11:59:33 +02:00
|
|
|
keyboard.preferred_scale = scale;
|
|
|
|
flip_landscape();
|
2023-09-08 22:56:50 +02:00
|
|
|
};
|
2021-08-24 20:13:37 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
static void
|
|
|
|
display_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags,
|
|
|
|
int width, int height, int refresh)
|
|
|
|
{
|
|
|
|
}
|
2021-08-24 20:13:37 +02:00
|
|
|
|
|
|
|
static const struct wl_output_listener output_listener = {
|
2023-09-08 22:56:50 +02:00
|
|
|
.geometry = display_handle_geometry,
|
|
|
|
.mode = display_handle_mode,
|
|
|
|
.done = display_handle_done,
|
|
|
|
.scale = display_handle_scale};
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
static void
|
|
|
|
xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
xdg_wm_base_pong(xdg_wm_base, serial);
|
2023-09-06 09:28:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
2023-09-08 22:56:50 +02:00
|
|
|
.ping = xdg_wm_base_ping,
|
2023-09-06 09:28:09 +02:00
|
|
|
};
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
handle_global(void *data, struct wl_registry *registry, uint32_t name,
|
|
|
|
const char *interface, uint32_t version)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
if (strcmp(interface, wl_compositor_interface.name) == 0) {
|
|
|
|
compositor =
|
|
|
|
wl_registry_bind(registry, name, &wl_compositor_interface, 3);
|
|
|
|
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
|
|
|
|
draw_ctx.shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
|
2023-10-23 11:54:51 +09:00
|
|
|
} else if (strcmp(interface, wl_output_interface.name) == 0) {
|
2023-09-08 22:56:50 +02:00
|
|
|
if (wl_outputs_size < WL_OUTPUTS_LIMIT) {
|
|
|
|
struct Output *output = &wl_outputs[wl_outputs_size];
|
|
|
|
output->data =
|
|
|
|
wl_registry_bind(registry, name, &wl_output_interface, 2);
|
|
|
|
output->name = name;
|
|
|
|
output->scale = 1;
|
|
|
|
wl_output_add_listener(output->data, &output_listener, output);
|
|
|
|
wl_outputs_size += 1;
|
|
|
|
}
|
|
|
|
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
|
|
|
|
seat = wl_registry_bind(registry, name, &wl_seat_interface, 1);
|
|
|
|
wl_seat_add_listener(seat, &seat_listener, NULL);
|
|
|
|
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
|
|
|
|
layer_shell =
|
|
|
|
wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1);
|
|
|
|
} else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
|
|
|
|
wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1);
|
|
|
|
xdg_wm_base_add_listener(wm_base, &xdg_wm_base_listener, NULL);
|
|
|
|
} else if (strcmp(interface,
|
|
|
|
wp_fractional_scale_manager_v1_interface.name) == 0) {
|
|
|
|
wfs_mgr = wl_registry_bind(
|
|
|
|
registry, name, &wp_fractional_scale_manager_v1_interface, 1);
|
|
|
|
} else if (strcmp(interface, wp_viewporter_interface.name) == 0) {
|
|
|
|
viewporter =
|
|
|
|
wl_registry_bind(registry, name, &wp_viewporter_interface, 1);
|
|
|
|
} else if (strcmp(interface,
|
|
|
|
zwp_virtual_keyboard_manager_v1_interface.name) == 0) {
|
|
|
|
vkbd_mgr = wl_registry_bind(
|
|
|
|
registry, name, &zwp_virtual_keyboard_manager_v1_interface, 1);
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
handle_global_remove(void *data, struct wl_registry *registry, uint32_t name)
|
|
|
|
{
|
2023-10-30 01:33:26 +09:00
|
|
|
for (int i = 0; i < wl_outputs_size; i += 1) {
|
2023-09-08 22:56:50 +02:00
|
|
|
if (wl_outputs[i].name == name) {
|
|
|
|
wl_output_destroy(wl_outputs[i].data);
|
2023-10-30 01:33:26 +09:00
|
|
|
for (; i < wl_outputs_size - 1; i += 1) {
|
2023-09-08 22:56:50 +02:00
|
|
|
wl_outputs[i] = wl_outputs[i + 1];
|
|
|
|
}
|
|
|
|
wl_outputs_size -= 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2023-08-26 18:15:28 +09:00
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
static void
|
|
|
|
xdg_popup_surface_configure(void *data, struct xdg_surface *xdg_surface,
|
|
|
|
uint32_t serial)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
xdg_surface_ack_configure(xdg_surface, serial);
|
2024-03-28 20:39:10 +09:00
|
|
|
popup_xdg_surface_configured = true;
|
2023-09-08 22:56:50 +02:00
|
|
|
drwsurf_flip(&popup_draw_surf);
|
2023-09-06 09:28:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct xdg_surface_listener xdg_popup_surface_listener = {
|
2023-09-08 22:56:50 +02:00
|
|
|
.configure = xdg_popup_surface_configure,
|
2023-09-06 09:28:09 +02:00
|
|
|
};
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
static void
|
|
|
|
xdg_popup_configure(void *data, struct xdg_popup *xdg_popup, int32_t x,
|
|
|
|
int32_t y, int32_t width, int32_t height)
|
|
|
|
{
|
2023-09-06 09:28:09 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
static void
|
|
|
|
xdg_popup_done(void *data, struct xdg_popup *xdg_popup)
|
|
|
|
{
|
|
|
|
}
|
2023-09-06 09:28:09 +02:00
|
|
|
|
|
|
|
static const struct xdg_popup_listener xdg_popup_listener = {
|
2023-09-08 22:56:50 +02:00
|
|
|
.configure = xdg_popup_configure,
|
|
|
|
.popup_done = xdg_popup_done,
|
2023-09-06 09:28:09 +02:00
|
|
|
};
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
static void
|
2023-09-18 11:59:33 +02:00
|
|
|
wp_fractional_scale_preferred_scale(
|
2023-09-08 22:56:50 +02:00
|
|
|
void *data, struct wp_fractional_scale_v1 *wp_fractional_scale_v1,
|
2023-09-08 23:14:24 +02:00
|
|
|
uint32_t scale)
|
|
|
|
{
|
2023-09-18 11:59:33 +02:00
|
|
|
keyboard.preferred_fractional_scale = (double)scale / 120;
|
2023-09-07 21:31:47 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 22:42:07 +02:00
|
|
|
static const struct wp_fractional_scale_v1_listener
|
2023-09-08 22:56:50 +02:00
|
|
|
wp_fractional_scale_listener = {
|
2023-09-18 11:59:33 +02:00
|
|
|
.preferred_scale = wp_fractional_scale_preferred_scale,
|
2023-09-07 21:31:47 +02:00
|
|
|
};
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
2023-09-18 11:59:33 +02:00
|
|
|
flip_landscape()
|
2023-09-08 23:14:24 +02:00
|
|
|
{
|
2024-02-28 11:08:53 +01:00
|
|
|
bool previous_landscape = keyboard.landscape;
|
|
|
|
|
|
|
|
if (current_output) {
|
|
|
|
keyboard.landscape = current_output->w > current_output->h;
|
|
|
|
} else if (wl_outputs_size) {
|
Fix the initial output geometry guessing
wvkbd adapt its height, and layout depending on if the screen
is in landscape mode or not.
The only realiable way to know which outputs our surface is
rendered on is the wl_surface->enter(wl_output) event. But we receive
this event very late in the flow. After the first frame rendering, and
commit to the surface.
There already is some code to guess the best initial tentative, on the
most simple situations, to try to avoid an immediate re-creation of the
Wayland objects, buffer, and re-rendering of the layout.
But two issues was present:
First, we need a second roundtrip of the events, after the global
handle. This make the compositor to send the wl_outputs events earlier,
giving their geometry before our first show().
Then, the code that loop on them, if we don't already know the
current_output, was wrong. Because we changed the default state to
landscaped a while ago.
We also change how this code behave, we use the very first wl_output we
know about. Every behaviors are somehow wrong at this point, this one is
the simplest.
Now when starting wvkbd with only one screen, we don't need a second
loop anymore.
On situation where multiple screens are present, it will eventually need
a second one.
Signed-off-by: Willow Barraco <contact@willowbarraco.fr>
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2024-11-05 07:59:43 +01:00
|
|
|
keyboard.landscape = wl_outputs[0].w > wl_outputs[0].h;
|
2024-02-28 11:08:53 +01:00
|
|
|
}
|
2023-09-08 22:56:50 +02:00
|
|
|
|
|
|
|
enum layout_id layer;
|
|
|
|
if (keyboard.landscape) {
|
|
|
|
layer = keyboard.landscape_layers[0];
|
|
|
|
height = landscape_height;
|
|
|
|
} else {
|
|
|
|
layer = keyboard.layers[0];
|
|
|
|
height = normal_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
keyboard.layout = &keyboard.layouts[layer];
|
|
|
|
keyboard.layer_index = 0;
|
|
|
|
keyboard.prevlayout = keyboard.layout;
|
|
|
|
keyboard.last_abc_layout = keyboard.layout;
|
|
|
|
keyboard.last_abc_index = 0;
|
|
|
|
|
2024-03-03 12:52:21 +01:00
|
|
|
if (layer_surface && previous_landscape != keyboard.landscape) {
|
|
|
|
if (popup_xdg_popup) {
|
|
|
|
xdg_popup_destroy(popup_xdg_popup);
|
|
|
|
popup_xdg_popup = NULL;
|
|
|
|
}
|
|
|
|
if (popup_xdg_surface) {
|
|
|
|
xdg_surface_destroy(popup_xdg_surface);
|
|
|
|
popup_xdg_surface = NULL;
|
|
|
|
}
|
|
|
|
if (popup_draw_surf.surf) {
|
|
|
|
wl_surface_destroy(popup_draw_surf.surf);
|
|
|
|
popup_draw_surf.surf = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
zwlr_layer_surface_v1_destroy(layer_surface);
|
|
|
|
layer_surface = NULL;
|
|
|
|
wl_surface_destroy(draw_surf.surf);
|
|
|
|
|
|
|
|
show();
|
2023-09-08 22:56:50 +02:00
|
|
|
}
|
2023-09-07 21:31:49 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
layer_surface_configure(void *data, struct zwlr_layer_surface_v1 *surface,
|
|
|
|
uint32_t serial, uint32_t w, uint32_t h)
|
|
|
|
{
|
2023-09-18 11:59:33 +02:00
|
|
|
double scale = keyboard.preferred_scale;
|
|
|
|
if (keyboard.preferred_fractional_scale) {
|
|
|
|
scale = keyboard.preferred_fractional_scale;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (keyboard.w != w || keyboard.h != h || keyboard.scale != scale ||
|
|
|
|
hidden) {
|
2023-09-17 20:18:19 +02:00
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
keyboard.w = w;
|
|
|
|
keyboard.h = h;
|
2023-09-18 11:59:33 +02:00
|
|
|
keyboard.scale = scale;
|
2023-09-17 20:18:19 +02:00
|
|
|
hidden = false;
|
2023-09-08 22:56:50 +02:00
|
|
|
|
|
|
|
if (wfs_mgr && viewporter) {
|
|
|
|
wp_viewport_set_destination(draw_surf_viewport, keyboard.w,
|
|
|
|
keyboard.h);
|
|
|
|
} else {
|
|
|
|
wl_surface_set_buffer_scale(draw_surf.surf, keyboard.scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (popup_xdg_popup) {
|
|
|
|
xdg_popup_destroy(popup_xdg_popup);
|
|
|
|
}
|
|
|
|
if (popup_xdg_surface) {
|
|
|
|
xdg_surface_destroy(popup_xdg_surface);
|
|
|
|
}
|
|
|
|
if (popup_draw_surf.surf) {
|
|
|
|
wl_surface_destroy(popup_draw_surf.surf);
|
|
|
|
}
|
|
|
|
|
|
|
|
popup_draw_surf.surf = wl_compositor_create_surface(compositor);
|
|
|
|
|
|
|
|
xdg_positioner_set_size(popup_xdg_positioner, w, h * 2);
|
|
|
|
xdg_positioner_set_anchor_rect(popup_xdg_positioner, 0, -h, w, h * 2);
|
|
|
|
|
|
|
|
wl_surface_set_input_region(popup_draw_surf.surf, empty_region);
|
|
|
|
popup_xdg_surface =
|
|
|
|
xdg_wm_base_get_xdg_surface(wm_base, popup_draw_surf.surf);
|
2024-03-28 20:39:10 +09:00
|
|
|
popup_xdg_surface_configured = false;
|
2023-09-08 22:56:50 +02:00
|
|
|
xdg_surface_add_listener(popup_xdg_surface, &xdg_popup_surface_listener,
|
|
|
|
NULL);
|
|
|
|
popup_xdg_popup = xdg_surface_get_popup(popup_xdg_surface, NULL,
|
|
|
|
popup_xdg_positioner);
|
|
|
|
xdg_popup_add_listener(popup_xdg_popup, &xdg_popup_listener, NULL);
|
|
|
|
zwlr_layer_surface_v1_get_popup(layer_surface, popup_xdg_popup);
|
|
|
|
|
|
|
|
if (wfs_mgr && viewporter) {
|
|
|
|
popup_draw_surf_viewport =
|
|
|
|
wp_viewporter_get_viewport(viewporter, popup_draw_surf.surf);
|
|
|
|
wp_viewport_set_destination(popup_draw_surf_viewport, keyboard.w,
|
|
|
|
keyboard.h * 2);
|
|
|
|
} else {
|
|
|
|
wl_surface_set_buffer_scale(popup_draw_surf.surf, keyboard.scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
wl_surface_commit(popup_draw_surf.surf);
|
|
|
|
|
2023-10-30 01:13:23 +09:00
|
|
|
zwlr_layer_surface_v1_ack_configure(surface, serial);
|
|
|
|
kbd_resize(&keyboard, layouts, NumLayouts);
|
|
|
|
drwsurf_flip(&draw_surf);
|
|
|
|
} else {
|
|
|
|
zwlr_layer_surface_v1_ack_configure(surface, serial);
|
|
|
|
}
|
2020-09-11 01:25:28 -07:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
layer_surface_closed(void *data, struct zwlr_layer_surface_v1 *surface)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
zwlr_layer_surface_v1_destroy(surface);
|
|
|
|
wl_surface_destroy(draw_surf.surf);
|
|
|
|
run_display = false;
|
2020-09-11 01:25:28 -07:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
usage(char *argv0)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
fprintf(stderr,
|
|
|
|
"usage: %s [-hov] [-H height] [-L landscape height] [-fn font] [-l "
|
|
|
|
"layers]\n",
|
|
|
|
argv0);
|
|
|
|
fprintf(stderr, "Options:\n");
|
|
|
|
fprintf(stderr, " -D - Enable debug\n");
|
|
|
|
fprintf(stderr, " -o - Print pressed keys to standard output\n");
|
|
|
|
fprintf(stderr,
|
|
|
|
" -O - Print intersected keys to standard output\n");
|
|
|
|
fprintf(stderr, " -H [int] - Height in pixels\n");
|
|
|
|
fprintf(stderr, " -L [int] - Landscape height in pixels\n");
|
2024-04-15 20:38:02 +02:00
|
|
|
fprintf(stderr, " -R [int] - Rounding radius in pixels\n");
|
2023-09-08 22:56:50 +02:00
|
|
|
fprintf(stderr, " --fn [font] - Set font (e.g: DejaVu Sans 20)\n");
|
|
|
|
fprintf(stderr, " --hidden - Start hidden (send SIGUSR2 to show)\n");
|
|
|
|
fprintf(
|
|
|
|
stderr,
|
|
|
|
" --alpha [int] - Set alpha value for all colors [0-255]\n");
|
|
|
|
fprintf(stderr, " --bg [rrggbb|aa] - Set color of background\n");
|
|
|
|
fprintf(stderr, " --fg [rrggbb|aa] - Set color of keys\n");
|
|
|
|
fprintf(stderr, " --fg-sp [rrggbb|aa] - Set color of special keys\n");
|
|
|
|
fprintf(stderr, " --press [rrggbb|aa] - Set color of pressed keys\n");
|
|
|
|
fprintf(stderr,
|
|
|
|
" --press-sp [rrggbb|aa] - Set color of pressed special keys\n");
|
|
|
|
fprintf(stderr, " --swipe [rrggbb|aa] - Set color of swiped keys\n");
|
|
|
|
fprintf(stderr,
|
|
|
|
" --swipe-sp [rrggbb|aa] - Set color of swiped special keys\n");
|
|
|
|
fprintf(stderr, " --text [rrggbb|aa] - Set color of text on keys\n");
|
|
|
|
fprintf(stderr,
|
|
|
|
" --text-sp [rrggbb|aa] - Set color of text on special keys\n");
|
|
|
|
fprintf(stderr,
|
|
|
|
" --list-layers - Print the list of available layers\n");
|
|
|
|
fprintf(stderr,
|
|
|
|
" -l - Comma separated list of layers\n");
|
|
|
|
fprintf(stderr, " --landscape-layers - Comma separated list of "
|
|
|
|
"landscape layers\n");
|
2022-08-16 16:16:08 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
list_layers()
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
int i;
|
|
|
|
for (i = 0; i < NumLayouts - 1; i++) {
|
|
|
|
if (layouts[i].name) {
|
|
|
|
puts(layouts[i].name);
|
|
|
|
}
|
|
|
|
}
|
2021-08-24 13:08:49 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
hide()
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
if (!layer_surface) {
|
|
|
|
return;
|
|
|
|
}
|
2021-08-26 13:29:40 +02:00
|
|
|
|
2023-11-03 21:18:25 +09:00
|
|
|
if(wfs_draw_surf) {
|
|
|
|
wp_fractional_scale_v1_destroy(wfs_draw_surf);
|
|
|
|
wfs_draw_surf = NULL;
|
|
|
|
}
|
|
|
|
if(draw_surf_viewport) {
|
|
|
|
wp_viewport_destroy(draw_surf_viewport);
|
|
|
|
draw_surf_viewport = NULL;
|
|
|
|
}
|
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
zwlr_layer_surface_v1_destroy(layer_surface);
|
|
|
|
wl_surface_destroy(draw_surf.surf);
|
|
|
|
layer_surface = NULL;
|
|
|
|
hidden = true;
|
2021-08-26 13:29:40 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
show()
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
if (layer_surface) {
|
|
|
|
return;
|
|
|
|
}
|
2021-08-26 13:29:40 +02:00
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
wl_display_sync(display);
|
2021-08-26 13:29:40 +02:00
|
|
|
|
2024-02-28 11:08:53 +01:00
|
|
|
flip_landscape();
|
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
draw_surf.surf = wl_compositor_create_surface(compositor);
|
|
|
|
wl_surface_add_listener(draw_surf.surf, &surface_listener, NULL);
|
2023-09-17 20:18:19 +02:00
|
|
|
if (wfs_mgr && viewporter) {
|
|
|
|
wfs_draw_surf = wp_fractional_scale_manager_v1_get_fractional_scale(
|
|
|
|
wfs_mgr, draw_surf.surf);
|
|
|
|
wp_fractional_scale_v1_add_listener(
|
|
|
|
wfs_draw_surf, &wp_fractional_scale_listener, NULL);
|
|
|
|
draw_surf_viewport =
|
|
|
|
wp_viewporter_get_viewport(viewporter, draw_surf.surf);
|
|
|
|
}
|
|
|
|
|
2024-03-01 23:42:16 +01:00
|
|
|
struct wl_output *current_output_data = NULL;
|
|
|
|
if (current_output)
|
|
|
|
current_output_data = current_output->data;
|
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
layer_surface = zwlr_layer_shell_v1_get_layer_surface(
|
2024-03-01 23:42:16 +01:00
|
|
|
layer_shell, draw_surf.surf, current_output_data, layer, namespace);
|
2021-08-26 13:29:40 +02:00
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
zwlr_layer_surface_v1_set_size(layer_surface, 0, height);
|
|
|
|
zwlr_layer_surface_v1_set_anchor(layer_surface, anchor);
|
|
|
|
zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, height);
|
|
|
|
zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface, false);
|
|
|
|
zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener,
|
|
|
|
NULL);
|
|
|
|
wl_surface_commit(draw_surf.surf);
|
2021-08-26 13:29:40 +02:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
toggle_visibility()
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
if (hidden)
|
|
|
|
show();
|
|
|
|
else
|
|
|
|
hide();
|
2022-01-26 12:03:58 -05:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
pipewarn()
|
|
|
|
{
|
|
|
|
fprintf(stderr, "wvkbd: cannot pipe data out.\n");
|
|
|
|
}
|
2023-09-08 22:56:50 +02:00
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
void
|
|
|
|
set_kbd_colors(uint8_t *bgra, char *hex)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
// bg, fg, text, high, swipe
|
|
|
|
int length = strlen(hex);
|
|
|
|
if (length == 6 || length == 8) {
|
2024-04-01 19:13:34 -03:00
|
|
|
char subhex[3] = { 0 };
|
2023-09-08 22:56:50 +02:00
|
|
|
memcpy(subhex, hex, 2);
|
|
|
|
bgra[2] = (int)strtol(subhex, NULL, 16);
|
|
|
|
memcpy(subhex, hex + 2, 2);
|
|
|
|
bgra[1] = (int)strtol(subhex, NULL, 16);
|
|
|
|
memcpy(subhex, hex + 4, 2);
|
|
|
|
bgra[0] = (int)strtol(subhex, NULL, 16);
|
|
|
|
if (length == 8) {
|
|
|
|
memcpy(subhex, hex + 6, 2);
|
|
|
|
bgra[3] = (int)strtol(subhex, NULL, 16);
|
|
|
|
}
|
|
|
|
}
|
2022-07-27 11:43:11 +03:00
|
|
|
}
|
|
|
|
|
2023-09-08 23:14:24 +02:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
|
|
|
{
|
2023-09-08 22:56:50 +02:00
|
|
|
/* parse command line arguments */
|
|
|
|
char *layer_names_list = NULL, *landscape_layer_names_list = NULL;
|
2023-10-23 13:59:31 +02:00
|
|
|
char *fc_font_pattern = NULL;
|
2024-02-28 11:08:53 +01:00
|
|
|
height = landscape_height = KBD_PIXEL_LANDSCAPE_HEIGHT;
|
|
|
|
normal_height = KBD_PIXEL_HEIGHT;
|
2023-09-08 22:56:50 +02:00
|
|
|
|
|
|
|
char *tmp;
|
|
|
|
if ((tmp = getenv("WVKBD_LAYERS")))
|
|
|
|
layer_names_list = estrdup(tmp);
|
|
|
|
if ((tmp = getenv("WVKBD_LANDSCAPE_LAYERS")))
|
|
|
|
landscape_layer_names_list = estrdup(tmp);
|
|
|
|
if ((tmp = getenv("WVKBD_HEIGHT")))
|
|
|
|
normal_height = atoi(tmp);
|
|
|
|
if ((tmp = getenv("WVKBD_LANDSCAPE_HEIGHT")))
|
|
|
|
landscape_height = atoi(tmp);
|
|
|
|
|
|
|
|
/* keyboard settings */
|
|
|
|
keyboard.layers = (enum layout_id *)&layers;
|
|
|
|
keyboard.landscape_layers = (enum layout_id *)&landscape_layers;
|
2023-10-09 17:27:51 +02:00
|
|
|
keyboard.schemes = schemes;
|
2024-02-28 11:08:53 +01:00
|
|
|
keyboard.landscape = true;
|
2023-09-08 22:56:50 +02:00
|
|
|
keyboard.layer_index = 0;
|
2023-09-22 18:42:27 +02:00
|
|
|
keyboard.preferred_scale = 1;
|
2023-09-18 11:59:33 +02:00
|
|
|
keyboard.preferred_fractional_scale = 0;
|
2023-09-08 22:56:50 +02:00
|
|
|
|
|
|
|
uint8_t alpha = 0;
|
|
|
|
bool alpha_defined = false;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for (i = 1; argv[i]; i++) {
|
|
|
|
if ((!strcmp(argv[i], "-v")) || (!strcmp(argv[i], "--version"))) {
|
|
|
|
printf("wvkbd-%s\n", VERSION);
|
|
|
|
exit(0);
|
|
|
|
} else if ((!strcmp(argv[i], "-h")) || (!strcmp(argv[i], "--help"))) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(0);
|
|
|
|
} else if (!strcmp(argv[i], "-l")) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (layer_names_list)
|
|
|
|
free(layer_names_list);
|
|
|
|
layer_names_list = estrdup(argv[++i]);
|
|
|
|
} else if ((!strcmp(argv[i], "-landscape-layers")) ||
|
|
|
|
(!strcmp(argv[i], "--landscape-layers"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (landscape_layer_names_list)
|
|
|
|
free(landscape_layer_names_list);
|
|
|
|
landscape_layer_names_list = estrdup(argv[++i]);
|
|
|
|
} else if ((!strcmp(argv[i], "-bg")) || (!strcmp(argv[i], "--bg"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2023-10-09 17:27:51 +02:00
|
|
|
set_kbd_colors(keyboard.schemes[0].bg.bgra, argv[++i]);
|
2023-09-08 22:56:50 +02:00
|
|
|
} else if ((!strcmp(argv[i], "-alpha")) ||
|
|
|
|
(!strcmp(argv[i], "--alpha"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
alpha = atoi(argv[++i]);
|
|
|
|
alpha_defined = true;
|
|
|
|
} else if ((!strcmp(argv[i], "-fg")) || (!strcmp(argv[i], "--fg"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2023-10-09 17:27:51 +02:00
|
|
|
set_kbd_colors(keyboard.schemes[0].fg.bgra, argv[++i]);
|
2023-09-08 22:56:50 +02:00
|
|
|
} else if ((!strcmp(argv[i], "-fg-sp")) ||
|
|
|
|
(!strcmp(argv[i], "--fg-sp"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2023-10-09 17:27:51 +02:00
|
|
|
set_kbd_colors(keyboard.schemes[1].fg.bgra, argv[++i]);
|
2023-09-08 22:56:50 +02:00
|
|
|
} else if ((!strcmp(argv[i], "-press")) ||
|
|
|
|
(!strcmp(argv[i], "--press"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2023-10-09 17:27:51 +02:00
|
|
|
set_kbd_colors(keyboard.schemes[0].high.bgra, argv[++i]);
|
2023-09-08 22:56:50 +02:00
|
|
|
} else if ((!strcmp(argv[i], "-press-sp")) ||
|
|
|
|
(!strcmp(argv[i], "--press-sp"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2023-10-09 17:27:51 +02:00
|
|
|
set_kbd_colors(keyboard.schemes[1].high.bgra, argv[++i]);
|
2023-09-08 22:56:50 +02:00
|
|
|
} else if ((!strcmp(argv[i], "-swipe")) ||
|
|
|
|
(!strcmp(argv[i], "--swipe"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2023-10-09 17:27:51 +02:00
|
|
|
set_kbd_colors(keyboard.schemes[0].swipe.bgra, argv[++i]);
|
2023-09-08 22:56:50 +02:00
|
|
|
} else if ((!strcmp(argv[i], "-swipe-sp")) ||
|
|
|
|
(!strcmp(argv[i], "--swipe-sp"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2023-10-09 17:27:51 +02:00
|
|
|
set_kbd_colors(keyboard.schemes[1].swipe.bgra, argv[++i]);
|
2023-09-08 22:56:50 +02:00
|
|
|
} else if ((!strcmp(argv[i], "-text")) ||
|
|
|
|
(!strcmp(argv[i], "--text"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2023-10-09 17:27:51 +02:00
|
|
|
set_kbd_colors(keyboard.schemes[0].text.bgra, argv[++i]);
|
2023-09-08 22:56:50 +02:00
|
|
|
} else if ((!strcmp(argv[i], "-text-sp")) ||
|
|
|
|
(!strcmp(argv[i], "--text-sp"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2023-10-09 17:27:51 +02:00
|
|
|
set_kbd_colors(keyboard.schemes[1].text.bgra, argv[++i]);
|
2023-09-08 22:56:50 +02:00
|
|
|
} else if (!strcmp(argv[i], "-H")) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-02-28 11:08:53 +01:00
|
|
|
normal_height = atoi(argv[++i]);
|
2023-09-08 22:56:50 +02:00
|
|
|
} else if (!strcmp(argv[i], "-L")) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-02-28 11:08:53 +01:00
|
|
|
height = landscape_height = atoi(argv[++i]);
|
2024-04-15 20:38:02 +02:00
|
|
|
} else if (!strcmp(argv[i], "-R")) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
rounding = atoi(argv[++i]);
|
2023-09-08 22:56:50 +02:00
|
|
|
} else if (!strcmp(argv[i], "-D")) {
|
|
|
|
keyboard.debug = true;
|
|
|
|
} else if ((!strcmp(argv[i], "-fn")) || (!strcmp(argv[i], "--fn"))) {
|
|
|
|
if (i >= argc - 1) {
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
fc_font_pattern = estrdup(argv[++i]);
|
|
|
|
} else if (!strcmp(argv[i], "-o")) {
|
|
|
|
keyboard.print = true;
|
|
|
|
} else if (!strcmp(argv[i], "-O")) {
|
|
|
|
keyboard.print_intersect = true;
|
|
|
|
} else if ((!strcmp(argv[i], "-hidden")) ||
|
|
|
|
(!strcmp(argv[i], "--hidden"))) {
|
|
|
|
hidden = true;
|
|
|
|
} else if ((!strcmp(argv[i], "-list-layers")) ||
|
|
|
|
(!strcmp(argv[i], "--list-layers"))) {
|
|
|
|
list_layers();
|
|
|
|
exit(0);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Invalid argument: %s\n", argv[i]);
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (alpha_defined) {
|
2023-10-09 17:27:51 +02:00
|
|
|
keyboard.schemes[0].bg.bgra[3] = alpha;
|
|
|
|
keyboard.schemes[0].fg.bgra[3] = alpha;
|
|
|
|
keyboard.schemes[0].high.bgra[3] = alpha;
|
|
|
|
keyboard.schemes[1].bg.bgra[3] = alpha;
|
|
|
|
keyboard.schemes[1].fg.bgra[3] = alpha;
|
|
|
|
keyboard.schemes[1].high.bgra[3] = alpha;
|
2023-09-08 22:56:50 +02:00
|
|
|
}
|
|
|
|
|
2023-10-23 13:59:31 +02:00
|
|
|
if (fc_font_pattern) {
|
|
|
|
for (i = 0; i < countof(schemes); i++)
|
|
|
|
schemes[i].font = fc_font_pattern;
|
2023-09-08 22:56:50 +02:00
|
|
|
}
|
|
|
|
|
2024-04-15 20:38:02 +02:00
|
|
|
if (rounding != DEFAULT_ROUNDING) {
|
|
|
|
for (i = 0; i < countof(schemes); i++)
|
|
|
|
schemes[i].rounding = rounding;
|
|
|
|
}
|
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
display = wl_display_connect(NULL);
|
|
|
|
if (display == NULL) {
|
|
|
|
die("Failed to create display\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
draw_surf.ctx = &draw_ctx;
|
|
|
|
popup_draw_surf.ctx = &draw_ctx;
|
|
|
|
keyboard.surf = &draw_surf;
|
|
|
|
keyboard.popup_surf = &popup_draw_surf;
|
|
|
|
|
|
|
|
struct wl_registry *registry = wl_display_get_registry(display);
|
|
|
|
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
|
|
|
wl_display_roundtrip(display);
|
|
|
|
|
|
|
|
if (compositor == NULL) {
|
|
|
|
die("wl_compositor not available\n");
|
|
|
|
}
|
|
|
|
if (draw_ctx.shm == NULL) {
|
|
|
|
die("wl_shm not available\n");
|
|
|
|
}
|
|
|
|
if (layer_shell == NULL) {
|
|
|
|
die("layer_shell not available\n");
|
|
|
|
}
|
|
|
|
if (wm_base == NULL) {
|
|
|
|
die("wm_base not available\n");
|
|
|
|
}
|
|
|
|
if (vkbd_mgr == NULL) {
|
|
|
|
die("virtual_keyboard_manager not available\n");
|
|
|
|
}
|
|
|
|
|
Fix the initial output geometry guessing
wvkbd adapt its height, and layout depending on if the screen
is in landscape mode or not.
The only realiable way to know which outputs our surface is
rendered on is the wl_surface->enter(wl_output) event. But we receive
this event very late in the flow. After the first frame rendering, and
commit to the surface.
There already is some code to guess the best initial tentative, on the
most simple situations, to try to avoid an immediate re-creation of the
Wayland objects, buffer, and re-rendering of the layout.
But two issues was present:
First, we need a second roundtrip of the events, after the global
handle. This make the compositor to send the wl_outputs events earlier,
giving their geometry before our first show().
Then, the code that loop on them, if we don't already know the
current_output, was wrong. Because we changed the default state to
landscaped a while ago.
We also change how this code behave, we use the very first wl_output we
know about. Every behaviors are somehow wrong at this point, this one is
the simplest.
Now when starting wvkbd with only one screen, we don't need a second
loop anymore.
On situation where multiple screens are present, it will eventually need
a second one.
Signed-off-by: Willow Barraco <contact@willowbarraco.fr>
Signed-off-by: Maarten van Gompel <proycon@anaproy.nl>
2024-11-05 07:59:43 +01:00
|
|
|
// A second round-trip to receive wl_outputs events
|
|
|
|
wl_display_roundtrip(display);
|
|
|
|
|
2023-09-08 22:56:50 +02:00
|
|
|
empty_region = wl_compositor_create_region(compositor);
|
|
|
|
popup_xdg_positioner = xdg_wm_base_create_positioner(wm_base);
|
|
|
|
|
|
|
|
keyboard.vkbd =
|
|
|
|
zwp_virtual_keyboard_manager_v1_create_virtual_keyboard(vkbd_mgr, seat);
|
|
|
|
if (keyboard.vkbd == NULL) {
|
|
|
|
die("failed to init virtual keyboard_manager\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
kbd_init(&keyboard, (struct layout *)&layouts, layer_names_list,
|
|
|
|
landscape_layer_names_list);
|
|
|
|
|
2023-10-23 13:59:31 +02:00
|
|
|
for (i = 0; i < countof(schemes); i++) {
|
|
|
|
schemes[i].font_description =
|
|
|
|
pango_font_description_from_string(schemes[i].font);
|
|
|
|
}
|
2023-09-08 22:56:50 +02:00
|
|
|
|
|
|
|
if (!hidden)
|
|
|
|
show();
|
|
|
|
|
|
|
|
struct pollfd fds[2];
|
|
|
|
int WAYLAND_FD = 0;
|
|
|
|
int SIGNAL_FD = 1;
|
|
|
|
fds[WAYLAND_FD].events = POLLIN;
|
|
|
|
fds[SIGNAL_FD].events = POLLIN;
|
|
|
|
|
|
|
|
fds[WAYLAND_FD].fd = wl_display_get_fd(display);
|
|
|
|
if (fds[WAYLAND_FD].fd == -1) {
|
|
|
|
die("Failed to get wayland_fd: %d\n", errno);
|
|
|
|
}
|
|
|
|
|
|
|
|
sigset_t signal_mask;
|
|
|
|
sigemptyset(&signal_mask);
|
|
|
|
sigaddset(&signal_mask, SIGUSR1);
|
|
|
|
sigaddset(&signal_mask, SIGUSR2);
|
|
|
|
sigaddset(&signal_mask, SIGRTMIN);
|
|
|
|
sigaddset(&signal_mask, SIGPIPE);
|
|
|
|
if (sigprocmask(SIG_BLOCK, &signal_mask, NULL) == -1) {
|
|
|
|
die("Failed to disable handled signals: %d\n", errno);
|
|
|
|
}
|
|
|
|
|
|
|
|
fds[SIGNAL_FD].fd = signalfd(-1, &signal_mask, 0);
|
|
|
|
if (fds[SIGNAL_FD].fd == -1) {
|
|
|
|
die("Failed to get signalfd: %d\n", errno);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (run_display) {
|
|
|
|
wl_display_flush(display);
|
|
|
|
poll(fds, 2, -1);
|
|
|
|
|
|
|
|
if (fds[WAYLAND_FD].revents & POLLIN)
|
|
|
|
wl_display_dispatch(display);
|
2024-01-29 20:56:28 -05:00
|
|
|
if (fds[WAYLAND_FD].revents & POLLERR) {
|
|
|
|
die("Exceptional condition on wayland socket.\n");
|
|
|
|
}
|
|
|
|
if (fds[WAYLAND_FD].revents & POLLHUP) {
|
|
|
|
die("Wayland socket has been disconnected.\n");
|
|
|
|
}
|
2023-09-08 22:56:50 +02:00
|
|
|
|
|
|
|
if (fds[SIGNAL_FD].revents & POLLIN) {
|
|
|
|
struct signalfd_siginfo si;
|
|
|
|
|
|
|
|
if (read(fds[SIGNAL_FD].fd, &si, sizeof(si)) != sizeof(si))
|
|
|
|
fprintf(stderr, "Signal read error: %d", errno);
|
|
|
|
else if (si.ssi_signo == SIGUSR1)
|
|
|
|
hide();
|
|
|
|
else if (si.ssi_signo == SIGUSR2)
|
|
|
|
show();
|
|
|
|
else if (si.ssi_signo == SIGRTMIN)
|
|
|
|
toggle_visibility();
|
|
|
|
else if (si.ssi_signo == SIGPIPE)
|
|
|
|
pipewarn();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-23 13:59:31 +02:00
|
|
|
if (fc_font_pattern) {
|
2023-09-08 22:56:50 +02:00
|
|
|
free((void *)fc_font_pattern);
|
2023-10-23 13:59:31 +02:00
|
|
|
for (i = 0; i < countof(schemes); i++)
|
|
|
|
schemes[i].font = NULL;
|
2023-09-08 22:56:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2020-09-11 01:25:28 -07:00
|
|
|
}
|