summaryrefslogtreecommitdiff
path: root/src/platform/x11
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform/x11')
-rw-r--r--src/platform/x11/keymap.c2
-rw-r--r--src/platform/x11/keymap.h6
-rw-r--r--src/platform/x11/native.c14
-rw-r--r--src/platform/x11/window.c1174
4 files changed, 888 insertions, 308 deletions
diff --git a/src/platform/x11/keymap.c b/src/platform/x11/keymap.c
index 3c566b3..35178dd 100644
--- a/src/platform/x11/keymap.c
+++ b/src/platform/x11/keymap.c
@@ -2,7 +2,7 @@
#include <string.h>
/* XKB standard physical key names, independent of server numeric keycodes. */
-enum yasl_key yasl_key_from_xkb_name(const char name[4])
+enum yasl_key yasl_private_key_from_xkb_name(const char name[4])
{
static const struct { char name[4]; enum yasl_key key; } keys[] = {
{{'T', 'L', 'D', 'E'}, YASL_KEY_GRAVE},
diff --git a/src/platform/x11/keymap.h b/src/platform/x11/keymap.h
index 8114fb5..9bb009d 100644
--- a/src/platform/x11/keymap.h
+++ b/src/platform/x11/keymap.h
@@ -1,8 +1,8 @@
-#ifndef YASL_X11_KEYMAP_H
-#define YASL_X11_KEYMAP_H
+#ifndef YASL_PRIVATE_X11_KEYMAP_H
+#define YASL_PRIVATE_X11_KEYMAP_H
#include "yasl/keycodes.h"
-enum yasl_key yasl_key_from_xkb_name(const char name[4]);
+enum yasl_key yasl_private_key_from_xkb_name(const char name[4]);
#endif
diff --git a/src/platform/x11/native.c b/src/platform/x11/native.c
index 249adec..fffe171 100644
--- a/src/platform/x11/native.c
+++ b/src/platform/x11/native.c
@@ -1,14 +1,14 @@
#include "common/backend.h"
-#include "yasl/native/x11.h"
+#include "common/private_native_x11.h"
-Display *yasl_x11_display_get_display(struct yasl_display *d)
+Display *yasl_private_x11_display_get_display(struct yasl_private_display *d)
{
- return (d && yasl_display_backend(d) == YASL_BACKEND_X11) ?
- (Display *)yasl_display_get_native_handle(d) : NULL;
+ return (d && yasl_private_display_backend(d) == YASL_PRIVATE_BACKEND_X11) ?
+ (Display *)yasl_private_display_get_native_handle(d) : NULL;
}
-uintptr_t yasl_x11_surface_get_window(struct yasl_surface *s)
+uintptr_t yasl_private_x11_surface_get_window(struct yasl_surface *s)
{
- return (s && s->display && yasl_display_backend(s->display) == YASL_BACKEND_X11) ?
- (uintptr_t)yasl_surface_get_native_handle(s) : 0;
+ return (s && s->display && yasl_private_display_backend(s->display) == YASL_PRIVATE_BACKEND_X11) ?
+ (uintptr_t)yasl_private_surface_get_native_handle(s) : 0;
}
diff --git a/src/platform/x11/window.c b/src/platform/x11/window.c
index 004d56c..8129dd5 100644
--- a/src/platform/x11/window.c
+++ b/src/platform/x11/window.c
@@ -16,6 +16,10 @@
#include <X11/keysym.h>
#include <X11/extensions/XInput2.h>
#include <X11/extensions/XShm.h>
+#if YASL_HAS_EGL
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif
#include <sys/ipc.h>
#include <sys/shm.h>
#if YASL_HAS_XRANDR
@@ -35,7 +39,7 @@
#include <wchar.h>
#define TEXT_LIMIT (16 * 1024 * 1024)
-#define PASTE_TIMEOUT_NS YASL_MS_TO_NS(30000)
+#define PASTE_TIMEOUT_NS YASL_PRIVATE_MS_TO_NS(30000)
#ifndef likely
#define likely(x) __builtin_expect(!!(x), 1)
@@ -50,26 +54,33 @@ struct x11_surface {
struct x11_surface *dead_next;
Window window;
GC gc;
+ Colormap colormap;
XIC ic;
+#if YASL_HAS_EGL
+ EGLContext gl_context;
+ EGLSurface gl_surface;
+ EGLConfig gl_config;
+#endif
XImage *image;
uint32_t *pixels;
bool shm_active;
XShmSegmentInfo shm_info;
- struct yasl_vector2i size;
- const struct yasl_window_cbs *cbs;
+ struct yasl_private_vector2i size;
+ const struct yasl_private_window_cbs *cbs;
void *ud;
struct input_queue input;
- struct yasl_frame frame;
- struct yasl_damage_list damage;
- struct yasl_frame_clock clock;
+ struct yasl_private_frame frame;
+ struct yasl_private_damage_list damage;
+ struct yasl_private_frame_clock clock;
bool want_draw, drawing, presented, destroyed;
+ bool focused;
struct x11_surface *parent;
bool is_popup;
- struct yasl_vector2i content_offset;
+ struct yasl_private_vector2i content_offset;
char *ime_preedit;
int ime_cursor_begin;
int ime_cursor_end;
- struct yasl_rect2i ime_caret;
+ struct yasl_private_rect2i ime_caret;
};
struct paste_request {
@@ -79,33 +90,45 @@ struct paste_request {
Window window;
Atom selection;
uint64_t id;
- yasl_timer_id timeout;
+ yasl_private_timer_id timeout;
};
struct tablet_axis {
int number;
double min, max, value;
+ bool valid;
+};
+
+struct x11_scroll_axis {
+ int number;
+ double increment, value;
+ bool valid, initialized;
+ int type;
};
struct x11_pointer {
struct x11_pointer *next;
int id;
- enum yasl_pointer_device device;
- struct tablet_axis pressure, tilt_x, tilt_y;
+ enum yasl_private_pointer_device device;
+ unsigned tool;
+ struct tablet_axis pressure, tilt_x, tilt_y, rotation, distance, tangential, wheel;
+ struct x11_scroll_axis scroll_x, scroll_y;
+ uint32_t buttons;
+ bool finger_scroll;
};
struct x11_display {
- struct yasl_display base;
+ struct yasl_private_display base;
Display *native;
int screen;
- struct yasl_loop *loop;
+ struct yasl_private_loop *loop;
int watch;
struct x11_surface *surfaces, *dead;
int depth;
XIM im;
Window selection_window;
Atom protocols, delete_window, utf8, clipboard, targets, paste_property, incr;
- Atom net_name, net_state, fullscreen, maximized_h, maximized_v;
+ Atom net_name, net_state, fullscreen, maximized_h, maximized_v, motif_hints;
Atom xdnd_aware, xdnd_enter, xdnd_position, xdnd_status, xdnd_leave, xdnd_drop, xdnd_finished;
Atom xdnd_selection, xdnd_action_copy, xdnd_type_list, uri_list;
char *selection[2];
@@ -121,20 +144,26 @@ struct x11_display {
int xkb_event;
enum yasl_key keys[256];
Cursor cursors[16];
- Atom abs_pressure, abs_tilt_x, abs_tilt_y, tool_type, eraser;
+ Atom abs_pressure, abs_tilt_x, abs_tilt_y, abs_rotation, abs_distance, abs_tangential, abs_wheel;
+ Atom tool_type, eraser;
+ Atom brush, airbrush, pencil;
struct x11_pointer *pointers;
+#if YASL_HAS_EGL
+ EGLDisplay egl;
+ bool egl_ready;
+#endif
struct {
bool active;
struct x11_surface *origin;
struct x11_surface *carried;
- struct yasl_vector2i carry_offset;
- struct yasl_drag_listener listener;
+ struct yasl_private_vector2i carry_offset;
+ struct yasl_private_drag_listener listener;
void *ud;
struct x11_surface *hover;
- struct yasl_vector2i hover_pos;
+ struct yasl_private_vector2i hover_pos;
Window icon_window;
Pixmap icon_pixmap;
- struct yasl_vector2i hotspot;
+ struct yasl_private_vector2i hotspot;
} drag;
struct {
Window source;
@@ -142,7 +171,7 @@ struct x11_display {
bool accepts;
bool has_uri_list;
struct x11_surface *surface;
- struct yasl_vector2i pos;
+ struct yasl_private_vector2i pos;
Time time;
} xdnd;
struct {
@@ -153,11 +182,11 @@ struct x11_display {
} pending_drop;
};
-static bool place(struct yasl_surface *base, struct yasl_vector2i at);
-static void drag_end(struct x11_display *d, enum yasl_drag_end how);
-static void drag_cancel(struct yasl_display *base);
+static bool place(struct yasl_surface *base, struct yasl_private_vector2i at);
+static void drag_end(struct x11_display *d, enum yasl_private_drag_end how);
+static void drag_cancel(struct yasl_private_display *base);
static void schedule_redraw(struct yasl_surface *base);
-static uint64_t paste_timeout(void *ud, yasl_timer_id id, uint64_t interval_ns);
+static uint64_t paste_timeout(void *ud, yasl_private_timer_id id, uint64_t interval_ns);
static void leave(struct x11_display *d)
{
@@ -169,7 +198,7 @@ static void leave(struct x11_display *d)
}
}
-static void push(struct x11_surface *s, struct yasl_event event,
+static void push(struct x11_surface *s, struct yasl_private_event event,
const char *text, size_t len)
{
if (s->destroyed) return;
@@ -189,39 +218,39 @@ static unsigned long component(uint32_t color, unsigned long mask)
return (((unsigned long)color * m + 127) / 255) << shift;
}
-static void drag_set_hover(struct x11_display *d, struct x11_surface *s, struct yasl_vector2i pos)
+static void drag_set_hover(struct x11_display *d, struct x11_surface *s, struct yasl_private_vector2i pos)
{
if (!d->drag.active) return;
if (d->drag.hover && d->drag.hover != s) {
struct x11_surface *old = d->drag.hover;
- struct yasl_vector2i old_pos = d->drag.hover_pos;
+ struct yasl_private_vector2i old_pos = d->drag.hover_pos;
d->drag.hover = NULL;
if (!old->destroyed)
- yasl_surface_notify_drag(&old->base, YASL_DRAG_LEAVE, old_pos);
+ yasl_private_surface_notify_drag(&old->base, YASL_PRIVATE_DRAG_LEAVE, old_pos);
if (!d->drag.active || (s && s->destroyed)) return;
}
if (s && s->destroyed) return;
d->drag.hover = s;
d->drag.hover_pos = pos;
if (s && !s->destroyed)
- yasl_surface_notify_drag(&s->base, YASL_DRAG_OVER, pos);
+ yasl_private_surface_notify_drag(&s->base, YASL_PRIVATE_DRAG_OVER, pos);
}
-static void drag_leave_hover(struct x11_display *d, struct x11_surface *s, struct yasl_vector2i pos)
+static void drag_leave_hover(struct x11_display *d, struct x11_surface *s, struct yasl_private_vector2i pos)
{
if (!d->drag.active || d->drag.hover != s) return;
d->drag.hover = NULL;
if (s && !s->destroyed)
- yasl_surface_notify_drag(&s->base, YASL_DRAG_LEAVE, pos);
+ yasl_private_surface_notify_drag(&s->base, YASL_PRIVATE_DRAG_LEAVE, pos);
}
static void drag_drop_hover(struct x11_display *d)
{
if (!d->drag.active) return;
- drag_end(d, YASL_DRAG_DROPPED);
+ drag_end(d, YASL_PRIVATE_DRAG_DROPPED);
}
-static int yasl_x11_error_handler(Display *native, XErrorEvent *event)
+static int yasl_private_x11_error_handler(Display *native, XErrorEvent *event)
{
(void)native;
(void)event;
@@ -230,7 +259,7 @@ static int yasl_x11_error_handler(Display *native, XErrorEvent *event)
return 0;
}
-static struct x11_surface *surface_at_root_pos(struct x11_display *d, int rx, int ry, struct yasl_vector2i *out_pos)
+static struct x11_surface *surface_at_root_pos(struct x11_display *d, int rx, int ry, struct yasl_private_vector2i *out_pos)
{
if (!d->native) return NULL;
Window ignore_icon = d->drag.icon_window;
@@ -243,7 +272,7 @@ static struct x11_surface *surface_at_root_pos(struct x11_display *d, int rx, in
if (XTranslateCoordinates(d->native, RootWindow(d->native, d->screen),
s->window, rx, ry, &tx, &ty, &sub)) {
if (tx >= 0 && ty >= 0 && tx < s->size.x && ty < s->size.y) {
- if (out_pos) *out_pos = (struct yasl_vector2i){tx, ty};
+ if (out_pos) *out_pos = (struct yasl_private_vector2i){tx, ty};
return s;
}
}
@@ -253,19 +282,31 @@ static struct x11_surface *surface_at_root_pos(struct x11_display *d, int rx, in
static uint32_t modifiers(unsigned state)
{
- return ((state & ShiftMask) ? YASL_MOD_SHIFT : 0) |
- ((state & ControlMask) ? YASL_MOD_CTRL : 0) |
- ((state & Mod1Mask) ? YASL_MOD_ALT : 0) |
- ((state & Mod4Mask) ? YASL_MOD_SUPER : 0) |
- ((state & LockMask) ? YASL_MOD_CAPS : 0);
+ return ((state & ShiftMask) ? YASL_PRIVATE_MOD_SHIFT : 0) |
+ ((state & ControlMask) ? YASL_PRIVATE_MOD_CTRL : 0) |
+ ((state & Mod1Mask) ? YASL_PRIVATE_MOD_ALT : 0) |
+ ((state & Mod4Mask) ? YASL_PRIVATE_MOD_SUPER : 0) |
+ ((state & LockMask) ? YASL_PRIVATE_MOD_CAPS : 0);
}
static void pointer_info(struct x11_display *d, struct x11_pointer *p,
const XIDeviceInfo *info)
{
p->id = info->deviceid;
- p->device = YASL_PTR_DEV_MOUSE;
+ p->device = YASL_PRIVATE_PTR_DEV_MOUSE;
+ p->tool = 0;
+ p->buttons = 0;
p->pressure.number = p->tilt_x.number = p->tilt_y.number = -1;
+ p->rotation.number = p->distance.number = p->tangential.number = p->wheel.number = -1;
+ p->scroll_x.number = p->scroll_y.number = -1;
+ if (info->name) {
+ for (const char *s = info->name; *s; s++) {
+ if (!strncasecmp(s, "touchpad", 8) || !strncasecmp(s, "trackpad", 8)) {
+ p->finger_scroll = true;
+ break;
+ }
+ }
+ }
bool touch = false;
for (int i = 0; i < info->num_classes; i++) {
XIAnyClassInfo *c = info->classes[i];
@@ -275,17 +316,42 @@ static void pointer_info(struct x11_display *d, struct x11_pointer *p,
if (v->mode != XIModeAbsolute) continue;
struct tablet_axis *axis = v->label == d->abs_pressure ? &p->pressure :
v->label == d->abs_tilt_x ? &p->tilt_x :
- v->label == d->abs_tilt_y ? &p->tilt_y : NULL;
- if (axis) *axis = (struct tablet_axis){v->number, v->min, v->max, v->value};
+ v->label == d->abs_tilt_y ? &p->tilt_y :
+ v->label == d->abs_rotation ? &p->rotation :
+ v->label == d->abs_distance ? &p->distance :
+ v->label == d->abs_tangential ? &p->tangential :
+ v->label == d->abs_wheel ? &p->wheel : NULL;
+ if (axis) *axis = (struct tablet_axis){v->number, v->min, v->max, v->value, true};
+ }
+ for (int i = 0; i < info->num_classes; i++) {
+ XIAnyClassInfo *c = info->classes[i];
+ if (c->type != XIScrollClass) continue;
+ XIScrollClassInfo *scroll = (XIScrollClassInfo *)c;
+ struct x11_scroll_axis *axis = scroll->scroll_type == XIScrollTypeVertical ?
+ &p->scroll_y : scroll->scroll_type == XIScrollTypeHorizontal ? &p->scroll_x : NULL;
+ if (!axis) continue;
+ *axis = (struct x11_scroll_axis){.number = scroll->number,
+ .increment = scroll->increment, .type = scroll->scroll_type};
+ for (int j = 0; j < info->num_classes; j++) {
+ XIAnyClassInfo *vclass = info->classes[j];
+ if (vclass->type != XIValuatorClass) continue;
+ XIValuatorClassInfo *v = (XIValuatorClassInfo *)vclass;
+ if (v->number == scroll->number) {
+ axis->value = v->value;
+ axis->initialized = axis->valid = true;
+ break;
+ }
+ }
}
if (!touch && p->pressure.number >= 0) {
- p->device = YASL_PTR_DEV_PEN;
+ p->device = YASL_PRIVATE_PTR_DEV_PEN;
+ p->tool = 1;
/* Xorg's Wacom and libinput drivers expose separate eraser devices.
* Use the tool property when available, with the device name as a
* fallback for servers (including Xwayland) without that property. */
if (info->name) {
for (const char *s = info->name; *s; s++)
- if (!strncasecmp(s, "eraser", 6)) { p->device = YASL_PTR_DEV_ERASER; break; }
+ if (!strncasecmp(s, "eraser", 6)) { p->device = YASL_PRIVATE_PTR_DEV_ERASER; break; }
}
}
}
@@ -301,17 +367,21 @@ static struct x11_pointer *pointer_for(struct x11_display *d, int id)
struct x11_pointer *p = count ? calloc(1, sizeof(*p)) : NULL;
if (p) {
pointer_info(d, p, info);
- if (p->device == YASL_PTR_DEV_PEN || p->device == YASL_PTR_DEV_ERASER) {
+ if (p->device == YASL_PRIVATE_PTR_DEV_PEN || p->device == YASL_PRIVATE_PTR_DEV_ERASER) {
Atom type;
int format;
unsigned long n, after;
unsigned char *value = NULL;
if (XIGetProperty(d->native, id, d->tool_type, 0, 1, False,
XA_ATOM, &type, &format, &n, &after, &value) == Success &&
- type == XA_ATOM && format == 32 && n == 1 && value)
+ type == XA_ATOM && format == 32 && n == 1 && value) {
/* XIGetProperty packs format-32 values as uint32_t, unlike
* XGetWindowProperty's array of native-sized longs. */
- p->device = *(uint32_t *)value == d->eraser ? YASL_PTR_DEV_ERASER : p->device;
+ if (*(uint32_t *)value == d->eraser) p->device = YASL_PRIVATE_PTR_DEV_ERASER;
+ else if (d->brush && *(uint32_t *)value == d->brush) p->tool = 3;
+ else if (d->airbrush && *(uint32_t *)value == d->airbrush) p->tool = 4;
+ else if (d->pencil && *(uint32_t *)value == d->pencil) p->tool = 5;
+ }
if (value) XFree(value);
}
p->next = d->pointers;
@@ -330,21 +400,61 @@ static void clear_pointers(struct x11_display *d)
}
}
-static void update_axes(struct x11_pointer *p, const XIValuatorState *state)
+static uint32_t update_axes(struct x11_pointer *p, const XIValuatorState *state)
{
+ uint32_t changed = 0;
const double *value = state->values;
for (int i = 0; i < state->mask_len * 8; i++) {
if (!XIMaskIsSet(state->mask, i)) continue;
- struct tablet_axis *axes[] = {&p->pressure, &p->tilt_x, &p->tilt_y};
+ struct tablet_axis *axes[] = {&p->pressure, &p->tilt_x, &p->tilt_y, &p->rotation,
+ &p->distance, &p->tangential, &p->wheel};
+ const uint32_t bits[] = {YASL_PRIVATE_PEN_PRESSURE, YASL_PRIVATE_PEN_TILT,
+ YASL_PRIVATE_PEN_TILT, YASL_PRIVATE_PEN_ROTATION, YASL_PRIVATE_PEN_DISTANCE,
+ YASL_PRIVATE_PEN_TANGENTIAL, YASL_PRIVATE_PEN_WHEEL};
for (unsigned a = 0; a < sizeof(axes) / sizeof(axes[0]); a++)
- if (axes[a]->number == i && isfinite(*value)) axes[a]->value = *value;
+ if (axes[a]->number == i && isfinite(*value)) {
+ axes[a]->value = *value;
+ axes[a]->valid = true;
+ changed |= bits[a];
+ }
+ value++;
+ }
+ return changed;
+}
+
+static void update_scroll(struct x11_pointer *p, const XIValuatorState *state,
+ struct yasl_private_pointer_event *out)
+{
+ const double *value = state->values;
+ for (int i = 0; i < state->mask_len * 8; i++) {
+ if (!XIMaskIsSet(state->mask, i)) continue;
+ struct x11_scroll_axis *axes[] = {&p->scroll_x, &p->scroll_y};
+ for (unsigned a = 0; a < 2; a++) {
+ struct x11_scroll_axis *axis = axes[a];
+ if (axis->number != i || !isfinite(*value)) continue;
+ if (axis->initialized) {
+ double delta = *value - axis->value;
+ if (axis->increment != 0 && isfinite(delta)) {
+ double lines = delta / axis->increment;
+ if (a == 0) out->scroll.x += lines;
+ else out->scroll.y += lines;
+ if (lines != 0) {
+ out->scroll_valid |= 1u;
+ out->scroll_source = p->finger_scroll ? 2u : 1u;
+ out->scroll_phase = 2u;
+ }
+ }
+ }
+ axis->value = *value;
+ axis->initialized = true;
+ }
value++;
}
}
static uint16_t pressure_value(const struct tablet_axis *a)
{
- if (a->number < 0 || !(a->max > a->min) || !isfinite(a->value)) return 0;
+ if (a->number < 0 || !(a->max > a->min) || !a->valid || !isfinite(a->value)) return 0;
double v = (a->value - a->min) / (a->max - a->min);
return (uint16_t)lround(fmax(0, fmin(1, v)) * 65535);
}
@@ -352,50 +462,121 @@ static uint16_t pressure_value(const struct tablet_axis *a)
static int8_t tilt_value(const struct tablet_axis *a)
{
/* Xorg tablet tilt valuators are already in degrees. */
- return a->number < 0 || !isfinite(a->value) ? 0 :
+ return a->number < 0 || !a->valid || !isfinite(a->value) ? 0 :
(int8_t)lround(fmax(-90, fmin(90, a->value)));
}
-static enum yasl_pointer_button pointer_button(unsigned button)
+static enum yasl_private_pointer_button pointer_button(unsigned button)
+{
+ return button == 1 ? YASL_PRIVATE_BUTTON_PRIMARY :
+ button == 2 ? YASL_PRIVATE_BUTTON_MIDDLE :
+ button == 3 ? YASL_PRIVATE_BUTTON_SECONDARY :
+ button >= 8 && button <= INT16_MAX ? (enum yasl_private_pointer_button)(button - 5) :
+ YASL_PRIVATE_BUTTON_BACK;
+}
+
+static uint32_t pen_axes_valid(const struct x11_pointer *p)
{
- return button == 1 ? YASL_BUTTON_PRIMARY :
- button == 2 ? YASL_BUTTON_MIDDLE :
- button == 3 ? YASL_BUTTON_SECONDARY :
- button >= 8 && button <= INT16_MAX ? (enum yasl_pointer_button)(button - 5) :
- YASL_BUTTON_BACK;
+ return (p->pressure.valid ? YASL_PRIVATE_PEN_PRESSURE : 0) |
+ (p->tilt_x.valid || p->tilt_y.valid ? YASL_PRIVATE_PEN_TILT : 0) |
+ (p->rotation.valid ? YASL_PRIVATE_PEN_ROTATION : 0) |
+ (p->distance.valid ? YASL_PRIVATE_PEN_DISTANCE : 0) |
+ (p->tangential.valid ? YASL_PRIVATE_PEN_TANGENTIAL : 0) |
+ (p->wheel.valid ? YASL_PRIVATE_PEN_WHEEL : 0);
+}
+
+static double axis_normalized(const struct tablet_axis *axis)
+{
+ return axis->valid && axis->max > axis->min && isfinite(axis->value) ?
+ fmax(0, fmin(1, (axis->value - axis->min) / (axis->max - axis->min))) : 0;
+}
+
+static void push_pen_sample(struct x11_surface *s, struct x11_pointer *p,
+ unsigned action, double x, double y, uint32_t changed, unsigned changed_button)
+{
+ if (!p || (p->device != YASL_PRIVATE_PTR_DEV_PEN && p->device != YASL_PRIVATE_PTR_DEV_ERASER)) return;
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_PEN,
+ .pen = {
+ .device_id = (uint64_t)(unsigned)p->id,
+ .tool_id = 0, /* XI2 exposes source IDs, but not a stable per-tool serial. */
+ .x = x, .y = y,
+ .pressure = p->pressure.valid && p->pressure.max > p->pressure.min ?
+ fmax(0, fmin(1, (p->pressure.value - p->pressure.min) /
+ (p->pressure.max - p->pressure.min))) : 0,
+ .tilt_x = p->tilt_x.valid ? fmax(-90, fmin(90, p->tilt_x.value)) : 0,
+ .tilt_y = p->tilt_y.valid ? fmax(-90, fmin(90, p->tilt_y.value)) : 0,
+ .rotation = p->rotation.valid ? p->rotation.value : 0,
+ .distance = axis_normalized(&p->distance),
+ .tangential = p->tangential.valid && p->tangential.max > p->tangential.min ?
+ fmax(-1, fmin(1, 2 * axis_normalized(&p->tangential) - 1)) : 0,
+ .wheel_degrees = p->wheel.valid ? p->wheel.value : 0,
+ .axes_valid = pen_axes_valid(p), .axes_changed = changed,
+ .buttons = p->buttons, .changed_button = changed_button,
+ .in_contact = (p->buttons & YASL_PRIVATE_BUTTON_BIT(YASL_PRIVATE_BUTTON_PRIMARY)) != 0,
+ .tool = p->device == YASL_PRIVATE_PTR_DEV_ERASER ? 2u : p->tool,
+ .action = action,
+ }}, NULL, 0);
}
static void xi_pointer_event(struct x11_surface *s, const XIDeviceEvent *ev)
{
struct x11_display *d = (struct x11_display *)s->base.display;
struct x11_pointer *p = pointer_for(d, ev->sourceid);
- struct yasl_event event = {
+ struct yasl_private_event event = {
.pointer = {
- .pos = {yasl_scale_to_device(ev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(ev->event_y, YASL_SCALE_UNIT)},
- .device = p ? p->device : YASL_PTR_DEV_MOUSE,
+ .pos = {yasl_private_scale_to_device(ev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(ev->event_y, YASL_PRIVATE_SCALE_UNIT)},
+ .device = p ? p->device : YASL_PRIVATE_PTR_DEV_MOUSE,
.mods = modifiers(ev->mods.effective),
},
};
- if (p && (p->device == YASL_PTR_DEV_PEN || p->device == YASL_PTR_DEV_ERASER)) {
- update_axes(p, &ev->valuators);
- if (ev->evtype == XI_ButtonRelease && ev->detail == 1)
+ uint32_t pen_changed = 0;
+ if (p && (p->device == YASL_PRIVATE_PTR_DEV_PEN || p->device == YASL_PRIVATE_PTR_DEV_ERASER)) {
+ pen_changed = update_axes(p, &ev->valuators);
+ if (ev->evtype == XI_ButtonRelease && ev->detail == 1) {
p->pressure.value = p->pressure.min;
- event.pointer.pen = (struct yasl_pointer_pen){
+ pen_changed |= p->pressure.valid ? YASL_PRIVATE_PEN_PRESSURE : 0;
+ }
+ if (ev->evtype == XI_ButtonPress || ev->evtype == XI_ButtonRelease) {
+ enum yasl_private_pointer_button button = pointer_button(ev->detail);
+ uint32_t mask = YASL_PRIVATE_BUTTON_BIT(button);
+ if (ev->evtype == XI_ButtonPress) p->buttons |= mask;
+ else p->buttons &= ~mask;
+ }
+ event.pointer.pen = (struct yasl_private_pointer_pen){
pressure_value(&p->pressure), tilt_value(&p->tilt_x), tilt_value(&p->tilt_y)};
}
- if (ev->evtype == XI_Motion) event.type = YASL_EVENT_POINTER_MOTION;
+ if (p) update_scroll(p, &ev->valuators, &event.pointer);
+ if (ev->evtype == XI_Motion) event.type = YASL_PRIVATE_EVENT_POINTER_MOTION;
else if (ev->detail >= 4 && ev->detail <= 7) {
if (ev->evtype == XI_ButtonRelease) return;
- event.type = YASL_EVENT_POINTER_SCROLL;
+ event.type = YASL_PRIVATE_EVENT_POINTER_SCROLL;
if (ev->detail <= 5) event.pointer.scroll.y = ev->detail == 4 ? -1 : 1;
else event.pointer.scroll.x = ev->detail == 6 ? -1 : 1;
+ event.pointer.scroll_valid = 1u;
+ event.pointer.scroll_source = p && p->finger_scroll ? 2u : 1u;
+ event.pointer.scroll_phase = 2u;
} else {
- event.type = ev->evtype == XI_ButtonPress ? YASL_EVENT_POINTER_DOWN : YASL_EVENT_POINTER_UP;
+ event.type = ev->evtype == XI_ButtonPress ? YASL_PRIVATE_EVENT_POINTER_DOWN : YASL_PRIVATE_EVENT_POINTER_UP;
event.pointer.button = pointer_button(ev->detail);
}
d->mods = event.pointer.mods;
+ if (p && (p->device == YASL_PRIVATE_PTR_DEV_PEN || p->device == YASL_PRIVATE_PTR_DEV_ERASER) &&
+ ev->detail != 4 && ev->detail != 5 && ev->detail != 6 && ev->detail != 7) {
+ unsigned action = ev->evtype == XI_Motion ? YASL_PRIVATE_PEN_MOVE :
+ ev->evtype == XI_ButtonPress ? (ev->detail == 1 ? YASL_PRIVATE_PEN_DOWN : YASL_PRIVATE_PEN_BUTTON) :
+ (ev->detail == 1 ? YASL_PRIVATE_PEN_UP : YASL_PRIVATE_PEN_BUTTON);
+ push_pen_sample(s, p, action, ev->event_x, ev->event_y, pen_changed,
+ ev->evtype == XI_Motion ? 0u : (unsigned)ev->detail);
+ }
push(s, event, NULL, 0);
+ if (event.type == YASL_PRIVATE_EVENT_POINTER_MOTION && event.pointer.scroll_valid) {
+ event.type = YASL_PRIVATE_EVENT_POINTER_SCROLL;
+ event.pointer.pos = (struct yasl_private_vector2i){
+ yasl_private_scale_to_device(ev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(ev->event_y, YASL_PRIVATE_SCALE_UNIT)};
+ push(s, event, NULL, 0);
+ }
}
static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
@@ -403,15 +584,20 @@ static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
if (cookie->evtype == XI_HierarchyChanged || cookie->evtype == XI_DeviceChanged) {
if (cookie->evtype == XI_DeviceChanged &&
((XIDeviceChangedEvent *)cookie->data)->reason == XISlaveSwitch) return;
+ for (struct x11_pointer *p = d->pointers; p; p = p->next) {
+ if (!p->buttons) continue;
+ for (struct x11_surface *s = d->surfaces; s; s = s->next)
+ push_pen_sample(s, p, YASL_PRIVATE_PEN_CANCEL, 0, 0, 0, 0);
+ }
clear_pointers(d);
if (cookie->evtype == XI_HierarchyChanged &&
(((XIHierarchyEvent *)cookie->data)->flags &
(XISlaveRemoved | XIDeviceDisabled | XISlaveDetached | XIMasterRemoved))) {
/* Removal/disable may interrupt a drag before a release arrives. */
if (d->drag.active)
- drag_end(d, YASL_DRAG_CANCELLED);
+ drag_end(d, YASL_PRIVATE_DRAG_CANCELLED);
for (struct x11_surface *s = d->surfaces; s; s = s->next)
- push(s, (struct yasl_event){.type = YASL_EVENT_INPUT_RESET}, NULL, 0);
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_INPUT_RESET}, NULL, 0);
}
return;
}
@@ -430,22 +616,22 @@ static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
XMoveWindow(d->native, d->drag.icon_window,
(int)round(mev->root_x) - d->drag.hotspot.x,
(int)round(mev->root_y) - d->drag.hotspot.y);
- struct yasl_vector2i hpos = {yasl_scale_to_device(mev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(mev->event_y, YASL_SCALE_UNIT)};
+ struct yasl_private_vector2i hpos = {yasl_private_scale_to_device(mev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(mev->event_y, YASL_PRIVATE_SCALE_UNIT)};
struct x11_surface *hsurf = d->native ?
surface_at_root_pos(d, (int)round(mev->root_x), (int)round(mev->root_y), &hpos) : s;
drag_set_hover(d, hsurf, hpos);
} else if (cookie->evtype == XI_Enter && d->drag.active) {
const XIEnterEvent *eev = cookie->data;
- struct yasl_vector2i hpos = {yasl_scale_to_device(eev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(eev->event_y, YASL_SCALE_UNIT)};
+ struct yasl_private_vector2i hpos = {yasl_private_scale_to_device(eev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(eev->event_y, YASL_PRIVATE_SCALE_UNIT)};
struct x11_surface *hsurf = d->native ?
surface_at_root_pos(d, (int)round(eev->root_x), (int)round(eev->root_y), &hpos) : s;
drag_set_hover(d, hsurf, hpos);
} else if (cookie->evtype == XI_Leave && d->drag.active) {
const XIEnterEvent *lev = cookie->data;
- struct yasl_vector2i lpos = {yasl_scale_to_device(lev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(lev->event_y, YASL_SCALE_UNIT)};
+ struct yasl_private_vector2i lpos = {yasl_private_scale_to_device(lev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(lev->event_y, YASL_PRIVATE_SCALE_UNIT)};
drag_leave_hover(d, s, lpos);
} else if (cookie->evtype == XI_ButtonRelease && d->drag.active) {
drag_drop_hover(d);
@@ -455,24 +641,35 @@ static void xi_event(struct x11_display *d, XGenericEventCookie *cookie)
else {
const XIEnterEvent *ev = cookie->data;
struct x11_pointer *p = pointer_for(d, ev->sourceid);
- if (p) p->pressure.value = p->pressure.min;
- push(s, (struct yasl_event){
- .type = cookie->evtype == XI_Leave ? YASL_EVENT_POINTER_LEAVE : YASL_EVENT_POINTER_MOTION,
+ if (p && cookie->evtype == XI_Leave) {
+ p->pressure.value = p->pressure.min;
+ if (p->pressure.valid) push_pen_sample(s, p, YASL_PRIVATE_PEN_LEAVE,
+ ev->event_x, ev->event_y, YASL_PRIVATE_PEN_PRESSURE, 0);
+ } else if (p && (p->device == YASL_PRIVATE_PTR_DEV_PEN || p->device == YASL_PRIVATE_PTR_DEV_ERASER)) {
+ push_pen_sample(s, p, YASL_PRIVATE_PEN_ENTER, ev->event_x, ev->event_y, 0, 0);
+ }
+ push(s, (struct yasl_private_event){
+ .type = cookie->evtype == XI_Leave ? YASL_PRIVATE_EVENT_POINTER_LEAVE : YASL_PRIVATE_EVENT_POINTER_MOTION,
.pointer = {
- .pos = {yasl_scale_to_device(ev->event_x, YASL_SCALE_UNIT),
- yasl_scale_to_device(ev->event_y, YASL_SCALE_UNIT)},
- .device = p ? p->device : YASL_PTR_DEV_MOUSE,
+ .pos = {yasl_private_scale_to_device(ev->event_x, YASL_PRIVATE_SCALE_UNIT),
+ yasl_private_scale_to_device(ev->event_y, YASL_PRIVATE_SCALE_UNIT)},
+ .device = p ? p->device : YASL_PRIVATE_PTR_DEV_MOUSE,
.mods = modifiers(ev->mods.effective),
},
}, NULL, 0);
}
}
-static bool resize(struct x11_surface *s, struct yasl_vector2i size)
+static bool resize(struct x11_surface *s, struct yasl_private_vector2i size)
{
if (size.x <= 0 || size.y <= 0 || size.x > 32767 || size.y > 32767 ||
(size_t)size.x > SIZE_MAX / sizeof(uint32_t) / (size_t)size.y)
return false;
+ if (s->base.presenter != YASL_PRIVATE_PRESENTER_CPU) {
+ s->size = size;
+ s->base.size = size;
+ return true;
+ }
if (s->image && size.x == s->size.x && size.y == s->size.y) return true;
struct x11_display *d = (struct x11_display *)s->base.display;
if (!d->native) {
@@ -480,7 +677,7 @@ static bool resize(struct x11_surface *s, struct yasl_vector2i size)
s->want_draw = true;
return true;
}
- uint64_t start = yasl_loop_now_ns();
+ uint64_t start = yasl_private_loop_now_ns();
/* The presented frame goes with the old pixels. */
s->presented = false;
@@ -557,9 +754,9 @@ static bool resize(struct x11_surface *s, struct yasl_vector2i size)
s->pixels = pixels;
s->size = size;
s->base.size = size;
- s->base.scale_120 = YASL_SCALE_UNIT;
+ s->base.scale_120 = YASL_PRIVATE_SCALE_UNIT;
s->want_draw = true;
- yasl_clock_note_resize(&s->clock, yasl_loop_now_ns() - start);
+ yasl_private_clock_note_resize(&s->clock, yasl_private_loop_now_ns() - start);
return true;
}
@@ -575,7 +772,7 @@ static void cancel_pastes(struct x11_display *d, struct x11_surface *target)
p = &r->next;
} else if (!target) {
*p = r->next;
- if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
+ if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
XDestroyWindow(d->native, r->window);
free(r);
} else {
@@ -584,7 +781,7 @@ static void cancel_pastes(struct x11_display *d, struct x11_surface *target)
}
}
-static uint64_t paste_timeout(void *ud, yasl_timer_id id, uint64_t interval_ns)
+static uint64_t paste_timeout(void *ud, yasl_private_timer_id id, uint64_t interval_ns)
{
(void)id;
(void)interval_ns;
@@ -597,7 +794,7 @@ static uint64_t paste_timeout(void *ud, yasl_timer_id id, uint64_t interval_ns)
r->timeout = 0; /* The loop retires this one-shot timer after the callback. */
XDestroyWindow(d->native, r->window);
if (s && !s->destroyed)
- yasl_surface_complete_paste(&s->base, r->id, YASL_TRANSFER_FAILED, NULL, 0);
+ yasl_private_surface_complete_paste(&s->base, r->id, YASL_PRIVATE_TRANSFER_FAILED, NULL, 0);
free(r);
return 0;
}
@@ -609,7 +806,7 @@ static void surface_destroy(struct yasl_surface *base)
struct x11_display *d = (struct x11_display *)base->display;
if (d->drag.active) {
if (d->drag.origin == s || d->drag.carried == s)
- drag_end(d, YASL_DRAG_CANCELLED);
+ drag_end(d, YASL_PRIVATE_DRAG_CANCELLED);
else if (d->drag.hover == s)
d->drag.hover = NULL;
}
@@ -627,6 +824,10 @@ static void surface_destroy(struct yasl_surface *base)
free(s->ime_preedit);
s->ime_preedit = NULL;
if (s->ic) XDestroyIC(s->ic);
+#if YASL_HAS_EGL
+ if (s->gl_context && d->egl_ready) eglDestroyContext(d->egl, s->gl_context);
+ if (s->gl_surface && d->egl_ready) eglDestroySurface(d->egl, s->gl_surface);
+#endif
if (s->shm_active) {
XShmDetach(d->native, &s->shm_info);
if (s->image) XDestroyImage(s->image);
@@ -643,6 +844,7 @@ static void surface_destroy(struct yasl_surface *base)
if (d->native) {
if (s->gc) XFreeGC(d->native, s->gc);
if (s->window) XDestroyWindow(d->native, s->window);
+ if (s->colormap) XFreeColormap(d->native, s->colormap);
}
input_queue_clear(&s->input);
if (d->depth) {
@@ -652,11 +854,11 @@ static void surface_destroy(struct yasl_surface *base)
}
static void set_callbacks(struct yasl_surface *base,
- const struct yasl_window_cbs *cbs, void *ud)
+ const struct yasl_private_window_cbs *cbs, void *ud)
{
struct x11_surface *s = (struct x11_surface *)base;
if (s->destroyed) return;
- s->base.callbacks = cbs ? *cbs : (struct yasl_window_cbs){0};
+ s->base.callbacks = cbs ? *cbs : (struct yasl_private_window_cbs){0};
s->cbs = &s->base.callbacks;
s->base.ud = ud;
s->ud = ud;
@@ -685,7 +887,7 @@ static bool net_message(struct x11_surface *s, Atom type,
SubstructureRedirectMask | SubstructureNotifyMask, &event) != 0;
}
-static bool surface_set_size(struct yasl_surface *base, struct yasl_vector2i size)
+static bool surface_set_size(struct yasl_surface *base, struct yasl_private_vector2i size)
{
struct x11_surface *s = (struct x11_surface *)base;
struct x11_display *d = (struct x11_display *)base->display;
@@ -817,7 +1019,7 @@ static char *xim_text_dup(const XIMText *text, size_t *len)
if (converted != text->length) { free(out); return NULL; }
}
out[used] = '\0';
- if (!yasl_utf8_validate(out, used)) { free(out); return NULL; }
+ if (!yasl_private_utf8_validate(out, used)) { free(out); return NULL; }
*len = used;
return out;
}
@@ -831,7 +1033,7 @@ static void xim_preedit_done(XIM im, XPointer client_data, XPointer call_data)
free(s->ime_preedit);
s->ime_preedit = NULL;
s->ime_cursor_begin = s->ime_cursor_end = -1;
- yasl_surface_notify_composition(&s->base, NULL, -1, -1);
+ yasl_private_surface_notify_composition(&s->base, NULL, -1, -1);
}
static int xim_preedit_start(XIM im, XPointer client_data, XPointer call_data)
@@ -880,7 +1082,7 @@ static void xim_preedit_draw(XIM im, XPointer client_data, XPointer call_data)
int caret = draw->caret < 0 ? -1 : (int)utf8_offset_for_chars(
s->ime_preedit ? s->ime_preedit : "", new_len, draw->caret);
s->ime_cursor_begin = s->ime_cursor_end = caret;
- yasl_surface_notify_composition(&s->base, s->ime_preedit, caret, caret);
+ yasl_private_surface_notify_composition(&s->base, s->ime_preedit, caret, caret);
}
static void xim_preedit_caret(XIM im, XPointer client_data, XPointer call_data)
@@ -892,7 +1094,7 @@ static void xim_preedit_caret(XIM im, XPointer client_data, XPointer call_data)
int offset = caret->position < 0 ? -1 : (int)utf8_offset_for_chars(
s->ime_preedit, strlen(s->ime_preedit), caret->position);
s->ime_cursor_begin = s->ime_cursor_end = offset;
- yasl_surface_notify_composition(&s->base, s->ime_preedit, offset, offset);
+ yasl_private_surface_notify_composition(&s->base, s->ime_preedit, offset, offset);
}
static XIC create_ic(struct x11_display *d, struct x11_surface *s)
@@ -923,22 +1125,35 @@ static XIC create_ic(struct x11_display *d, struct x11_surface *s)
return ic;
}
-static struct yasl_surface *create_toplevel(struct yasl_display *base,
- const struct yasl_window_spec *spec, void *graphics_device)
+static struct yasl_surface *create_toplevel_visual(struct yasl_private_display *base,
+ const struct yasl_private_window_spec *spec, Visual *visual, int depth,
+ enum yasl_private_presenter presenter)
{
- (void)graphics_device;
if (!spec) return NULL;
struct x11_display *d = (struct x11_display *)base;
struct x11_surface *s = calloc(1, sizeof(*s));
if (!s) return NULL;
s->base.display = base;
- s->clock.refresh_ns = YASL_REFRESH_DEFAULT_NS;
+ s->base.creation_flags = spec->flags | (spec->external_gpu ? 0u : YASL_PRIVATE_SURFACE_CPU);
+ s->base.presenter = presenter;
+ s->clock.refresh_ns = YASL_PRIVATE_REFRESH_DEFAULT_NS;
if (!resize(s, spec->size)) { free(s); return NULL; }
- s->window = XCreateSimpleWindow(d->native, RootWindow(d->native, d->screen),
- 0, 0, (unsigned)spec->size.x, (unsigned)spec->size.y, 0, 0, 0);
+ if (!visual) visual = DefaultVisual(d->native, d->screen);
+ if (!depth) depth = DefaultDepth(d->native, d->screen);
+ s->colormap = XCreateColormap(d->native, RootWindow(d->native, d->screen), visual, AllocNone);
+ XSetWindowAttributes attrs = {.colormap = s->colormap, .border_pixel = 0, .background_pixel = 0};
+ s->window = XCreateWindow(d->native, RootWindow(d->native, d->screen), 0, 0,
+ (unsigned)spec->size.x, (unsigned)spec->size.y, 0, depth, InputOutput,
+ visual, CWBorderPixel | CWBackPixel | CWColormap, &attrs);
+ if (!s->window) {
+ XFreeColormap(d->native, s->colormap);
+ free(s);
+ errno = ENODEV;
+ return NULL;
+ }
s->base.native_handle = (void *)(uintptr_t)s->window;
s->base.size = s->size;
- s->base.scale_120 = YASL_SCALE_UNIT;
+ s->base.scale_120 = YASL_PRIVATE_SCALE_UNIT;
s->gc = XCreateGC(d->native, s->window, 0, NULL);
XSelectInput(d->native, s->window, ExposureMask | StructureNotifyMask |
FocusChangeMask | KeyPressMask | KeyReleaseMask | PropertyChangeMask |
@@ -955,6 +1170,19 @@ static struct yasl_surface *create_toplevel(struct yasl_display *base,
XISelectEvents(d->native, s->window, &mask, 1);
}
XSetWMProtocols(d->native, s->window, &d->delete_window, 1);
+ if (spec->flags & YASL_PRIVATE_SURFACE_UNDECORATED) {
+ struct { unsigned long flags, functions, decorations; long input_mode; unsigned long status; } hints = {
+ .flags = 1, .decorations = 0,
+ };
+ XChangeProperty(d->native, s->window, d->motif_hints, d->motif_hints, 32,
+ PropModeReplace, (unsigned char *)&hints, 5);
+ }
+ if (spec->flags & YASL_PRIVATE_SURFACE_FIXED_SIZE) {
+ XSizeHints size_hints = {.flags = PMinSize | PMaxSize,
+ .min_width = spec->size.x, .max_width = spec->size.x,
+ .min_height = spec->size.y, .max_height = spec->size.y};
+ XSetWMNormalHints(d->native, s->window, &size_hints);
+ }
XClassHint hint = { .res_name = d->app_id, .res_class = d->app_id };
XSetClassHint(d->native, s->window, &hint);
Atom xdnd_version = 5;
@@ -967,17 +1195,197 @@ static struct yasl_surface *create_toplevel(struct yasl_display *base,
if (spec->fullscreen) {
XChangeProperty(d->native, s->window, d->net_state, XA_ATOM, 32,
PropModeReplace, (unsigned char *)&d->fullscreen, 1);
- s->base.state |= YASL_STATE_FULLSCREEN;
+ s->base.state |= YASL_PRIVATE_STATE_FULLSCREEN;
}
- XMapWindow(d->native, s->window);
+ if (!(spec->flags & YASL_PRIVATE_SURFACE_HIDDEN)) XMapWindow(d->native, s->window);
XFlush(d->native);
return &s->base;
}
+static struct yasl_surface *create_toplevel(struct yasl_private_display *base,
+ const struct yasl_private_window_spec *spec, void *graphics_device)
+{
+ if (!spec) return NULL;
+ if (graphics_device) { errno = ENOTSUP; return NULL; }
+ return create_toplevel_visual(base, spec, NULL, 0,
+ spec->external_gpu ? YASL_PRIVATE_PRESENTER_NONE : YASL_PRIVATE_PRESENTER_CPU);
+}
+
+#if YASL_HAS_EGL
+static bool egl_open(struct x11_display *d)
+{
+ if (d->egl_ready) return true;
+ d->egl = eglGetDisplay((EGLNativeDisplayType)d->native);
+ EGLint major = 0, minor = 0;
+ if (d->egl == EGL_NO_DISPLAY || !eglInitialize(d->egl, &major, &minor)) {
+ errno = ENOTSUP;
+ return false;
+ }
+ d->egl_ready = true;
+ return true;
+}
+
+static struct yasl_surface *create_gl_surface(struct yasl_private_display *base,
+ const struct yasl_private_window_spec *spec, const int *attrs,
+ struct yasl_surface *share)
+{
+ if (!spec) { errno = EINVAL; return NULL; }
+ struct x11_display *d = (struct x11_display *)base;
+ struct yasl_private_gl_options options;
+ if (!yasl_private_gl_parse_options(attrs, &options)) { errno = EINVAL; return NULL; }
+ if (!egl_open(d)) return NULL;
+ if (options.srgb) {
+ const char *extensions = eglQueryString(d->egl, EGL_EXTENSIONS);
+ if (!extensions || !strstr(extensions, "EGL_KHR_gl_colorspace")) {
+ errno = ENOTSUP;
+ return NULL;
+ }
+ }
+
+ EGLint renderable = options.api == YASL_PRIVATE_GL_OPENGL_ES ? EGL_OPENGL_ES2_BIT : EGL_OPENGL_BIT;
+ EGLint config_attrs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, renderable,
+ EGL_RED_SIZE, options.red_bits,
+ EGL_GREEN_SIZE, options.green_bits,
+ EGL_BLUE_SIZE, options.blue_bits,
+ EGL_ALPHA_SIZE, options.alpha_bits,
+ EGL_DEPTH_SIZE, options.depth_bits,
+ EGL_STENCIL_SIZE, options.stencil_bits,
+ EGL_SAMPLE_BUFFERS, options.samples > 0 ? 1 : 0,
+ EGL_SAMPLES, options.samples,
+ EGL_NONE,
+ };
+ EGLConfig config = NULL;
+ EGLint count = 0;
+ if (!eglChooseConfig(d->egl, config_attrs, &config, 1, &count) || !count) {
+ errno = ENOTSUP;
+ return NULL;
+ }
+ EGLint visual_id = 0, depth = 0;
+ if (!eglGetConfigAttrib(d->egl, config, EGL_NATIVE_VISUAL_ID, &visual_id) ||
+ !eglGetConfigAttrib(d->egl, config, EGL_BUFFER_SIZE, &depth)) {
+ errno = ENODEV;
+ return NULL;
+ }
+ XVisualInfo visual_query = {.visualid = (VisualID)visual_id};
+ int visual_count = 0;
+ XVisualInfo *visual_info = XGetVisualInfo(d->native, VisualIDMask, &visual_query, &visual_count);
+ if (!visual_info || !visual_count) {
+ if (visual_info) XFree(visual_info);
+ errno = ENODEV;
+ return NULL;
+ }
+ Visual *visual = visual_info[0].visual;
+ depth = visual_info[0].depth;
+ struct yasl_private_window_spec gl_spec = *spec;
+ gl_spec.external_gpu = true;
+ gl_spec.flags &= ~YASL_PRIVATE_SURFACE_CPU;
+ struct yasl_surface *base_surface = create_toplevel_visual(base, &gl_spec, visual, depth,
+ YASL_PRIVATE_PRESENTER_GL);
+ XFree(visual_info);
+ if (!base_surface) return NULL;
+ struct x11_surface *s = (struct x11_surface *)base_surface;
+ s->gl_config = config;
+ EGLint surface_attrs[] = {EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, EGL_NONE};
+ s->gl_surface = eglCreateWindowSurface(d->egl, config,
+ (EGLNativeWindowType)s->window, options.srgb ? surface_attrs : NULL);
+ if (s->gl_surface == EGL_NO_SURFACE) {
+ surface_destroy(base_surface);
+ errno = ENODEV;
+ return NULL;
+ }
+ if (options.api == YASL_PRIVATE_GL_OPENGL) {
+ if (!eglBindAPI(EGL_OPENGL_API)) { surface_destroy(base_surface); errno = ENOTSUP; return NULL; }
+ } else if (!eglBindAPI(EGL_OPENGL_ES_API)) {
+ surface_destroy(base_surface); errno = ENOTSUP; return NULL;
+ }
+ EGLContext share_context = EGL_NO_CONTEXT;
+ if (share) {
+ struct x11_surface *shared = (struct x11_surface *)share;
+ if (share->display != base || shared->base.presenter != YASL_PRIVATE_PRESENTER_GL ||
+ shared->gl_context == EGL_NO_CONTEXT) {
+ surface_destroy(base_surface); errno = EINVAL; return NULL;
+ }
+ share_context = shared->gl_context;
+ }
+ EGLint context_attrs[12];
+ EGLint n = 0;
+ context_attrs[n++] = EGL_CONTEXT_MAJOR_VERSION;
+ context_attrs[n++] = options.major;
+ context_attrs[n++] = EGL_CONTEXT_MINOR_VERSION;
+ context_attrs[n++] = options.minor;
+ if (options.api == YASL_PRIVATE_GL_OPENGL && options.profile != YASL_PRIVATE_GL_ANY) {
+ context_attrs[n++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
+ context_attrs[n++] = options.profile == YASL_PRIVATE_GL_CORE ?
+ EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR;
+ }
+ EGLint context_flags = (options.debug ? EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR : 0) |
+ (options.forward_compat ? EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR : 0);
+ if (context_flags) {
+ context_attrs[n++] = EGL_CONTEXT_FLAGS_KHR;
+ context_attrs[n++] = context_flags;
+ }
+ context_attrs[n] = EGL_NONE;
+ s->gl_context = eglCreateContext(d->egl, config, share_context, context_attrs);
+ if (s->gl_context == EGL_NO_CONTEXT) {
+ surface_destroy(base_surface);
+ errno = ENOTSUP;
+ return NULL;
+ }
+ return base_surface;
+}
+
+static bool gl_make_current(struct yasl_private_display *base, struct yasl_surface *surface)
+{
+ struct x11_display *d = (struct x11_display *)base;
+ if (!d->egl_ready) { errno = ENOTSUP; return false; }
+ if (!surface) return eglMakeCurrent(d->egl, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ struct x11_surface *s = (struct x11_surface *)surface;
+ if (surface->display != base || s->base.presenter != YASL_PRIVATE_PRESENTER_GL || !s->gl_context) {
+ errno = EINVAL;
+ return false;
+ }
+ return eglMakeCurrent(d->egl, s->gl_surface, s->gl_surface, s->gl_context) == EGL_TRUE;
+}
+
+static yasl_private_gl_proc gl_get_proc_address(struct yasl_private_display *base, const char *name)
+{
+ (void)base;
+ return name ? (yasl_private_gl_proc)eglGetProcAddress(name) : NULL;
+}
+
+static bool gl_swap_interval(struct yasl_private_display *base, struct yasl_surface *surface, int interval)
+{
+ struct x11_display *d = (struct x11_display *)base;
+ if (!surface || surface->display != base || ((struct x11_surface *)surface)->base.presenter != YASL_PRIVATE_PRESENTER_GL) {
+ errno = EINVAL;
+ return false;
+ }
+ return d->egl_ready && eglSwapInterval(d->egl, interval) == EGL_TRUE;
+}
+
+static bool gl_swap_buffers(struct yasl_private_display *base, struct yasl_surface *surface)
+{
+ struct x11_display *d = (struct x11_display *)base;
+ struct x11_surface *s = (struct x11_surface *)surface;
+ if (!surface || surface->display != base || s->base.presenter != YASL_PRIVATE_PRESENTER_GL || !d->egl_ready) {
+ errno = EINVAL;
+ return false;
+ }
+ if (!eglSwapBuffers(d->egl, s->gl_surface)) return false;
+ s->presented = true;
+ yasl_private_clock_presented(&s->clock, yasl_private_loop_now_ns(), false);
+ return true;
+}
+#endif
+
static bool popup_spec_valid(const struct x11_surface *parent,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
if (!parent || !spec) return false;
+ if (spec->positioner_explicit && (spec->anchor_edges > 8 || spec->gravity > 8 ||
+ (spec->constraints & ~63u))) return false;
int parent_cx = parent->is_popup ? parent->content_offset.x : 0;
int parent_cy = parent->is_popup ? parent->content_offset.y : 0;
int64_t x = (int64_t)spec->anchor.x - parent_cx;
@@ -992,10 +1400,87 @@ static bool popup_spec_valid(const struct x11_surface *parent,
(int64_t)spec->content_offset.y + spec->content_size.y <= spec->size.y;
}
+enum { X11_ANCHOR_NONE, X11_ANCHOR_TOP, X11_ANCHOR_BOTTOM, X11_ANCHOR_LEFT,
+ X11_ANCHOR_RIGHT, X11_ANCHOR_TOP_LEFT, X11_ANCHOR_BOTTOM_LEFT,
+ X11_ANCHOR_TOP_RIGHT, X11_ANCHOR_BOTTOM_RIGHT };
+enum { X11_CONSTRAINT_SLIDE_X = 1u, X11_CONSTRAINT_SLIDE_Y = 2u,
+ X11_CONSTRAINT_FLIP_X = 4u, X11_CONSTRAINT_FLIP_Y = 8u,
+ X11_CONSTRAINT_RESIZE_X = 16u, X11_CONSTRAINT_RESIZE_Y = 32u };
+
+static void popup_anchor_point(const struct yasl_private_popup_spec *spec, int *x, int *y)
+{
+ switch (spec->anchor_edges) {
+ case X11_ANCHOR_TOP: *x = spec->anchor.x + spec->anchor.width / 2; *y = spec->anchor.y; break;
+ case X11_ANCHOR_BOTTOM: *x = spec->anchor.x + spec->anchor.width / 2; *y = spec->anchor.y + spec->anchor.height; break;
+ case X11_ANCHOR_LEFT: *x = spec->anchor.x; *y = spec->anchor.y + spec->anchor.height / 2; break;
+ case X11_ANCHOR_RIGHT: *x = spec->anchor.x + spec->anchor.width; *y = spec->anchor.y + spec->anchor.height / 2; break;
+ case X11_ANCHOR_TOP_LEFT: *x = spec->anchor.x; *y = spec->anchor.y; break;
+ case X11_ANCHOR_BOTTOM_LEFT: *x = spec->anchor.x; *y = spec->anchor.y + spec->anchor.height; break;
+ case X11_ANCHOR_TOP_RIGHT: *x = spec->anchor.x + spec->anchor.width; *y = spec->anchor.y; break;
+ case X11_ANCHOR_BOTTOM_RIGHT: *x = spec->anchor.x + spec->anchor.width; *y = spec->anchor.y + spec->anchor.height; break;
+ default: *x = spec->anchor.x + spec->anchor.width / 2; *y = spec->anchor.y + spec->anchor.height / 2; break;
+ }
+}
+
+static unsigned popup_flip_x(unsigned gravity)
+{
+ switch (gravity) {
+ case X11_ANCHOR_LEFT: return X11_ANCHOR_RIGHT;
+ case X11_ANCHOR_RIGHT: return X11_ANCHOR_LEFT;
+ case X11_ANCHOR_TOP_LEFT: return X11_ANCHOR_TOP_RIGHT;
+ case X11_ANCHOR_BOTTOM_LEFT: return X11_ANCHOR_BOTTOM_RIGHT;
+ case X11_ANCHOR_TOP_RIGHT: return X11_ANCHOR_TOP_LEFT;
+ case X11_ANCHOR_BOTTOM_RIGHT: return X11_ANCHOR_BOTTOM_LEFT;
+ default: return gravity;
+ }
+}
+
+static unsigned popup_flip_y(unsigned gravity)
+{
+ switch (gravity) {
+ case X11_ANCHOR_TOP: return X11_ANCHOR_BOTTOM;
+ case X11_ANCHOR_BOTTOM: return X11_ANCHOR_TOP;
+ case X11_ANCHOR_TOP_LEFT: return X11_ANCHOR_BOTTOM_LEFT;
+ case X11_ANCHOR_TOP_RIGHT: return X11_ANCHOR_BOTTOM_RIGHT;
+ case X11_ANCHOR_BOTTOM_LEFT: return X11_ANCHOR_TOP_LEFT;
+ case X11_ANCHOR_BOTTOM_RIGHT: return X11_ANCHOR_TOP_RIGHT;
+ default: return gravity;
+ }
+}
+
+static void popup_position_at(const struct yasl_private_popup_spec *spec, int ax, int ay,
+ unsigned gravity, struct yasl_private_vector2i size, int *x, int *y)
+{
+ int content_w = spec->content_size.x ? spec->content_size.x : size.x - spec->content_offset.x;
+ int content_h = spec->content_size.y ? spec->content_size.y : size.y - spec->content_offset.y;
+ switch (gravity) {
+ case X11_ANCHOR_LEFT: case X11_ANCHOR_TOP_LEFT: case X11_ANCHOR_BOTTOM_LEFT:
+ *x = ax - content_w - spec->content_offset.x; break;
+ case X11_ANCHOR_RIGHT: case X11_ANCHOR_TOP_RIGHT: case X11_ANCHOR_BOTTOM_RIGHT:
+ *x = ax - spec->content_offset.x; break;
+ default: *x = ax - content_w / 2 - spec->content_offset.x; break;
+ }
+ switch (gravity) {
+ case X11_ANCHOR_TOP: case X11_ANCHOR_TOP_LEFT: case X11_ANCHOR_TOP_RIGHT:
+ *y = ay - content_h - spec->content_offset.y; break;
+ case X11_ANCHOR_BOTTOM: case X11_ANCHOR_BOTTOM_LEFT: case X11_ANCHOR_BOTTOM_RIGHT:
+ *y = ay - spec->content_offset.y; break;
+ default: *y = ay - content_h / 2 - spec->content_offset.y; break;
+ }
+}
+
+static int popup_overflow(int pos, int extent, int low, int high)
+{
+ int64_t end = (int64_t)pos + extent;
+ int64_t overflow = (pos < low ? (int64_t)low - pos : 0) + (end > high ? end - high : 0);
+ return overflow > INT_MAX ? INT_MAX : (int)overflow;
+}
+
static void popup_calculate_position(struct x11_display *d,
struct x11_surface *parent,
- const struct yasl_popup_spec *spec,
- int *out_x, int *out_y)
+ const struct yasl_private_popup_spec *spec,
+ int *out_x, int *out_y,
+ struct yasl_private_vector2i *out_size)
{
int parent_rx = 0, parent_ry = 0;
if (d->native) {
@@ -1007,16 +1492,23 @@ static void popup_calculate_position(struct x11_display *d,
int parent_cx = parent->is_popup ? parent->content_offset.x : 0;
int parent_cy = parent->is_popup ? parent->content_offset.y : 0;
- int anchor_x = parent_rx + (spec->anchor.x - parent_cx);
- int anchor_y = parent_ry + (spec->anchor.y - parent_cy);
-
- int root_x, root_y;
- if (spec->beside) {
- root_x = anchor_x + spec->anchor.width - spec->content_offset.x;
- root_y = anchor_y - spec->content_offset.y;
+ struct yasl_private_vector2i size = spec->size;
+ int anchor_x, anchor_y, root_x, root_y;
+ if (spec->positioner_explicit) {
+ popup_anchor_point(spec, &anchor_x, &anchor_y);
+ anchor_x += parent_rx - parent_cx;
+ anchor_y += parent_ry - parent_cy;
+ popup_position_at(spec, anchor_x, anchor_y, spec->gravity, size, &root_x, &root_y);
} else {
- root_x = anchor_x - spec->content_offset.x;
- root_y = anchor_y + spec->anchor.height - spec->content_offset.y;
+ anchor_x = parent_rx + (spec->anchor.x - parent_cx);
+ anchor_y = parent_ry + (spec->anchor.y - parent_cy);
+ if (spec->beside) {
+ root_x = anchor_x + spec->anchor.width - spec->content_offset.x;
+ root_y = anchor_y - spec->content_offset.y;
+ } else {
+ root_x = anchor_x - spec->content_offset.x;
+ root_y = anchor_y + spec->anchor.height - spec->content_offset.y;
+ }
}
int mon_x = 0, mon_y = 0;
@@ -1043,29 +1535,69 @@ static void popup_calculate_position(struct x11_display *d,
}
#endif
- if (spec->beside) {
- if (root_x + spec->size.x > mon_x + mon_w) {
- int flipped_x = anchor_x - spec->size.x + spec->content_offset.x;
- if (flipped_x >= mon_x) root_x = flipped_x;
+ if (spec->positioner_explicit) {
+ if (spec->constraints & X11_CONSTRAINT_FLIP_X) {
+ int flip_x, flip_y;
+ /* Reflect the selected anchor edge across the anchor rectangle center. */
+ int anchor_origin_x = parent_rx - parent_cx + spec->anchor.x;
+ int flipped_anchor_x = 2 * anchor_origin_x + spec->anchor.width - anchor_x;
+ popup_position_at(spec, flipped_anchor_x, anchor_y, popup_flip_x(spec->gravity), size, &flip_x, &flip_y);
+ if (popup_overflow(flip_x, size.x, mon_x, mon_x + mon_w) <
+ popup_overflow(root_x, size.x, mon_x, mon_x + mon_w)) root_x = flip_x;
+ }
+ if (spec->constraints & X11_CONSTRAINT_FLIP_Y) {
+ int flip_x, flip_y;
+ int anchor_origin_y = parent_ry - parent_cy + spec->anchor.y;
+ int flipped_anchor_y = 2 * anchor_origin_y + spec->anchor.height - anchor_y;
+ popup_position_at(spec, anchor_x, flipped_anchor_y, popup_flip_y(spec->gravity), size, &flip_x, &flip_y);
+ if (popup_overflow(flip_y, size.y, mon_y, mon_y + mon_h) <
+ popup_overflow(root_y, size.y, mon_y, mon_y + mon_h)) root_y = flip_y;
+ }
+ if (spec->constraints & X11_CONSTRAINT_SLIDE_X) {
+ if (root_x < mon_x) root_x = mon_x;
+ if (root_x + size.x > mon_x + mon_w) root_x = mon_x + mon_w - size.x;
+ }
+ if (spec->constraints & X11_CONSTRAINT_SLIDE_Y) {
+ if (root_y < mon_y) root_y = mon_y;
+ if (root_y + size.y > mon_y + mon_h) root_y = mon_y + mon_h - size.y;
+ }
+ if ((spec->constraints & X11_CONSTRAINT_RESIZE_X) &&
+ popup_overflow(root_x, size.x, mon_x, mon_x + mon_w)) {
+ if (root_x >= mon_x + mon_w) root_x = mon_x + mon_w - 1;
+ if (root_x < mon_x) { size.x -= mon_x - root_x; root_x = mon_x; }
+ if (root_x + size.x > mon_x + mon_w) size.x = mon_x + mon_w - root_x;
+ if (size.x < 1) size.x = 1;
+ }
+ if ((spec->constraints & X11_CONSTRAINT_RESIZE_Y) &&
+ popup_overflow(root_y, size.y, mon_y, mon_y + mon_h)) {
+ if (root_y >= mon_y + mon_h) root_y = mon_y + mon_h - 1;
+ if (root_y < mon_y) { size.y -= mon_y - root_y; root_y = mon_y; }
+ if (root_y + size.y > mon_y + mon_h) size.y = mon_y + mon_h - root_y;
+ if (size.y < 1) size.y = 1;
}
} else {
- if (root_y + spec->size.y > mon_y + mon_h) {
- int flipped_y = anchor_y - spec->size.y + spec->content_offset.y;
+ if (spec->beside) {
+ if (root_x + size.x > mon_x + mon_w) {
+ int flipped_x = anchor_x - size.x + spec->content_offset.x;
+ if (flipped_x >= mon_x) root_x = flipped_x;
+ }
+ } else if (root_y + size.y > mon_y + mon_h) {
+ int flipped_y = anchor_y - size.y + spec->content_offset.y;
if (flipped_y >= mon_y) root_y = flipped_y;
}
+ if (root_x + size.x > mon_x + mon_w) root_x = mon_x + mon_w - size.x;
+ if (root_x < mon_x) root_x = mon_x;
+ if (root_y + size.y > mon_y + mon_h) root_y = mon_y + mon_h - size.y;
+ if (root_y < mon_y) root_y = mon_y;
}
- if (root_x + spec->size.x > mon_x + mon_w) root_x = mon_x + mon_w - spec->size.x;
- if (root_x < mon_x) root_x = mon_x;
- if (root_y + spec->size.y > mon_y + mon_h) root_y = mon_y + mon_h - spec->size.y;
- if (root_y < mon_y) root_y = mon_y;
-
*out_x = root_x;
*out_y = root_y;
+ if (out_size) *out_size = size;
}
static struct yasl_surface *surface_create_popup(struct yasl_surface *parent_base,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
struct x11_surface *parent = (struct x11_surface *)parent_base;
if (!parent || parent->destroyed || !popup_spec_valid(parent, spec))
@@ -1074,14 +1606,17 @@ static struct yasl_surface *surface_create_popup(struct yasl_surface *parent_bas
struct x11_surface *s = calloc(1, sizeof(*s));
if (!s) return NULL;
s->base.display = parent_base->display;
+ s->base.creation_flags = parent_base->creation_flags;
+ s->base.presenter = (parent_base->creation_flags & YASL_PRIVATE_SURFACE_CPU) ?
+ YASL_PRIVATE_PRESENTER_CPU : YASL_PRIVATE_PRESENTER_NONE;
s->parent = parent;
s->is_popup = true;
s->content_offset = spec->content_offset;
s->clock.refresh_ns = parent->clock.refresh_ns;
- if (!resize(s, spec->size)) { free(s); return NULL; }
-
int root_x = 0, root_y = 0;
- popup_calculate_position(d, parent, spec, &root_x, &root_y);
+ struct yasl_private_vector2i actual_size;
+ popup_calculate_position(d, parent, spec, &root_x, &root_y, &actual_size);
+ if (!resize(s, actual_size)) { free(s); return NULL; }
if (d->native) {
XSetWindowAttributes attrs = {
@@ -1089,7 +1624,7 @@ static struct yasl_surface *surface_create_popup(struct yasl_surface *parent_bas
.save_under = True,
};
s->window = XCreateWindow(d->native, RootWindow(d->native, d->screen),
- root_x, root_y, (unsigned)spec->size.x, (unsigned)spec->size.y,
+ root_x, root_y, (unsigned)actual_size.x, (unsigned)actual_size.y,
0, CopyFromParent, InputOutput, CopyFromParent,
CWOverrideRedirect | CWSaveUnder, &attrs);
if (!s->window) {
@@ -1098,7 +1633,7 @@ static struct yasl_surface *surface_create_popup(struct yasl_surface *parent_bas
}
s->base.native_handle = (void *)(uintptr_t)s->window;
s->base.size = s->size;
- s->base.scale_120 = YASL_SCALE_UNIT;
+ s->base.scale_120 = YASL_PRIVATE_SCALE_UNIT;
s->gc = XCreateGC(d->native, s->window, 0, NULL);
XSelectInput(d->native, s->window, ExposureMask | StructureNotifyMask |
FocusChangeMask | KeyPressMask | KeyReleaseMask | PropertyChangeMask |
@@ -1127,25 +1662,27 @@ static struct yasl_surface *surface_create_popup(struct yasl_surface *parent_bas
}
static bool surface_popup_reposition(struct yasl_surface *popup_base,
- const struct yasl_popup_spec *spec)
+ const struct yasl_private_popup_spec *spec)
{
struct x11_surface *s = (struct x11_surface *)popup_base;
if (!s || s->destroyed || !s->is_popup || !s->parent || s->parent->destroyed ||
!popup_spec_valid(s->parent, spec))
return false;
struct x11_display *d = (struct x11_display *)popup_base->display;
- if (spec->size.x != s->size.x || spec->size.y != s->size.y) {
- if (!resize(s, spec->size))
- return false;
- }
s->content_offset = spec->content_offset;
int root_x = 0, root_y = 0;
- popup_calculate_position(d, s->parent, spec, &root_x, &root_y);
+ struct yasl_private_vector2i actual_size;
+ popup_calculate_position(d, s->parent, spec, &root_x, &root_y, &actual_size);
+ bool changed_size = actual_size.x != s->size.x || actual_size.y != s->size.y;
+ if (changed_size && !resize(s, actual_size)) return false;
if (d->native && s->window) {
XMoveResizeWindow(d->native, s->window, root_x, root_y,
- (unsigned)spec->size.x, (unsigned)spec->size.y);
+ (unsigned)actual_size.x, (unsigned)actual_size.y);
XFlush(d->native);
}
+ if (changed_size)
+ yasl_private_surface_notify_configure(&s->base,
+ (struct yasl_private_geometry){actual_size, YASL_PRIVATE_SCALE_UNIT});
schedule_redraw(&s->base);
return true;
}
@@ -1157,22 +1694,22 @@ static void update_state(struct x11_surface *s)
int format;
unsigned long count, left;
unsigned char *data = NULL;
- uint32_t state = s->base.state & ~(YASL_STATE_FULLSCREEN | YASL_STATE_MAXIMIZED);
+ uint32_t state = s->base.state & ~(YASL_PRIVATE_STATE_FULLSCREEN | YASL_PRIVATE_STATE_MAXIMIZED);
if (XGetWindowProperty(d->native, s->window, d->net_state, 0, 64, False,
XA_ATOM, &actual, &format, &count, &left, &data) == Success && format == 32) {
Atom *atoms = (Atom *)data;
bool h = false, v = false;
for (unsigned long i = 0; i < count; i++) {
- if (atoms[i] == d->fullscreen) state |= YASL_STATE_FULLSCREEN;
+ if (atoms[i] == d->fullscreen) state |= YASL_PRIVATE_STATE_FULLSCREEN;
if (atoms[i] == d->maximized_h) h = true;
if (atoms[i] == d->maximized_v) v = true;
}
- if (h && v) state |= YASL_STATE_MAXIMIZED;
+ if (h && v) state |= YASL_PRIVATE_STATE_MAXIMIZED;
}
if (data) XFree(data);
if (state == s->base.state) return;
s->base.state = state;
- yasl_surface_notify_state(&s->base, state);
+ yasl_private_surface_notify_state(&s->base, state);
}
static void selection_request(struct x11_display *d, XSelectionRequestEvent *request)
@@ -1184,10 +1721,10 @@ static void selection_request(struct x11_display *d, XSelectionRequestEvent *req
.target = request->target, .time = request->time,
};
Atom property = request->property ? request->property : request->target;
- int slot = request->selection == XA_PRIMARY ? YASL_PRIMARY : YASL_CLIPBOARD;
+ int slot = request->selection == XA_PRIMARY ? YASL_PRIVATE_PRIMARY : YASL_PRIVATE_CLIPBOARD;
const char *text = d->selection[slot];
size_t latin1_len = 0;
- char *latin1 = text ? yasl_utf8_to_latin1(text, &latin1_len) : NULL;
+ char *latin1 = text ? yasl_private_utf8_to_latin1(text, &latin1_len) : NULL;
if (text && request->target == d->targets) {
Atom targets[] = {d->targets, d->utf8, XA_STRING};
XChangeProperty(d->native, request->requestor, property, XA_ATOM, 32,
@@ -1267,7 +1804,7 @@ static void xdnd_selection_notify(struct x11_display *d, XSelectionEvent *event)
size_t out_len = 0;
char *parsed = parse_file_uris((const char *)data, count, &out_len);
if (parsed && out_len > 0) {
- push(s, (struct yasl_event){.type = YASL_EVENT_DROP}, parsed, out_len);
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_DROP}, parsed, out_len);
free(parsed);
success = true;
}
@@ -1304,20 +1841,20 @@ static void selection_notify(struct x11_display *d, XSelectionEvent *event)
/* Surface destruction detached this accepted request. The reply means
* the owner has finished writing the initial property; retire safely. */
*p = r->next;
- if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
+ if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
XDestroyWindow(d->native, r->window);
free(r);
return;
}
if (event->property == None) {
*p = r->next;
- if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
- enum yasl_transfer_status status =
+ if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
+ enum yasl_private_transfer_status status =
XGetSelectionOwner(d->native, r->selection) == None
- ? YASL_TRANSFER_UNAVAILABLE : YASL_TRANSFER_FAILED;
+ ? YASL_PRIVATE_TRANSFER_UNAVAILABLE : YASL_PRIVATE_TRANSFER_FAILED;
XDestroyWindow(d->native, r->window);
if (s && !s->destroyed)
- yasl_surface_complete_paste(&s->base, r->id, status, NULL, 0);
+ yasl_private_surface_complete_paste(&s->base, r->id, status, NULL, 0);
free(r);
return;
}
@@ -1333,14 +1870,14 @@ static void selection_notify(struct x11_display *d, XSelectionEvent *event)
&probe_count, &probe_left, &probe_data);
if (probe_data) XFree(probe_data);
if (probe_result == Success && probe_type == d->incr) {
- yasl_surface_complete_paste(&s->base, r->id,
- YASL_TRANSFER_FAILED, NULL, 0);
+ yasl_private_surface_complete_paste(&s->base, r->id,
+ YASL_PRIVATE_TRANSFER_FAILED, NULL, 0);
r->target = NULL;
r->id = 0;
return;
}
*p = r->next;
- if (r->timeout) yasl_loop_del_timer(d->loop, r->timeout);
+ if (r->timeout) yasl_private_loop_del_timer(d->loop, r->timeout);
Atom actual = None;
int format = 0;
unsigned long count = 0, left = 0;
@@ -1389,17 +1926,17 @@ static void selection_notify(struct x11_display *d, XSelectionEvent *event)
}
if (complete && actual == XA_STRING) {
size_t utf8_len;
- char *utf8 = yasl_utf8_from_latin1(buf, total, &utf8_len);
+ char *utf8 = yasl_private_utf8_from_latin1(buf, total, &utf8_len);
free(buf);
buf = utf8;
if (buf) total = utf8_len;
}
- enum yasl_transfer_status status = YASL_TRANSFER_FAILED;
- if (complete && buf && yasl_utf8_validate(buf, total))
- status = YASL_TRANSFER_OK;
- yasl_surface_complete_paste(&s->base, r->id, status,
- status == YASL_TRANSFER_OK ? buf : NULL,
- status == YASL_TRANSFER_OK ? total : 0);
+ enum yasl_private_transfer_status status = YASL_PRIVATE_TRANSFER_FAILED;
+ if (complete && buf && yasl_private_utf8_validate(buf, total))
+ status = YASL_PRIVATE_TRANSFER_OK;
+ yasl_private_surface_complete_paste(&s->base, r->id, status,
+ status == YASL_PRIVATE_TRANSFER_OK ? buf : NULL,
+ status == YASL_PRIVATE_TRANSFER_OK ? total : 0);
free(buf);
XDestroyWindow(d->native, r->window);
free(r);
@@ -1413,7 +1950,7 @@ static void refresh_keyboard(struct x11_display *d)
if (!keyboard) return;
if (keyboard->names && keyboard->names->keys) {
for (unsigned code = keyboard->min_key_code; code <= keyboard->max_key_code; code++)
- d->keys[code] = yasl_key_from_xkb_name(keyboard->names->keys[code].name);
+ d->keys[code] = yasl_private_key_from_xkb_name(keyboard->names->keys[code].name);
}
XkbFreeKeyboard(keyboard, XkbAllComponentsMask, True);
}
@@ -1460,18 +1997,18 @@ static void key_event(struct x11_surface *s, XKeyEvent *key, bool repeat)
}
}
uint32_t cp = xkb_keysym_to_utf32((xkb_keysym_t)base);
- push(s, (struct yasl_event){
- .type = YASL_EVENT_KEY,
+ push(s, (struct yasl_private_event){
+ .type = YASL_PRIVATE_EVENT_KEY,
.key = {.key = key->keycode < 256 ? d->keys[key->keycode] : YASL_KEY_UNKNOWN,
- .codepoint = yasl_key_label(cp), .native_code = key->keycode,
- .shifted = yasl_key_label(xkb_keysym_to_utf32((xkb_keysym_t)shifted)),
+ .codepoint = yasl_private_key_label(cp), .native_code = key->keycode,
+ .shifted = yasl_private_key_label(xkb_keysym_to_utf32((xkb_keysym_t)shifted)),
.mods = d->mods,
.action = key->type == KeyRelease ? YASL_KEY_RELEASE :
repeat ? YASL_KEY_REPEAT : YASL_KEY_PRESS},
}, NULL, 0);
if (len > 0 && text && (unsigned char)text[0] >= 0x20 && text[0] != 0x7f &&
- !(d->mods & (YASL_MOD_CTRL | YASL_MOD_SUPER | YASL_MOD_ALT)))
- push(s, (struct yasl_event){.type = YASL_EVENT_TEXT}, text, (size_t)len);
+ !(d->mods & (YASL_PRIVATE_MOD_CTRL | YASL_PRIVATE_MOD_SUPER | YASL_PRIVATE_MOD_ALT)))
+ push(s, (struct yasl_private_event){.type = YASL_PRIVATE_EVENT_TEXT}, text, (size_t)len);
if (text != local) free(text);
}
@@ -1480,7 +2017,7 @@ static void handle_client_message(struct x11_display *d, struct x11_surface *s,
{
if (ev->message_type == d->protocols &&
(Atom)ev->data.l[0] == d->delete_window) {
- yasl_surface_notify_close(&s->base);
+ yasl_private_surface_notify_close(&s->base);
} else if (ev->message_type == d->xdnd_enter) {
Window source = (Window)ev->data.l[0];
int version = (int)((unsigned long)ev->data.l[1] >> 24);
@@ -1521,19 +2058,19 @@ static void handle_client_message(struct x11_display *d, struct x11_surface *s,
XTranslateCoordinates(d->native, RootWindow(d->native, d->screen), target,
rx, ry, &wx, &wy, &child);
}
- struct yasl_vector2i pos = {wx, wy};
+ struct yasl_private_vector2i pos = {wx, wy};
if (d->xdnd.surface && d->xdnd.surface != s) {
struct x11_surface *old = d->xdnd.surface;
- struct yasl_vector2i old_pos = d->xdnd.pos;
+ struct yasl_private_vector2i old_pos = d->xdnd.pos;
d->xdnd.surface = NULL;
if (d->xdnd.accepts && !old->destroyed)
- yasl_surface_notify_drop(&old->base, YASL_DROP_LEAVE, old_pos);
+ yasl_private_surface_notify_drop(&old->base, YASL_PRIVATE_DROP_LEAVE, old_pos);
}
d->xdnd.surface = s;
d->xdnd.pos = pos;
d->xdnd.time = t;
if (d->xdnd.accepts && !s->destroyed)
- yasl_surface_notify_drop(&s->base, YASL_DROP_OVER, pos);
+ yasl_private_surface_notify_drop(&s->base, YASL_PRIVATE_DROP_OVER, pos);
if (d->native) {
XEvent reply = {0};
@@ -1556,7 +2093,7 @@ static void handle_client_message(struct x11_display *d, struct x11_surface *s,
} else if (ev->message_type == d->xdnd_leave) {
if (d->xdnd.surface == s) {
if (d->xdnd.accepts && !s->destroyed)
- yasl_surface_notify_drop(&s->base, YASL_DROP_LEAVE, d->xdnd.pos);
+ yasl_private_surface_notify_drop(&s->base, YASL_PRIVATE_DROP_LEAVE, d->xdnd.pos);
}
d->xdnd = (typeof(d->xdnd)){0};
} else if (ev->message_type == d->xdnd_drop) {
@@ -1566,7 +2103,7 @@ static void handle_client_message(struct x11_display *d, struct x11_surface *s,
bool was_accepting = d->xdnd.accepts && d->xdnd.has_uri_list && (d->xdnd.source == source);
if (d->xdnd.surface == s) {
if (was_accepting && !s->destroyed)
- yasl_surface_notify_drop(&s->base, YASL_DROP_LEAVE, d->xdnd.pos);
+ yasl_private_surface_notify_drop(&s->base, YASL_PRIVATE_DROP_LEAVE, d->xdnd.pos);
}
if (was_accepting && !s->destroyed) {
d->pending_drop.active = true;
@@ -1593,7 +2130,7 @@ static void handle_client_message(struct x11_display *d, struct x11_surface *s,
}
}
-static void dispatch(struct yasl_display *base)
+static void dispatch(struct yasl_private_display *base)
{
struct x11_display *d = (struct x11_display *)base;
d->depth++;
@@ -1636,11 +2173,11 @@ static void dispatch(struct yasl_display *base)
switch (event.type) {
case Expose: s->want_draw = true; break;
case ConfigureNotify: {
- struct yasl_vector2i size = {event.xconfigure.width, event.xconfigure.height};
+ struct yasl_private_vector2i size = {event.xconfigure.width, event.xconfigure.height};
if (size.x == s->size.x && size.y == s->size.y) break;
if (resize(s, size))
- yasl_surface_notify_configure(&s->base,
- (struct yasl_geometry){size, YASL_SCALE_UNIT});
+ yasl_private_surface_notify_configure(&s->base,
+ (struct yasl_private_geometry){size, YASL_PRIVATE_SCALE_UNIT});
break;
}
case ClientMessage:
@@ -1648,12 +2185,16 @@ static void dispatch(struct yasl_display *base)
break;
case FocusIn: case FocusOut: {
bool focused = event.type == FocusIn;
- if (s->ic) { if (focused) XSetICFocus(s->ic); else XUnsetICFocus(s->ic); }
- if (focused) s->base.state |= YASL_STATE_ACTIVATED;
- else s->base.state &= ~YASL_STATE_ACTIVATED;
- push(s, (struct yasl_event){
- .type = YASL_EVENT_FOCUS, .focus.focused = focused}, NULL, 0);
- yasl_surface_notify_state(&s->base, s->base.state);
+ s->focused = focused;
+ if (s->ic) {
+ if (focused && s->base.text_input_active) XSetICFocus(s->ic);
+ else XUnsetICFocus(s->ic);
+ }
+ if (focused) s->base.state |= YASL_PRIVATE_STATE_ACTIVATED;
+ else s->base.state &= ~YASL_PRIVATE_STATE_ACTIVATED;
+ push(s, (struct yasl_private_event){
+ .type = YASL_PRIVATE_EVENT_FOCUS, .focus.focused = focused}, NULL, 0);
+ yasl_private_surface_notify_state(&s->base, s->base.state);
break;
}
case PropertyNotify:
@@ -1674,13 +2215,13 @@ static void dispatch(struct yasl_display *base)
break;
}
case MotionNotify: case LeaveNotify: case EnterNotify: case ButtonPress: case ButtonRelease: {
- struct yasl_event ev = {
- .pointer = {.device = YASL_PTR_DEV_MOUSE},
+ struct yasl_private_event ev = {
+ .pointer = {.device = YASL_PRIVATE_PTR_DEV_MOUSE},
};
unsigned state;
if (event.type == MotionNotify) {
- ev.pointer.pos = (struct yasl_vector2i){event.xmotion.x, event.xmotion.y};
- ev.type = YASL_EVENT_POINTER_MOTION;
+ ev.pointer.pos = (struct yasl_private_vector2i){event.xmotion.x, event.xmotion.y};
+ ev.type = YASL_PRIVATE_EVENT_POINTER_MOTION;
state = event.xmotion.state;
if (d->drag.active) {
if (d->drag.carried)
@@ -1689,38 +2230,41 @@ static void dispatch(struct yasl_display *base)
XMoveWindow(d->native, d->drag.icon_window,
event.xmotion.x_root - d->drag.hotspot.x,
event.xmotion.y_root - d->drag.hotspot.y);
- struct yasl_vector2i hpos = ev.pointer.pos;
+ struct yasl_private_vector2i hpos = ev.pointer.pos;
struct x11_surface *hsurf = d->native ?
surface_at_root_pos(d, event.xmotion.x_root, event.xmotion.y_root, &hpos) : s;
drag_set_hover(d, hsurf, hpos);
}
} else if (event.type == EnterNotify) {
- ev.pointer.pos = (struct yasl_vector2i){event.xcrossing.x, event.xcrossing.y};
- ev.type = YASL_EVENT_POINTER_MOTION;
+ ev.pointer.pos = (struct yasl_private_vector2i){event.xcrossing.x, event.xcrossing.y};
+ ev.type = YASL_PRIVATE_EVENT_POINTER_MOTION;
state = event.xcrossing.state;
if (d->drag.active) {
- struct yasl_vector2i hpos = ev.pointer.pos;
+ struct yasl_private_vector2i hpos = ev.pointer.pos;
struct x11_surface *hsurf = d->native ?
surface_at_root_pos(d, event.xcrossing.x_root, event.xcrossing.y_root, &hpos) : s;
drag_set_hover(d, hsurf, hpos);
}
} else if (event.type == LeaveNotify) {
- ev.pointer.pos = (struct yasl_vector2i){event.xcrossing.x, event.xcrossing.y};
- ev.type = YASL_EVENT_POINTER_LEAVE;
+ ev.pointer.pos = (struct yasl_private_vector2i){event.xcrossing.x, event.xcrossing.y};
+ ev.type = YASL_PRIVATE_EVENT_POINTER_LEAVE;
state = event.xcrossing.state;
if (d->drag.active)
drag_leave_hover(d, s, ev.pointer.pos);
} else {
- ev.pointer.pos = (struct yasl_vector2i){event.xbutton.x, event.xbutton.y};
+ ev.pointer.pos = (struct yasl_private_vector2i){event.xbutton.x, event.xbutton.y};
state = event.xbutton.state;
unsigned button = event.xbutton.button;
if (button >= 4 && button <= 7) {
if (event.type == ButtonRelease) break;
- ev.type = YASL_EVENT_POINTER_SCROLL;
+ ev.type = YASL_PRIVATE_EVENT_POINTER_SCROLL;
if (button <= 5) ev.pointer.scroll.y = button == 4 ? -1 : 1;
else ev.pointer.scroll.x = button == 6 ? -1 : 1;
+ ev.pointer.scroll_valid = 1u;
+ ev.pointer.scroll_source = 1u;
+ ev.pointer.scroll_phase = 2u;
} else {
- ev.type = event.type == ButtonPress ? YASL_EVENT_POINTER_DOWN : YASL_EVENT_POINTER_UP;
+ ev.type = event.type == ButtonPress ? YASL_PRIVATE_EVENT_POINTER_DOWN : YASL_PRIVATE_EVENT_POINTER_UP;
ev.pointer.button = pointer_button(button);
if (event.type == ButtonRelease && d->drag.active)
drag_drop_hover(d);
@@ -1735,13 +2279,13 @@ static void dispatch(struct yasl_display *base)
leave(d);
}
-static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb,
- const struct yasl_damage_list *damage)
+static bool present(struct yasl_surface *base, const struct yasl_private_framebuffer *fb,
+ const struct yasl_private_damage_list *damage)
{
struct x11_surface *s = (struct x11_surface *)base;
if (s->destroyed || !s->drawing || s->presented || !fb || !damage ||
fb->pixels != s->pixels || fb->size.x != s->size.x || fb->size.y != s->size.y ||
- damage->n < -1 || damage->n > YASL_DAMAGE_MAX) return false;
+ damage->n < -1 || damage->n > YASL_PRIVATE_DAMAGE_MAX) return false;
struct x11_display *d = (struct x11_display *)base->display;
XImage *im = s->image;
if (s->shm_active) {
@@ -1749,7 +2293,7 @@ static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb
XShmPutImage(d->native, s->window, s->gc, im, 0, 0, 0, 0,
(unsigned)s->size.x, (unsigned)s->size.y, False);
else for (int i = 0; i < damage->n; i++) {
- struct yasl_rect2i r = damage->rects[i];
+ struct yasl_private_rect2i r = damage->rects[i];
int64_t right = (int64_t)r.x + r.width, bottom = (int64_t)r.y + r.height;
int x = r.x > 0 ? r.x : 0, y = r.y > 0 ? r.y : 0;
int w = (int)(right < s->size.x ? right : s->size.x) - x;
@@ -1758,7 +2302,7 @@ static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb
XShmPutImage(d->native, s->window, s->gc, im, x, y, x, y, (unsigned)w, (unsigned)h, False);
}
s->presented = true;
- yasl_clock_presented(&s->clock, yasl_loop_now_ns(), false);
+ yasl_private_clock_presented(&s->clock, yasl_private_loop_now_ns(), false);
return true;
}
bool direct = im->bits_per_pixel == 32 && im->red_mask == 0xff0000 &&
@@ -1769,7 +2313,7 @@ static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb
y_start = s->size.y; y_end = 0;
x_start = s->size.x; x_end = 0;
for (int i = 0; i < damage->n; i++) {
- struct yasl_rect2i r = damage->rects[i];
+ struct yasl_private_rect2i r = damage->rects[i];
int y0 = r.y > 0 ? r.y : 0;
int y1 = (r.y + r.height < s->size.y) ? r.y + r.height : s->size.y;
int x0 = r.x > 0 ? r.x : 0;
@@ -1798,7 +2342,7 @@ static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb
XPutImage(d->native, s->window, s->gc, im, 0, 0, 0, 0,
(unsigned)s->size.x, (unsigned)s->size.y);
else for (int i = 0; i < damage->n; i++) {
- struct yasl_rect2i r = damage->rects[i];
+ struct yasl_private_rect2i r = damage->rects[i];
int64_t right = (int64_t)r.x + r.width, bottom = (int64_t)r.y + r.height;
int x = r.x > 0 ? r.x : 0, y = r.y > 0 ? r.y : 0;
int w = (int)(right < s->size.x ? right : s->size.x) - x;
@@ -1807,27 +2351,33 @@ static bool present(struct yasl_surface *base, const struct yasl_framebuffer *fb
XPutImage(d->native, s->window, s->gc, im, x, y, x, y, (unsigned)w, (unsigned)h);
}
s->presented = true;
- yasl_clock_presented(&s->clock, yasl_loop_now_ns(), false);
+ yasl_private_clock_presented(&s->clock, yasl_private_loop_now_ns(), false);
return true;
}
-static void flush(struct yasl_display *base)
+static void flush(struct yasl_private_display *base)
{
struct x11_display *d = (struct x11_display *)base;
d->depth++;
for (struct x11_surface *s = d->surfaces, *next; s; s = next) {
next = s->next;
- if (s->destroyed || !s->want_draw || !s->cbs || !s->cbs->draw || s->drawing) continue;
+ if (s->destroyed || !s->want_draw || s->drawing) continue;
+ if (s->base.presenter != YASL_PRIVATE_PRESENTER_CPU) {
+ s->want_draw = false;
+ yasl_private_surface_notify_refresh(&s->base);
+ continue;
+ }
+ if (!s->cbs || !s->cbs->draw) continue;
s->want_draw = false;
s->drawing = true;
s->presented = false;
- s->damage = (struct yasl_damage_list){0};
- s->frame = (struct yasl_frame){
+ s->damage = (struct yasl_private_damage_list){0};
+ s->frame = (struct yasl_private_frame){
.surface = &s->base,
- .target = {.generation = yasl_frame_begin(&s->base),
+ .target = {.generation = yasl_private_frame_begin(&s->base),
.pixels = s->pixels, .size = s->size},
};
- yasl_surface_draw(&s->base, &s->frame);
+ yasl_private_surface_draw(&s->base, &s->frame);
if (!s->destroyed) s->drawing = false;
}
XFlush(d->native);
@@ -1837,11 +2387,11 @@ static void flush(struct yasl_display *base)
static int ready(int fd, short events, void *ud)
{
(void)fd;
- struct yasl_display *base = ud;
+ struct yasl_private_display *base = ud;
struct x11_display *d = (struct x11_display *)base;
if ((events & (POLLERR | POLLHUP)) && !d->lost) {
d->lost = true;
- yasl_display_notify_event(base, YASL_EVENT_DISPLAY_LOST);
+ yasl_private_display_notify_event(base, YASL_PRIVATE_EVENT_DISPLAY_LOST);
return 0;
}
if ((events & POLLIN) && !d->lost) {
@@ -1851,7 +2401,7 @@ static int ready(int fd, short events, void *ud)
return 0;
}
-static int dispatch_timeout(struct yasl_display *base, int timeout_ms)
+static int dispatch_timeout(struct yasl_private_display *base, int timeout_ms)
{
struct x11_display *d = (struct x11_display *)base;
if (unlikely(!d || !d->native || d->lost)) return -1;
@@ -1867,26 +2417,26 @@ static int dispatch_timeout(struct yasl_display *base, int timeout_ms)
if (XEventsQueued(d->native, QueuedAlready) > 0)
timeout_ms = 0;
if (!XPending(d->native) && timeout_ms != 0) {
- yasl_loop_step(d->loop, timeout_ms);
+ yasl_private_loop_step(d->loop, timeout_ms);
dispatch(base);
} else {
- yasl_loop_step(d->loop, 0);
+ yasl_private_loop_step(d->loop, 0);
dispatch(base);
}
}
return 0;
}
-static struct yasl_display *display_open(struct yasl_loop *loop,
- const struct yasl_display_spec *spec)
+static struct yasl_private_display *display_open(struct yasl_private_loop *loop,
+ const struct yasl_private_display_spec *spec)
{
struct x11_display *d = calloc(1, sizeof(*d));
if (!d) return NULL;
- d->base.ops = &yasl_x11_backend;
- d->base.callbacks = spec && spec->cbs ? *spec->cbs : (struct yasl_display_cbs){0};
+ d->base.ops = &yasl_private_x11_backend;
+ d->base.callbacks = spec && spec->cbs ? *spec->cbs : (struct yasl_private_display_cbs){0};
d->native = XOpenDisplay(NULL);
if (!d->native) { free(d); errno = ENODEV; return NULL; }
- XSetErrorHandler(yasl_x11_error_handler);
+ XSetErrorHandler(yasl_private_x11_error_handler);
d->base.native_handle = d->native;
d->screen = DefaultScreen(d->native);
d->has_shm = XShmQueryExtension(d->native);
@@ -1908,8 +2458,15 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
d->abs_pressure = XInternAtom(d->native, "Abs Pressure", False);
d->abs_tilt_x = XInternAtom(d->native, "Abs Tilt X", False);
d->abs_tilt_y = XInternAtom(d->native, "Abs Tilt Y", False);
+ d->abs_rotation = XInternAtom(d->native, "Abs Rotation", False);
+ d->abs_distance = XInternAtom(d->native, "Abs Distance", False);
+ d->abs_tangential = XInternAtom(d->native, "Abs TPressure", False);
+ d->abs_wheel = XInternAtom(d->native, "Abs Wheel", False);
d->tool_type = XInternAtom(d->native, "Wacom Tool Type", False);
d->eraser = XInternAtom(d->native, "ERASER", False);
+ d->brush = XInternAtom(d->native, "BRUSH", False);
+ d->airbrush = XInternAtom(d->native, "AIRBRUSH", False);
+ d->pencil = XInternAtom(d->native, "PENCIL", False);
unsigned char bits[XIMaskLen(XI_LASTEVENT)] = {0};
XISetMask(bits, XI_HierarchyChanged);
XISetMask(bits, XI_DeviceChanged);
@@ -1917,7 +2474,7 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
XISelectEvents(d->native, RootWindow(d->native, d->screen), &mask, 1);
}
if (!loop) {
- d->loop = yasl_loop_create();
+ d->loop = yasl_private_loop_create();
d->owns_loop = true;
} else {
d->loop = loop;
@@ -1926,7 +2483,7 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
d->app_id = strdup(spec && spec->app_id ? spec->app_id : "YASL");
d->base.app_id = d->app_id;
if (!d->loop || !d->app_id) {
- if (d->owns_loop) yasl_loop_destroy(d->loop);
+ if (d->owns_loop) yasl_private_loop_destroy(d->loop);
free(d->app_id);
XCloseDisplay(d->native);
free(d);
@@ -1941,10 +2498,11 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
ATOM(utf8, "UTF8_STRING");
ATOM(clipboard, "CLIPBOARD");
ATOM(targets, "TARGETS");
- ATOM(paste_property, "YASL_SELECTION");
+ ATOM(paste_property, "YASL_PRIVATE_SELECTION");
ATOM(incr, "INCR");
ATOM(net_name, "_NET_WM_NAME");
ATOM(net_state, "_NET_WM_STATE");
+ ATOM(motif_hints, "_MOTIF_WM_HINTS");
ATOM(fullscreen, "_NET_WM_STATE_FULLSCREEN");
ATOM(maximized_h, "_NET_WM_STATE_MAXIMIZED_HORZ");
ATOM(maximized_v, "_NET_WM_STATE_MAXIMIZED_VERT");
@@ -1961,13 +2519,13 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
ATOM(uri_list, "text/uri-list");
#undef ATOM
if (d->loop) {
- d->watch = yasl_loop_add_fd(d->loop, ConnectionNumber(d->native), POLLIN, ready, &d->base);
+ d->watch = yasl_private_loop_add_fd(d->loop, ConnectionNumber(d->native), POLLIN, ready, &d->base);
if (d->watch < 0) {
if (d->im) XCloseIM(d->im);
XDestroyWindow(d->native, d->selection_window);
XCloseDisplay(d->native);
free(d->app_id);
- if (d->owns_loop) yasl_loop_destroy(d->loop);
+ if (d->owns_loop) yasl_private_loop_destroy(d->loop);
free(d);
return NULL;
}
@@ -1975,21 +2533,24 @@ static struct yasl_display *display_open(struct yasl_loop *loop,
return &d->base;
}
-static void display_close(struct yasl_display *base)
+static void display_close(struct yasl_private_display *base)
{
struct x11_display *d = (struct x11_display *)base;
assert(!d->surfaces && "destroy every surface before its display");
drag_cancel(base);
cancel_pastes(d, NULL);
d->pending_drop.active = false;
- if (d->loop && d->watch > 0) yasl_loop_del_fd(d->loop, d->watch);
+ if (d->loop && d->watch > 0) yasl_private_loop_del_fd(d->loop, d->watch);
if (d->owns_loop && d->loop) {
- yasl_loop_destroy(d->loop);
+ yasl_private_loop_destroy(d->loop);
d->loop = NULL;
d->base.loop = NULL;
}
if (d->im) XCloseIM(d->im);
clear_pointers(d);
+#if YASL_HAS_EGL
+ if (d->egl_ready) eglTerminate(d->egl);
+#endif
for (size_t i = 0; i < sizeof(d->cursors) / sizeof(d->cursors[0]); i++) {
if (d->cursors[i]) {
XFreeCursor(d->native, d->cursors[i]);
@@ -2004,16 +2565,16 @@ static void display_close(struct yasl_display *base)
free(d);
}
-static uint32_t caps(const struct yasl_display *d)
+static uint32_t caps(const struct yasl_private_display *d)
{
- return YASL_CAP_POPUPS | YASL_CAP_DRAG | YASL_CAP_DRAG_CARRY | YASL_CAP_PLACE_WINDOW |
- YASL_CAP_PRIMARY_SELECTION | YASL_CAP_CSD |
- (((const struct x11_display *)d)->xi2 ? YASL_CAP_TABLET : 0);
+ return YASL_PRIVATE_CAP_POPUPS | YASL_PRIVATE_CAP_DRAG | YASL_PRIVATE_CAP_DRAG_CARRY | YASL_PRIVATE_CAP_PLACE_WINDOW |
+ YASL_PRIVATE_CAP_PRIMARY_SELECTION | YASL_PRIVATE_CAP_CSD | YASL_PRIVATE_CAP_NATIVE_GRAPHICS |
+ (((const struct x11_display *)d)->xi2 ? YASL_PRIVATE_CAP_TABLET : 0);
}
-static bool copy_text(struct yasl_display *base, enum yasl_selection sel, const char *text)
+static bool copy_text(struct yasl_private_display *base, enum yasl_private_selection sel, const char *text)
{
- if (!text || (sel != YASL_CLIPBOARD && sel != YASL_PRIMARY)) {
+ if (!text || (sel != YASL_PRIVATE_CLIPBOARD && sel != YASL_PRIVATE_PRIMARY)) {
errno = EINVAL;
return false;
}
@@ -2022,39 +2583,39 @@ static bool copy_text(struct yasl_display *base, enum yasl_selection sel, const
if (!value) { errno = ENOMEM; return false; }
free(d->selection[sel]);
d->selection[sel] = value;
- XSetSelectionOwner(d->native, sel == YASL_PRIMARY ? XA_PRIMARY : d->clipboard,
+ XSetSelectionOwner(d->native, sel == YASL_PRIVATE_PRIMARY ? XA_PRIMARY : d->clipboard,
d->selection_window, CurrentTime);
XFlush(d->native);
return true;
}
-static void copy(struct yasl_display *base, enum yasl_selection sel, const char *text)
+static void copy(struct yasl_private_display *base, enum yasl_private_selection sel, const char *text)
{
(void)copy_text(base, sel, text);
}
-static bool request_paste(struct yasl_display *base, enum yasl_selection sel,
+static bool request_paste(struct yasl_private_display *base, enum yasl_private_selection sel,
struct yasl_surface *target, uint64_t id)
{
- if (!target || (sel != YASL_CLIPBOARD && sel != YASL_PRIMARY)) {
+ if (!target || (sel != YASL_PRIVATE_CLIPBOARD && sel != YASL_PRIVATE_PRIMARY)) {
errno = EINVAL;
return false;
}
struct x11_display *d = (struct x11_display *)base;
struct x11_surface *s = (struct x11_surface *)target;
if (s->destroyed || target->display != base) { errno = EINVAL; return false; }
- Atom selection = sel == YASL_PRIMARY ? XA_PRIMARY : d->clipboard;
+ Atom selection = sel == YASL_PRIVATE_PRIMARY ? XA_PRIMARY : d->clipboard;
Window owner = XGetSelectionOwner(d->native, selection);
if (owner == None) {
- yasl_surface_complete_paste(target, id, YASL_TRANSFER_UNAVAILABLE, NULL, 0);
+ yasl_private_surface_complete_paste(target, id, YASL_PRIVATE_TRANSFER_UNAVAILABLE, NULL, 0);
return true;
}
if (owner == d->selection_window) {
const char *text = d->selection[sel];
if (text)
- yasl_surface_complete_paste(target, id, YASL_TRANSFER_OK, text, strlen(text));
+ yasl_private_surface_complete_paste(target, id, YASL_PRIVATE_TRANSFER_OK, text, strlen(text));
else
- yasl_surface_complete_paste(target, id, YASL_TRANSFER_UNAVAILABLE, NULL, 0);
+ yasl_private_surface_complete_paste(target, id, YASL_PRIVATE_TRANSFER_UNAVAILABLE, NULL, 0);
return true;
} else {
struct paste_request *r = calloc(1, sizeof(*r));
@@ -2067,7 +2628,7 @@ static bool request_paste(struct yasl_display *base, enum yasl_selection sel,
r->selection = selection;
r->id = id;
errno = 0;
- r->timeout = yasl_loop_add_timer(d->loop, PASTE_TIMEOUT_NS,
+ r->timeout = yasl_private_loop_add_timer(d->loop, PASTE_TIMEOUT_NS,
paste_timeout, r);
if (!r->timeout) {
XDestroyWindow(d->native, r->window);
@@ -2084,17 +2645,17 @@ static bool request_paste(struct yasl_display *base, enum yasl_selection sel,
}
}
-static void paste(struct yasl_display *base, enum yasl_selection sel,
+static void paste(struct yasl_private_display *base, enum yasl_private_selection sel,
struct yasl_surface *target)
{
(void)request_paste(base, sel, target, 0);
}
-static bool input_poll(struct yasl_surface *base, struct yasl_event *event)
+static bool input_poll(struct yasl_surface *base, struct yasl_private_event *event)
{
struct x11_surface *s = (struct x11_surface *)base;
if (s->destroyed) return false;
- if (base->display->events) return yasl_events_poll_surface(base, event);
+ if (base->display->events) return yasl_private_events_poll_surface(base, event);
return input_queue_pop(&s->input, event);
}
@@ -2110,47 +2671,47 @@ static void schedule_redraw(struct yasl_surface *base)
s->want_draw = true;
struct x11_display *d = (struct x11_display *)base->display;
if (d && d->loop)
- yasl_loop_kick(d->loop);
+ yasl_private_loop_kick(d->loop);
}
}
-static struct yasl_display *surface_display(const struct yasl_surface *s) { return s->display; }
-static struct yasl_geometry geometry(const struct yasl_surface *s)
+static struct yasl_private_display *surface_display(const struct yasl_surface *s) { return s->display; }
+static struct yasl_private_geometry geometry(const struct yasl_surface *s)
{
- return (struct yasl_geometry){((const struct x11_surface *)s)->size, YASL_SCALE_UNIT};
+ return (struct yasl_private_geometry){((const struct x11_surface *)s)->size, YASL_PRIVATE_SCALE_UNIT};
}
-static int mods(const struct yasl_display *d) { return (int)((const struct x11_display *)d)->mods; }
-static void *native_display(struct yasl_display *d) { return ((struct x11_display *)d)->native; }
+static int mods(const struct yasl_private_display *d) { return (int)((const struct x11_display *)d)->mods; }
+static void *native_display(struct yasl_private_display *d) { return ((struct x11_display *)d)->native; }
static void *native_surface(struct yasl_surface *s) { return (void *)(uintptr_t)((struct x11_surface *)s)->window; }
-static struct yasl_timing timing(const struct yasl_surface *base)
+static struct yasl_private_timing timing(const struct yasl_surface *base)
{
const struct x11_surface *s = (const struct x11_surface *)base;
- struct yasl_timing t = {.refresh_ns = s->clock.refresh_ns,
+ struct yasl_private_timing t = {.refresh_ns = s->clock.refresh_ns,
.last_present_ns = s->clock.last_present_ns,
- .next_present_ns = yasl_clock_next_present_ns(&s->clock),
+ .next_present_ns = yasl_private_clock_next_present_ns(&s->clock),
.source = s->clock.source};
- yasl_clock_resize_stats(&s->clock, &t.resize);
+ yasl_private_clock_resize_stats(&s->clock, &t.resize);
return t;
}
static uint64_t frame_time(struct yasl_surface *s, uint64_t now)
{
- return yasl_clock_frame_timestamp_ns(&((struct x11_surface *)s)->clock, now);
+ return yasl_private_clock_frame_timestamp_ns(&((struct x11_surface *)s)->clock, now);
}
-static void cursor(struct yasl_surface *base, enum yasl_cursor cursor)
+static void cursor(struct yasl_surface *base, enum yasl_private_cursor cursor)
{
static const unsigned shapes[] = {XC_left_ptr, XC_xterm, XC_hand2, XC_crosshair,
XC_fleur, XC_bottom_right_corner, XC_bottom_left_corner,
XC_sb_h_double_arrow, XC_sb_v_double_arrow};
struct x11_surface *s = (struct x11_surface *)base;
- if (s->destroyed || (unsigned)cursor > YASL_CURSOR_HIDDEN) return;
+ if (s->destroyed || (unsigned)cursor > YASL_PRIVATE_CURSOR_HIDDEN) return;
struct x11_display *d = (struct x11_display *)base->display;
if (!d->native) return;
if (!d->cursors[cursor]) {
- if (cursor == YASL_CURSOR_HIDDEN) {
+ if (cursor == YASL_PRIVATE_CURSOR_HIDDEN) {
char bits[] = {0};
Pixmap pixmap = XCreateBitmapFromData(d->native, s->window, bits, 1, 1);
XColor color = {0};
@@ -2164,7 +2725,7 @@ static void cursor(struct yasl_surface *base, enum yasl_cursor cursor)
XDefineCursor(d->native, s->window, d->cursors[cursor]);
}
-static bool place(struct yasl_surface *base, struct yasl_vector2i at)
+static bool place(struct yasl_surface *base, struct yasl_private_vector2i at)
{
struct x11_surface *s = (struct x11_surface *)base;
struct x11_display *d = (struct x11_display *)base->display;
@@ -2227,7 +2788,7 @@ static bool xsettings_int(const unsigned char *p, size_t len, const char *name,
return false;
}
-static int double_click_ms(const struct yasl_display *base)
+static int double_click_ms(const struct yasl_private_display *base)
{
const struct x11_display *d = (const struct x11_display *)base;
if (d->native) {
@@ -2255,12 +2816,12 @@ static int double_click_ms(const struct yasl_display *base)
}
static bool read_pixels(struct yasl_surface *base, uint32_t *out, size_t cap,
- struct yasl_vector2i *size)
+ struct yasl_private_vector2i *size)
{
struct x11_surface *s = (struct x11_surface *)base;
/* presented stays set from the last draw until the next one starts. */
if (s->destroyed || s->drawing || !s->presented || !s->pixels) return false;
- return yasl_copy_frame(s->pixels, s->size, out, cap, size);
+ return yasl_private_copy_frame(s->pixels, s->size, out, cap, size);
}
static bool bell(struct yasl_surface *base)
@@ -2275,16 +2836,16 @@ static bool bell(struct yasl_surface *base)
return true;
}
-static void drag_end(struct x11_display *d, enum yasl_drag_end how)
+static void drag_end(struct x11_display *d, enum yasl_private_drag_end how)
{
if (!d || !d->drag.active) return;
- struct yasl_drag_listener l = d->drag.listener;
+ struct yasl_private_drag_listener l = d->drag.listener;
void *ud = d->drag.ud;
struct x11_surface *hover = d->drag.hover;
- struct yasl_vector2i hover_pos = d->drag.hover_pos;
+ struct yasl_private_vector2i hover_pos = d->drag.hover_pos;
d->drag.active = false;
- d->drag.listener = (struct yasl_drag_listener){0};
+ d->drag.listener = (struct yasl_private_drag_listener){0};
d->drag.hover = NULL;
d->drag.origin = NULL;
d->drag.carried = NULL;
@@ -2299,19 +2860,19 @@ static void drag_end(struct x11_display *d, enum yasl_drag_end how)
}
if (hover && !hover->destroyed) {
- if (how == YASL_DRAG_DROPPED)
- yasl_surface_notify_drag(&hover->base, YASL_DRAG_DROP, hover_pos);
+ if (how == YASL_PRIVATE_DRAG_DROPPED)
+ yasl_private_surface_notify_drag(&hover->base, YASL_PRIVATE_DRAG_DROP, hover_pos);
else
- yasl_surface_notify_drag(&hover->base, YASL_DRAG_LEAVE, hover_pos);
+ yasl_private_surface_notify_drag(&hover->base, YASL_PRIVATE_DRAG_LEAVE, hover_pos);
}
if (l.end)
l.end(ud, how);
}
-static bool drag_start(struct yasl_display *base, struct yasl_surface *origin,
- const struct yasl_drag_image *image,
- const struct yasl_drag_listener *l, void *ud)
+static bool drag_start(struct yasl_private_display *base, struct yasl_surface *origin,
+ const struct yasl_private_drag_image *image,
+ const struct yasl_private_drag_listener *l, void *ud)
{
struct x11_display *d = (struct x11_display *)base;
if (!d || !origin || d->drag.active || !l)
@@ -2383,12 +2944,12 @@ static bool drag_start(struct yasl_display *base, struct yasl_surface *origin,
return true;
}
-static void drag_cancel(struct yasl_display *base)
+static void drag_cancel(struct yasl_private_display *base)
{
- drag_end((struct x11_display *)base, YASL_DRAG_CANCELLED);
+ drag_end((struct x11_display *)base, YASL_PRIVATE_DRAG_CANCELLED);
}
-static bool drag_carry(struct yasl_surface *base, struct yasl_vector2i offset)
+static bool drag_carry(struct yasl_surface *base, struct yasl_private_vector2i offset)
{
struct x11_display *d = (struct x11_display *)base->display;
if (!d || !d->drag.active)
@@ -2420,7 +2981,7 @@ static bool interactive_move(struct yasl_surface *base)
return true;
}
-static bool interactive_resize(struct yasl_surface *base, enum yasl_resize_edge edge)
+static bool interactive_resize(struct yasl_surface *base, enum yasl_private_resize_edge edge)
{
struct x11_surface *s = (struct x11_surface *)base;
struct x11_display *d = (struct x11_display *)base->display;
@@ -2432,14 +2993,14 @@ static bool interactive_resize(struct yasl_surface *base, enum yasl_resize_edge
int dir;
switch (edge) {
- case YASL_EDGE_TOP_LEFT: dir = 0; break;
- case YASL_EDGE_TOP: dir = 1; break;
- case YASL_EDGE_TOP_RIGHT: dir = 2; break;
- case YASL_EDGE_RIGHT: dir = 3; break;
- case YASL_EDGE_BOTTOM_RIGHT: dir = 4; break;
- case YASL_EDGE_BOTTOM: dir = 5; break;
- case YASL_EDGE_BOTTOM_LEFT: dir = 6; break;
- case YASL_EDGE_LEFT: dir = 7; break;
+ case YASL_PRIVATE_EDGE_TOP_LEFT: dir = 0; break;
+ case YASL_PRIVATE_EDGE_TOP: dir = 1; break;
+ case YASL_PRIVATE_EDGE_TOP_RIGHT: dir = 2; break;
+ case YASL_PRIVATE_EDGE_RIGHT: dir = 3; break;
+ case YASL_PRIVATE_EDGE_BOTTOM_RIGHT: dir = 4; break;
+ case YASL_PRIVATE_EDGE_BOTTOM: dir = 5; break;
+ case YASL_PRIVATE_EDGE_BOTTOM_LEFT: dir = 6; break;
+ case YASL_PRIVATE_EDGE_LEFT: dir = 7; break;
default: return false;
}
@@ -2448,7 +3009,7 @@ static bool interactive_resize(struct yasl_surface *base, enum yasl_resize_edge
return true;
}
-static bool show_window_menu(struct yasl_surface *base, struct yasl_vector2i pos)
+static bool show_window_menu(struct yasl_surface *base, struct yasl_private_vector2i pos)
{
struct x11_surface *s = (struct x11_surface *)base;
struct x11_display *d = (struct x11_display *)base->display;
@@ -2458,7 +3019,18 @@ static bool show_window_menu(struct yasl_surface *base, struct yasl_vector2i pos
return true;
}
-static void set_ime_caret(struct yasl_surface *base, struct yasl_rect2i caret)
+static bool surface_update_text_input(struct yasl_surface *base)
+{
+ struct x11_surface *s = (struct x11_surface *)base;
+ if (!s || s->destroyed || !base->display) return false;
+ if (s->ic) {
+ if (s->focused && base->text_input_active) XSetICFocus(s->ic);
+ else XUnsetICFocus(s->ic);
+ }
+ return true;
+}
+
+static void set_ime_caret(struct yasl_surface *base, struct yasl_private_rect2i caret)
{
struct x11_surface *s = (struct x11_surface *)base;
if (!s) return;
@@ -2489,8 +3061,15 @@ static bool ime_preedit_cursor(const struct yasl_surface *base, int *begin, int
return true;
}
-const struct yasl_backend_ops yasl_x11_backend = {
- .type = YASL_BACKEND_X11,
+const struct yasl_private_backend_ops yasl_private_x11_backend = {
+#if YASL_HAS_EGL
+ .surface_create_gl = create_gl_surface,
+ .gl_make_current = gl_make_current,
+ .gl_get_proc_address = gl_get_proc_address,
+ .gl_swap_interval = gl_swap_interval,
+ .gl_swap_buffers = gl_swap_buffers,
+#endif
+ .type = YASL_PRIVATE_BACKEND_X11,
.display_open = display_open,
.display_close = display_close,
.display_caps = caps,
@@ -2530,6 +3109,7 @@ const struct yasl_backend_ops yasl_x11_backend = {
.surface_start_interactive_move = interactive_move,
.surface_start_interactive_resize = interactive_resize,
.surface_show_window_menu = show_window_menu,
+ .surface_update_text_input = surface_update_text_input,
.surface_set_ime_caret = set_ime_caret,
.surface_ime_preedit = ime_preedit,
.surface_ime_preedit_cursor = ime_preedit_cursor,