summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--meson.build10
-rwxr-xr-xscripts/line_count.sh2
-rw-r--r--src/egl_common.c14
-rw-r--r--src/egl_common.h1
-rw-r--r--src/poll_common.c4
-rw-r--r--src/window.c35
-rw-r--r--src/window.h27
-rw-r--r--src/window_glfw.c32
-rw-r--r--src/window_wayland.c237
-rw-r--r--src/window_wayland.h3
-rw-r--r--src/window_x11.c156
-rw-r--r--src/window_x11.h6
13 files changed, 306 insertions, 222 deletions
diff --git a/.gitignore b/.gitignore
index cd344ed..660dcb8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,5 @@ subprojects/glad/
subprojects/libakiyo
subprojects/libalabaster
subprojects/libev.wrap
-subprojects/liblfds.wrap
subprojects/wayland-protocols/
subprojects/wlr-protocols/
diff --git a/meson.build b/meson.build
index 4fb67f9..9afbb11 100644
--- a/meson.build
+++ b/meson.build
@@ -90,11 +90,11 @@ if get_option('window') == 'glfw'
stela_deps += [glfw3]
stela_args += ['-DSTELA_WINDOW_GLFW']
elif get_option('window') == 'x11'
- x11 = dependency('X11', required: false)
- if x11.found()
- stela_src += ['src/window_x11.c']
- stela_deps += [x11]
- endif
+ x11 = dependency('X11')
+ xext = dependency('xext')
+ xrandr = dependency('xrandr')
+ stela_src += ['src/window_x11.c']
+ stela_deps += [x11, xext, xrandr]
stela_args += ['-DSTELA_WINDOW_X11']
elif get_option('window') == 'wayland'
wl_client = dependency('wayland-client')
diff --git a/scripts/line_count.sh b/scripts/line_count.sh
index aadb675..9b46c9e 100755
--- a/scripts/line_count.sh
+++ b/scripts/line_count.sh
@@ -1,2 +1,2 @@
#! /usr/bin/env sh
-find ./src ./include -type f | xargs wc -l
+find ./src ./include -type f -exec wc -l {} +
diff --git a/src/egl_common.c b/src/egl_common.c
index 7fd8ddb..1c086d0 100644
--- a/src/egl_common.c
+++ b/src/egl_common.c
@@ -51,7 +51,9 @@ bool stl_load_egl(struct stl_egl_global *global)
void stl_terminate_egl(struct stl_egl_global *global)
{
- eglTerminate(global->display);
+ if (global->display != EGL_NO_DISPLAY) {
+ eglTerminate(global->display);
+ }
}
// https://gitlab.freedesktop.org/mesa/kmscube/-/blob/master/common.c#L162
@@ -158,6 +160,8 @@ bool stl_init_egl_context(struct stl_egl *egl, struct stl_egl_global *global, EG
return false;
}
+ egl->current = EGL_NO_CONTEXT;
+
egl->surface = EGL_NO_SURFACE;
return true;
@@ -165,12 +169,17 @@ bool stl_init_egl_context(struct stl_egl *egl, struct stl_egl_global *global, EG
void stl_egl_make_current(struct stl_egl *egl)
{
- eglMakeCurrent(egl->display, egl->surface, egl->surface, egl->context);
+ if (egl->context != egl->current) {
+ eglMakeCurrent(egl->display, egl->surface, egl->surface, egl->context);
+ egl->current = egl->context;
+ }
}
void stl_egl_release_current(struct stl_egl *egl)
{
+ al_assert(egl->context == egl->current);
eglMakeCurrent(egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ egl->current = EGL_NO_CONTEXT;
}
void stl_egl_swap_interval(struct stl_egl *egl, s32 interval)
@@ -190,7 +199,6 @@ bool stl_egl_is_ready(struct stl_egl *egl)
void stl_egl_destroy_surface(struct stl_egl *egl)
{
- stl_egl_release_current(egl);
eglDestroySurface(egl->display, egl->surface);
}
diff --git a/src/egl_common.h b/src/egl_common.h
index 1184eed..e59aa5c 100644
--- a/src/egl_common.h
+++ b/src/egl_common.h
@@ -17,6 +17,7 @@ struct stl_egl {
EGLDisplay display;
EGLSurface surface;
EGLContext context;
+ EGLContext current;
};
bool stl_maybe_load_egl(void);
diff --git a/src/poll_common.c b/src/poll_common.c
index bc637d7..32b5c2e 100644
--- a/src/poll_common.c
+++ b/src/poll_common.c
@@ -55,9 +55,9 @@ bool stl_process_events_common(struct aki_pollfd *fds)
}
#endif
return (fds[0].revents & POLLIN);
-#elif defined STELA_POLL_FD
+#else
(void)fds;
- return true;
#endif
+ return true;
}
diff --git a/src/window.c b/src/window.c
index 5efafdd..4389241 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1,9 +1,12 @@
+#include <al/log.h>
+
#include "window.h"
#define GET_EVENT_CHUNK(op) \
size_t size; \
u8 *ptr = al_ring_buffer_write_chunk(&window->events, &size); \
if (size < STELA_EVENT_SIZE) { \
+ al_log_warn("window", "Buffer full, discarding event."); \
return; \
} \
ptr[0] = op
@@ -88,11 +91,11 @@ void stl_window_send_key_event(struct stl_window *window, u8 state, u8 button)
void stl_window_send_resize_event(struct stl_window *window, s32 width, s32 height)
{
#if defined STELA_EVENT_BUFFER
- GET_EVENT_CHUNK(STELA_EVENT_RESIZE);
- ((s32 *)(&ptr[1]))[0] = width;
- ((s32 *)(&ptr[5]))[0] = height;
- APPEND_EVENT_CHUNK();
+ (void)width;
+ (void)height;
+ window->pending_resize = true;
#else
+ window->resize_internal(window, width, height);
if (window->resize_callback) {
window->resize_callback(window->userdata, width, height);
}
@@ -130,6 +133,19 @@ void stl_window_send_should_close_event(struct stl_window *window)
bool stl_window_read_events(struct stl_window *window)
{
u8 op = STELA_EVENT_NONE;
+ if (window->pending_resize) {
+ s32 width = window->width;
+ s32 height = window->height;
+ window->resize_internal(window, width, height);
+ if (window->resize_callback) {
+ window->resize_callback(window->userdata, width, height);
+ }
+#if defined STELA_PAUSE
+ window->pending_refresh = true;
+#endif
+ window->pending_resize = false;
+ op = STELA_EVENT_RESIZE;
+ }
size_t size;
u8 *ptr = al_ring_buffer_read_chunk(&window->events, &size);
u8 *bc = ptr;
@@ -183,17 +199,6 @@ bool stl_window_read_events(struct stl_window *window)
}
break;
}
- case STELA_EVENT_RESIZE: {
- s32 width = ((s32 *)(&bc[1]))[0];
- s32 height = ((s32 *)(&bc[5]))[0];
- if (window->resize_callback) {
- window->resize_callback(window->userdata, width, height);
- }
-#if defined STELA_PAUSE
- window->pending_refresh = true;
-#endif
- break;
- }
case STELA_EVENT_SHOULD_CLOSE: {
if (window->should_close_callback) {
window->should_close_callback(window->userdata);
diff --git a/src/window.h b/src/window.h
index 88cbb14..c96b6cd 100644
--- a/src/window.h
+++ b/src/window.h
@@ -23,11 +23,11 @@
#include <vulkan/vulkan.h>
#endif
-#ifndef STELA_MIN_WIDTH
+#if !defined STELA_MIN_WIDTH
#define STELA_MIN_WIDTH 16
#endif
-#ifndef STELA_MIN_HEIGHT
+#if !defined STELA_MIN_HEIGHT
#define STELA_MIN_HEIGHT 16
#endif
@@ -39,10 +39,8 @@ enum {
#define STELA_MAX_MONITOR_NAME 255u
struct stl_monitor {
- u32 x;
- u32 y;
- u32 width;
- u32 height;
+ s32 width;
+ s32 height;
s32 scale;
bool vertical;
char name[STELA_MAX_MONITOR_NAME];
@@ -57,6 +55,7 @@ struct stl_window {
u8 *data;
// Render thread events.
struct al_ring_buffer events;
+ bool pending_resize;
#endif
#if defined STELA_PAUSE
bool pending_refresh;
@@ -64,12 +63,10 @@ struct stl_window {
// Methods.
bool (*create_context)(struct stl_window *, s32);
bool (*create_window)(struct stl_window *, s32, s32, const char *, const char *, s32);
+ void (*resize_internal)(struct stl_window *, s32, s32);
void (*resize)(struct stl_window *, s32, s32);
void (*toggle_fullscreen)(struct stl_window *);
- void (*prepare_read)(struct stl_window *);
-#if defined STELA_POLL_FD
- s32 (*get_poll_fd)(struct stl_window *);
-#elif defined STELA_POLL_INLINE
+#if defined STELA_POLL_INLINE
bool (*poll)(struct stl_window *, bool);
#if defined STELA_PAUSE
void (*wake)(struct stl_window *);
@@ -129,15 +126,17 @@ enum {
};
#define STELA_EVENT_SIZE 32
-#ifndef STELA_EVENTS_SIZE
-#define STELA_EVENTS_SIZE (STELA_EVENT_SIZE * 288)
+#if !defined STELA_EVENTS_SIZE
+#define STELA_EVENTS_SIZE (STELA_EVENT_SIZE * 128)
#endif
void stl_set_output_discovered_callback(void (*output_discovered)(void *, struct stl_monitor *), void *userdata);
-bool stl_global_init(void);
+bool stl_global_init(bool skip_graphics);
+s32 stl_global_get_poll_fd();
+void stl_global_process_events();
void stl_global_close(void);
-struct stl_window *stl_window_create(void);
+struct stl_window *stl_window_create(void);
void stl_window_send_pointer_pos_event(struct stl_window *window, f64 x, f64 y);
void stl_window_send_scroll_event(struct stl_window *window, f64 y);
void stl_window_send_mouse_button_event(struct stl_window *window, u8 state, u8 button);
diff --git a/src/window_glfw.c b/src/window_glfw.c
index c586ffc..beb6bd9 100644
--- a/src/window_glfw.c
+++ b/src/window_glfw.c
@@ -33,8 +33,9 @@ static void error_callback(s32 error_code, const char *description)
al_log_error("glfw", "GLFW Error %d: %s.", error_code, description);
}
-bool stl_global_init(void)
+bool stl_global_init(bool skip_graphics)
{
+ (void)skip_graphics;
glfwSetErrorCallback(error_callback);
if (!glfwInit()) {
al_log_error("glfw", "Failed to initialize GLFW.");
@@ -45,6 +46,15 @@ bool stl_global_init(void)
return true;
}
+s32 stl_global_get_poll_fd()
+{
+ return -1;
+}
+
+void stl_global_process_events()
+{
+}
+
void stl_global_close(void)
{
glfwTerminate();
@@ -180,6 +190,13 @@ static bool window_glfw_create_window(struct stl_window *window, s32 width, s32
return true;
}
+static void window_glfw_resize_internal(struct stl_window *window, s32 width, s32 height)
+{
+ (void)window;
+ (void)width;
+ (void)height;
+}
+
static void window_glfw_resize(struct stl_window *window, s32 width, s32 height)
{
struct stl_window_glfw *glfw = (struct stl_window_glfw *)window;
@@ -246,13 +263,7 @@ static void window_glfw_toggle_fullscreen(struct stl_window *window)
glfw->w.fullscreen = !glfw->w.fullscreen;
}
-#if defined STELA_POLL_FD
-static s32 window_glfw_get_poll_fd(struct stl_window *window)
-{
- (void)window;
- return -1;
-}
-#elif defined STELA_POLL_INLINE
+#if defined STELA_POLL_INLINE
static bool window_glfw_poll(struct stl_window *window, bool block)
{
(void)window;
@@ -356,11 +367,10 @@ struct stl_window *stl_window_create(void)
glfw->w.fullscreen = false;
glfw->w.create_context = NULL;
glfw->w.create_window = window_glfw_create_window;
+ glfw->w.resize_internal = window_glfw_resize_internal;
glfw->w.resize = window_glfw_resize;
glfw->w.toggle_fullscreen = window_glfw_toggle_fullscreen;
-#if defined STELA_POLL_FD
- glfw->w.get_poll_fd = window_glfw_get_poll_fd;
-#elif defined STELA_POLL_INLINE
+#if defined STELA_POLL_INLINE
glfw->w.poll = window_glfw_poll;
#if defined STELA_PAUSE
glfw->w.wake = window_glfw_wake;
diff --git a/src/window_wayland.c b/src/window_wayland.c
index c839e4b..9b31d5f 100644
--- a/src/window_wayland.c
+++ b/src/window_wayland.c
@@ -40,13 +40,12 @@ static void handle_output_mode(void *data, struct wl_output *output,
(void)output;
(void)flags;
(void)refresh;
- al_assert(width >= 0 && height >= 0);
if (monitor->m.vertical) {
- monitor->m.width = (u32)height;
- monitor->m.height = (u32)width;
+ monitor->m.width = height;
+ monitor->m.height = width;
} else {
- monitor->m.width = (u32)width;
- monitor->m.height = (u32)height;
+ monitor->m.width = width;
+ monitor->m.height = height;
}
}
@@ -54,7 +53,7 @@ static void handle_output_done(void *data, struct wl_output *output)
{
struct stl_monitor_wayland *monitor = (struct stl_monitor_wayland *)data;
(void)output;
- al_log_info("window_wayland", "Output discovered: %s (%ux%u) (vertical: %s).",
+ al_log_info("window_wayland", "Output discovered: %s (%dx%d) (vertical: %s).",
monitor->m.name, monitor->m.width, monitor->m.height, AL_BOOLSTR(monitor->m.vertical));
if (global.output_discovered) {
global.output_discovered(global.userdata, (struct stl_monitor *)monitor);
@@ -79,8 +78,12 @@ static void handle_output_name(void *data, struct wl_output *output, const char
{
struct stl_monitor_wayland *monitor = (struct stl_monitor_wayland *)data;
(void)output;
- size_t len = strlen(name) + 1;
- al_memcpy(monitor->m.name, name, AL_MIN(len, STELA_MAX_MONITOR_NAME));
+ size_t len = al_strlen(name);
+ if (len >= STELA_MAX_MONITOR_NAME) {
+ len = STELA_MAX_MONITOR_NAME - 1;
+ monitor->m.name[len] = '\0';
+ }
+ al_memcpy(monitor->m.name, name, len);
}
static const struct wl_output_listener output_listener = {
@@ -122,22 +125,29 @@ void stl_set_output_discovered_callback(void (*output_discovered)(void *, struct
global.userdata = userdata;
}
-bool stl_global_init(void)
+bool stl_global_init(bool skip_graphics)
{
global.display = wl_display_connect(NULL);
if (!global.display) {
al_log_error("wayland", "Failed to connect to the display.");
return false;
}
+ global.display_fd = wl_display_get_fd(global.display);
+ if (!skip_graphics) {
#if defined STELA_API_OPENGL
- if (!stl_maybe_load_egl()) return false;
- global.egl.display = eglGetDisplay((EGLNativeDisplayType)global.display);
- if (!global.egl.display) {
- al_log_error("wayland", "Failed to get wayland-native EGL display.");
- return false;
- }
- if (!stl_load_egl(&global.egl)) return false;
+ if (!stl_maybe_load_egl()) return false;
+ global.egl.display = eglGetDisplay((EGLNativeDisplayType)global.display);
+ if (!global.egl.display) {
+ al_log_error("wayland", "Failed to get wayland-native EGL display.");
+ return false;
+ }
+ if (!stl_load_egl(&global.egl)) return false;
+#endif
+ } else {
+#if defined STELA_API_OPENGL
+ global.egl.display = EGL_NO_DISPLAY;
#endif
+ }
al_array_init(global.monitors);
global.registry = wl_display_get_registry(global.display);
wl_registry_add_listener(global.registry, &registry_listener, NULL);
@@ -147,6 +157,26 @@ bool stl_global_init(void)
return true;
}
+s32 stl_global_get_poll_fd()
+{
+ return global.display_fd;
+}
+
+static void display_prepare_read(struct wl_display *display)
+{
+ while (wl_display_prepare_read(display) != 0) {
+ wl_display_dispatch_pending(display);
+ }
+ wl_display_flush(display);
+}
+
+void stl_global_process_events()
+{
+ display_prepare_read(global.display);
+ wl_display_read_events(global.display);
+ wl_display_dispatch_pending(global.display);
+}
+
void stl_global_close(void)
{
#if defined STELA_API_OPENGL
@@ -157,6 +187,7 @@ void stl_global_close(void)
if (monitor->output) wl_output_destroy(monitor->output);
al_free(monitor);
}
+ al_array_free(global.monitors);
wl_display_disconnect(global.display);
}
@@ -524,23 +555,18 @@ static bool check_and_set_dimensions(struct stl_window_wayland *wl, s32 width, s
return true;
}
-static void send_resize_internal(struct stl_window_wayland *wl)
+static void send_resize(struct stl_window_wayland *wl)
{
-#if defined STELA_API_OPENGL
- if (stl_egl_is_ready(&wl->egl)) {
- wl_egl_window_resize(wl->egl_window, wl->w.width, wl->w.height, 0, 0);
- }
-#endif
stl_window_send_resize_event(&wl->w, wl->w.width, wl->w.height);
- wl->pending = false;
}
static void handle_xdg_surface_configure(void *data, struct xdg_surface *surface, u32 serial)
{
struct stl_window_wayland *wl = (struct stl_window_wayland *)data;
if (wl->pending) {
- send_resize_internal(wl);
+ send_resize(wl);
xdg_surface_set_window_geometry(wl->xdg_surface, 0, 0, wl->w.width, wl->w.height);
+ wl->pending = false;
}
xdg_surface_ack_configure(surface, serial);
}
@@ -555,7 +581,9 @@ static void handle_xdg_toplevel_configure(void *data, struct xdg_toplevel *tople
struct stl_window_wayland *wl = (struct stl_window_wayland *)data;
(void)toplevel;
(void)states;
- wl->pending = check_and_set_dimensions(wl, width, height);
+ if (check_and_set_dimensions(wl, width, height)) {
+ wl->pending = true;
+ }
}
static void handle_xdg_toplevel_close(void *data, struct xdg_toplevel *toplevel)
@@ -593,7 +621,7 @@ static void handle_layer_surface_configure(void *data, struct zwlr_layer_surface
{
struct stl_window_wayland *wl = (struct stl_window_wayland *)data;
if (check_and_set_dimensions(wl, width, height)) {
- send_resize_internal(wl);
+ send_resize(wl);
}
zwlr_layer_surface_v1_ack_configure(surface, serial);
}
@@ -629,6 +657,8 @@ static bool wl_egl_init(struct stl_window_wayland *wl)
wl->egl.surface = eglCreateWindowSurface(wl->egl.display, config, (EGLNativeWindowType)wl->egl_window, surface_attr);
+ eglSurfaceAttrib(wl->egl.display, wl->egl.surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
+
return true;
}
#endif
@@ -636,7 +666,7 @@ static bool wl_egl_init(struct stl_window_wayland *wl)
static bool create_context_internal(struct stl_window_wayland *wl)
{
wl->display = global.display;
- wl->fds[0].fd = wl_display_get_fd(wl->display);
+ wl->fds[0].fd = global.display_fd;
wl->fds[0].events = POLLIN;
#if defined STELA_POLL_INLINE && defined STELA_PAUSE
wl->fds[1].fd = eventfd(0, 0);
@@ -662,13 +692,63 @@ static bool window_wayland_create_context(struct stl_window *window, s32 flags)
static struct stl_monitor_wayland *monitor_from_name(const char *name)
{
- if (name) {
- for (u32 i = 0; i < global.monitors.size; i++) {
- struct stl_monitor_wayland *monitor = (struct stl_monitor_wayland *)al_array_at(global.monitors, i);
- if (strcmp(monitor->m.name, name) == 0) return monitor;
- }
+ for (u32 i = 0; i < global.monitors.size; i++) {
+ struct stl_monitor_wayland *monitor = (struct stl_monitor_wayland *)al_array_at(global.monitors, i);
+ if (strcmp(monitor->m.name, name) == 0) return monitor;
}
- return (struct stl_monitor_wayland *)al_array_at(global.monitors, 0);
+ return NULL;
+}
+
+static bool create_toplevel(struct stl_window_wayland *wl, s32 scale, const char *name)
+{
+ wl->w.scale = scale;
+ wl_surface_set_buffer_scale(wl->surface, scale);
+ wl->w.width *= scale;
+ wl->w.height *= scale;
+ wl->pending = true;
+
+ wl->xdg_surface = xdg_wm_base_get_xdg_surface(wl->xdg_wm_base, wl->surface);
+ if (!wl->xdg_surface) {
+ return false;
+ }
+ xdg_surface_add_listener(wl->xdg_surface, &xdg_surface_listener, wl);
+
+ wl->xdg_toplevel = xdg_surface_get_toplevel(wl->xdg_surface);
+ if (!wl->xdg_toplevel) {
+ return false;
+ }
+ xdg_toplevel_add_listener(wl->xdg_toplevel, &xdg_toplevel_listener, wl);
+
+ xdg_toplevel_set_title(wl->xdg_toplevel, name);
+ xdg_toplevel_set_app_id(wl->xdg_toplevel, name);
+ xdg_toplevel_set_min_size(wl->xdg_toplevel, STELA_MIN_WIDTH, STELA_MIN_HEIGHT);
+
+ u32 decor = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
+ wl->zxdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
+ wl->zxdg_decoration_manager, wl->xdg_toplevel);
+ zxdg_toplevel_decoration_v1_set_mode(wl->zxdg_toplevel_decoration, decor);
+
+ return true;
+}
+
+static bool create_layer_shell(struct stl_window_wayland *wl, struct stl_monitor_wayland *monitor, const char *name)
+{
+ wl->w.scale = monitor->m.scale;
+ u32 surface = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
+ u32 anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
+ | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
+ wl->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
+ wl->layer_shell, wl->surface, monitor->output, surface, name);
+ if (!wl->layer_surface) {
+ return false;
+ }
+ zwlr_layer_surface_v1_set_margin(wl->layer_surface, 0, 0, 0, 0);
+ zwlr_layer_surface_v1_set_size(wl->layer_surface, wl->w.width, wl->w.height);
+ zwlr_layer_surface_v1_set_anchor(wl->layer_surface, anchor);
+ zwlr_layer_surface_v1_add_listener(wl->layer_surface, &layer_surface_listener, wl);
+ return true;
}
static bool window_wayland_create_window(struct stl_window *window, s32 width, s32 height,
@@ -676,56 +756,25 @@ static bool window_wayland_create_window(struct stl_window *window, s32 width, s
{
struct stl_window_wayland *wl = (struct stl_window_wayland *)window;
+ al_assert(width >= STELA_MIN_WIDTH && height >= STELA_MIN_HEIGHT);
+
if (!create_context_internal(wl)) goto err;
- wl->monitor = monitor_from_name(monitor);
- if (!wl->monitor) goto err;
+ struct stl_monitor_wayland *selected = NULL;
wl->w.width = width;
wl->w.height = height;
- wl->pending = true;
wl->surface = wl_compositor_create_surface(wl->compositor);
if (!wl->surface) goto err;
wl_surface_add_listener(wl->surface, &surface_listener, wl);
if (!(flags & STELA_WINDOW_WALLPAPER)) {
- wl->w.scale = wl->monitor->m.scale;
- wl_surface_set_buffer_scale(wl->surface, wl->w.scale);
- wl->w.width *= wl->w.scale;
- wl->w.height *= wl->w.scale;
-
- wl->xdg_surface = xdg_wm_base_get_xdg_surface(wl->xdg_wm_base, wl->surface);
- if (!wl->xdg_surface) goto err;
- xdg_surface_add_listener(wl->xdg_surface, &xdg_surface_listener, wl);
-
- wl->xdg_toplevel = xdg_surface_get_toplevel(wl->xdg_surface);
- if (!wl->xdg_toplevel) goto err;
- xdg_toplevel_add_listener(wl->xdg_toplevel, &xdg_toplevel_listener, wl);
-
- xdg_toplevel_set_title(wl->xdg_toplevel, name);
- xdg_toplevel_set_app_id(wl->xdg_toplevel, name);
- xdg_toplevel_set_min_size(wl->xdg_toplevel, STELA_MIN_WIDTH, STELA_MIN_HEIGHT);
-
- u32 decor = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
- wl->zxdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(
- wl->zxdg_decoration_manager, wl->xdg_toplevel);
- zxdg_toplevel_decoration_v1_set_mode(wl->zxdg_toplevel_decoration, decor);
+ // TODO: Scale selection for toplevels.
+ selected = (struct stl_monitor_wayland *)al_array_at(global.monitors, 0);
+ if (!create_toplevel(wl, selected ? selected->m.scale : 1, name)) goto err;
} else {
- u32 surface = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
- //u32 surface = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND;
- u32 anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
- | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM
- | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
- | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
- wl->layer_surface = zwlr_layer_shell_v1_get_layer_surface(wl->layer_shell,
- wl->surface, wl->monitor->output, surface, name);
- if (!wl->layer_surface) goto err;
- zwlr_layer_surface_v1_set_margin(wl->layer_surface, 0, 0, 0, 0);
- if (!wl->w.width) wl->w.width = wl->monitor->m.width;
- if (!wl->w.height) wl->w.height = wl->monitor->m.height;
- zwlr_layer_surface_v1_set_size(wl->layer_surface, wl->w.width, wl->w.height);
- zwlr_layer_surface_v1_set_anchor(wl->layer_surface, anchor);
- zwlr_layer_surface_v1_add_listener(wl->layer_surface, &layer_surface_listener, wl);
+ selected = monitor_from_name(monitor);
+ if (!selected || !create_layer_shell(wl, selected, name)) goto err;
}
#if defined STELA_API_OPENGL
@@ -761,6 +810,20 @@ static void window_wayland_resize(struct stl_window *window, s32 width, s32 heig
(void)height;
}
+static void window_wayland_resize_internal(struct stl_window *window, s32 width, s32 height)
+{
+ struct stl_window_wayland *wl = (struct stl_window_wayland *)window;
+#if defined STELA_API_OPENGL
+ if (stl_egl_is_ready(&wl->egl)) {
+ wl_egl_window_resize(wl->egl_window, width, height, 0, 0);
+ }
+#else
+ (void)wl;
+ (void)width;
+ (void)height;
+#endif
+}
+
static void window_wayland_toggle_fullscreen(struct stl_window *window)
{
struct stl_window_wayland *wl = (struct stl_window_wayland *)window;
@@ -772,31 +835,11 @@ static void window_wayland_toggle_fullscreen(struct stl_window *window)
wl->w.fullscreen = !wl->w.fullscreen;
}
-static void prepare_read_internal(struct stl_window_wayland *wl)
-{
- while (wl_display_prepare_read(wl->display) != 0) {
- wl_display_dispatch_pending(wl->display);
- }
- wl_display_flush(wl->display);
-}
-
-static void window_wayland_prepare_read(struct stl_window *window)
-{
- struct stl_window_wayland *wl = (struct stl_window_wayland *)window;
- prepare_read_internal(wl);
-}
-
-#if defined STELA_POLL_FD
-static s32 window_wayland_get_poll_fd(struct stl_window *window)
-{
- struct stl_window_wayland *wl = (struct stl_window_wayland *)window;
- return wl->fds[0].fd;
-}
-#elif defined STELA_POLL_INLINE
+#if defined STELA_POLL_INLINE
static bool window_wayland_poll(struct stl_window *window, bool block)
{
struct stl_window_wayland *wl = (struct stl_window_wayland *)window;
- prepare_read_internal(wl);
+ display_prepare_read(wl->display);
return stl_poll_common(wl->fds, block);
}
@@ -917,11 +960,9 @@ struct stl_window *stl_window_create(void)
wl->w.create_context = window_wayland_create_context;
wl->w.create_window = window_wayland_create_window;
wl->w.resize = window_wayland_resize;
+ wl->w.resize_internal = window_wayland_resize_internal;
wl->w.toggle_fullscreen = window_wayland_toggle_fullscreen;
- wl->w.prepare_read = window_wayland_prepare_read;
-#if defined STELA_POLL_FD
- wl->w.get_poll_fd = window_wayland_get_poll_fd;
-#elif defined STELA_POLL_INLINE
+#if defined STELA_POLL_INLINE
wl->w.poll = window_wayland_poll;
#if defined STELA_PAUSE
wl->w.wake = window_wayland_wake;
diff --git a/src/window_wayland.h b/src/window_wayland.h
index 157705e..b7dadf3 100644
--- a/src/window_wayland.h
+++ b/src/window_wayland.h
@@ -18,10 +18,11 @@
struct stl_wayland_global {
struct wl_display *display;
- struct stl_egl_global egl;
+ s32 display_fd;
struct wl_registry *registry;
struct wl_surface *active_surface;
array(struct stl_monitor *) monitors;
+ struct stl_egl_global egl;
void (*output_discovered)(void *, struct stl_monitor *);
void *userdata;
};
diff --git a/src/window_x11.c b/src/window_x11.c
index 53cf0b5..4ffa4d0 100644
--- a/src/window_x11.c
+++ b/src/window_x11.c
@@ -16,17 +16,19 @@ static struct stl_x11_global global;
void stl_set_output_discovered_callback(void (*output_discovered)(void *, struct stl_monitor *), void *userdata)
{
- (void)output_discovered;
- (void)userdata;
+ global.output_discovered = output_discovered;
+ global.userdata = userdata;
}
-bool stl_global_init(void)
+bool stl_global_init(bool skip_graphics)
{
+ (void)skip_graphics;
global.x11_d = XOpenDisplay(NULL);
if (!global.x11_d) {
al_log_error("x11", "Couldn't open display.");
return false;
}
+ global.root = XRootWindow(global.x11_d, XDefaultScreen(global.x11_d));
#if defined STELA_API_OPENGL
if (!stl_maybe_load_egl()) return false;
global.egl.display = eglGetDisplay((EGLNativeDisplayType)global.x11_d);
@@ -35,11 +37,49 @@ bool stl_global_init(void)
}
if (!stl_load_egl(&global.egl)) return false;
#endif
+ s32 monitor_count;
+ XRRMonitorInfo *info = XRRGetMonitors(global.x11_d, global.root, 0, &monitor_count);
+ al_array_init(global.monitors);
+ al_array_reserve(global.monitors, monitor_count);
+ for (s32 i = 0; i < monitor_count; i++) {
+ struct stl_monitor *monitor = al_alloc_object(struct stl_monitor);
+ char *name = XGetAtomName(global.x11_d, info[i].name);
+ size_t len = al_strlen(name);
+ if (len >= STELA_MAX_MONITOR_NAME) {
+ len = STELA_MAX_MONITOR_NAME - 1;
+ monitor->name[len] = '\0';
+ }
+ al_memcpy(monitor->name, name, len);
+ free(name);
+ monitor->scale = 1;
+ monitor->width = info[i].width;
+ monitor->height = info[i].height;
+ al_array_push(global.monitors, monitor);
+ if (global.output_discovered) {
+ global.output_discovered(global.userdata, monitor);
+ }
+ }
+ XRRFreeMonitors(info);
return true;
}
+s32 stl_global_get_poll_fd()
+{
+ return -1;
+}
+
+void stl_global_process_events()
+{
+}
+
void stl_global_close(void)
{
+ for (u32 i = 0; i < global.monitors.size; i++) {
+ struct stl_monitor *monitor = al_array_at(global.monitors, i);
+ al_free(monitor);
+ }
+ al_array_free(global.monitors);
+ XCloseDisplay(global.x11_d);
}
static bool x11_egl_init(struct stl_window_x11 *xw)
@@ -69,72 +109,53 @@ static bool window_x11_create_window(struct stl_window *window, s32 width, s32 h
struct stl_window_x11 *xw = (struct stl_window_x11 *)window;
(void)monitor;
- xw->x11_d = global.x11_d;
-
- s32 screen = XDefaultScreen(xw->x11_d);
- Window root = RootWindow(xw->x11_d, screen);
-
XSetWindowAttributes swa;
swa.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask |
PointerMotionMask | ExposureMask | StructureNotifyMask |
PropertyChangeMask | VisibilityChangeMask;
- xw->window = XCreateWindow(xw->x11_d, root, 0, 0, width, height,
- 0, CopyFromParent, InputOutput, CopyFromParent, CWEventMask, &swa);
+ xw->window = XCreateWindow(global.x11_d, global.root, 0, 0, width, height, 0, CopyFromParent,
+ InputOutput, CopyFromParent, CWEventMask, &swa);
- ATOM_WM_DELETE_WINDOW = XInternAtom(xw->x11_d, "WM_DELETE_WINDOW", False);
- XSetWMProtocols(xw->x11_d, xw->window, &ATOM_WM_DELETE_WINDOW, 1);
+ ATOM_WM_DELETE_WINDOW = XInternAtom(global.x11_d, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(global.x11_d, xw->window, &ATOM_WM_DELETE_WINDOW, 1);
- XStoreName(xw->x11_d, xw->window, name);
+ XStoreName(global.x11_d, xw->window, name);
XSetWindowAttributes xattr;
xattr.override_redirect = False;
- XChangeWindowAttributes(xw->x11_d, xw->window, CWOverrideRedirect, &xattr);
+ XChangeWindowAttributes(global.x11_d, xw->window, CWOverrideRedirect, &xattr);
- XMapWindow(xw->x11_d, xw->window);
- XFlush(xw->x11_d);
+ XMapWindow(global.x11_d, xw->window);
+ XFlush(global.x11_d);
XWindowAttributes gwa;
- XGetWindowAttributes(xw->x11_d, xw->window, &gwa);
+ XGetWindowAttributes(global.x11_d, xw->window, &gwa);
xw->w.width = gwa.width;
xw->w.height = gwa.height;
if (flags & STELA_WINDOW_WALLPAPER)
{
- /*
- Atom desktop = XInternAtom(xw->x11_d, "_NET_WM_DESKTOP", False);
- unsigned long all_desktops = XWIN_ALL_DESKTOPS;
- XChangeProperty(xw->x11_d, xw->window, desktop,
- XA_CARDINAL, 32, PropModeReplace, (u8 *)&all_desktops, 1);
- */
-
- Atom net_wm_type = XInternAtom(xw->x11_d, "_NET_WM_WINDOW_TYPE", False);
- Atom desktop_type = XInternAtom(xw->x11_d, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
- XChangeProperty(xw->x11_d, xw->window, net_wm_type,
- XA_ATOM, 32, PropModeReplace, (u8 *)&desktop_type, 1);
-
- /*
- XEvent event;
- event.xclient.type = ClientMessage;
- event.xclient.serial = 0;
- event.xclient.send_event = True;
- event.xclient.display = xw->x11_d;
- event.xclient.window = xw->window;
- event.xclient.message_type = XInternAtom(xw->x11_d, "_NET_WM_STATE", False);
- event.xclient.format = 32;
-
- event.xclient.data.l[0] = _NET_WM_STATE_ADD;
- event.xclient.data.l[1] = XInternAtom(xw->x11_d, "_NET_WM_STATE_BELOW", False);
- event.xclient.data.l[2] = 0; //unused.
- event.xclient.data.l[3] = 0;
- event.xclient.data.l[4] = 0;
- XSendEvent(xw->x11_d, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &event);
+ Atom net_wm_type = XInternAtom(global.x11_d, "_NET_WM_WINDOW_TYPE", False);
+ if (net_wm_type) {
+ Atom desktop_type = XInternAtom(global.x11_d, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
+ XChangeProperty(global.x11_d, xw->window, net_wm_type, XA_ATOM, 32,
+ PropModeReplace, (u8 *)&desktop_type, 1);
+ }
- event.xclient.data.l[1] = XInternAtom(xw->x11_d, "_NET_WM_STATE_STICKY", False);
- XSendEvent(xw->x11_d, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &event);
+ Atom net_wm_state = XInternAtom(global.x11_d, "_NET_WM_STATE", False);
+ if (net_wm_state) {
+ Atom net_wm_sticky = XInternAtom(global.x11_d, "_NET_WM_STATE_STICKY", False);
+ XChangeProperty(global.x11_d, xw->window, net_wm_state, XA_ATOM, 32,
+ PropModeAppend, (u8*)&net_wm_sticky, 1);
+ }
- event.xclient.data.l[1] = XInternAtom(xw->x11_d, "_NET_WM_STATE_FULLSCREEN", False);
- */
+ Atom net_wm_desktop = XInternAtom(global.x11_d, "_NET_WM_DESKTOP", False);
+ if (net_wm_desktop) {
+ ulong all_desktops = XWIN_ALL_DESKTOPS;
+ XChangeProperty(global.x11_d, xw->window, net_wm_desktop, XA_CARDINAL, 32,
+ PropModeReplace, (u8 *)&all_desktops, 1);
+ }
}
if (!x11_egl_init(xw)) return false;
@@ -143,7 +164,7 @@ static bool window_x11_create_window(struct stl_window *window, s32 width, s32 h
stl_egl_swap_interval(&xw->egl, (flags & STELA_WINDOW_VSYNC) ? 1 : 0);
stl_egl_release_current(&xw->egl);
- xw->fds[0].fd = ConnectionNumber(xw->x11_d);
+ xw->fds[0].fd = ConnectionNumber(global.x11_d);
xw->fds[0].events = POLLIN;
#if defined STELA_POLL_INLINE && defined STELA_PAUSE
@@ -154,14 +175,19 @@ static bool window_x11_create_window(struct stl_window *window, s32 width, s32 h
return true;
}
-static void window_x11_resize(struct stl_window *window, s32 width, s32 height)
+static void window_x11_resize_internal(struct stl_window *window, s32 width, s32 height)
{
- struct stl_window_x11 *xw = (struct stl_window_x11 *)window;
- (void)xw;
+ (void)window;
(void)width;
(void)height;
}
+static void window_x11_resize(struct stl_window *window, s32 width, s32 height)
+{
+ struct stl_window_x11 *xw = (struct stl_window_x11 *)window;
+ XMoveResizeWindow(global.x11_d, xw->window, 0, 0, width, height);
+}
+
static void window_x11_toggle_fullscreen(struct stl_window *window)
{
struct stl_window_x11 *xw = (struct stl_window_x11 *)window;
@@ -171,13 +197,7 @@ static void window_x11_toggle_fullscreen(struct stl_window *window)
xw->w.fullscreen = !xw->w.fullscreen;
}
-#if defined STELA_POLL_FD
-static s32 window_x11_get_poll_fd(struct stl_window *window)
-{
- struct stl_window_x11 *xw = (struct stl_window_x11 *)window;
- return xw->fds[0].fd;
-}
-#elif defined STELA_POLL_INLINE
+#if defined STELA_POLL_INLINE
static bool window_x11_poll(struct stl_window *window, bool block)
{
struct stl_window_x11 *xw = (struct stl_window_x11 *)window;
@@ -196,7 +216,7 @@ static void window_x11_wake(struct stl_window *window)
static void handle_next_xevent(struct stl_window_x11 *xw)
{
XEvent xev;
- XNextEvent(xw->x11_d, &xev);
+ XNextEvent(global.x11_d, &xev);
switch (xev.type) {
case ClientMessage:
if ((Atom)xev.xclient.data.l[0] == ATOM_WM_DELETE_WINDOW) {
@@ -244,12 +264,9 @@ static void window_x11_process_events(struct stl_window *window)
{
struct stl_window_x11 *xw = (struct stl_window_x11 *)window;
stl_process_events_common(xw->fds);
- // It seems for some reason POLLIN doesn't get set even
- // when there's events.
- XPending(xw->x11_d);
- while (QLength(xw->x11_d) > 0) {
- handle_next_xevent(xw);
- }
+ // It seems for some reason POLLIN doesn't get set even when there's events.
+ XPending(global.x11_d);
+ while (QLength(global.x11_d) > 0) { handle_next_xevent(xw); }
}
#if defined STELA_PAUSE
@@ -330,11 +347,10 @@ struct stl_window *stl_window_create(void)
xw->w.fullscreen = false;
xw->w.create_context = NULL;
xw->w.create_window = window_x11_create_window;
+ xw->w.resize_internal = window_x11_resize_internal;
xw->w.resize = window_x11_resize;
xw->w.toggle_fullscreen = window_x11_toggle_fullscreen;
-#if defined STELA_POLL_FD
- xw->w.get_poll_fd = window_x11_get_poll_fd;
-#elif defined STELA_POLL_INLINE
+#if defined STELA_POLL_INLINE
xw->w.poll = window_x11_poll;
#if defined STELA_PAUSE
xw->w.wake = window_x11_wake;
diff --git a/src/window_x11.h b/src/window_x11.h
index 8b69e7f..5392493 100644
--- a/src/window_x11.h
+++ b/src/window_x11.h
@@ -4,18 +4,22 @@
#include <X11/Xlib.h>
#include <X11/Xatom.h>
+#include <X11/extensions/Xrandr.h>
#include "window.h"
#include "egl_common.h"
struct stl_x11_global {
Display *x11_d;
+ Window root;
+ array(struct stl_monitor *) monitors;
struct stl_egl_global egl;
+ void (*output_discovered)(void *, struct stl_monitor *);
+ void *userdata;
};
struct stl_window_x11 {
struct stl_window w;
- Display *x11_d;
Window window;
struct stl_egl egl;
#if defined STELA_PAUSE