diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/egl_common.c | 14 | ||||
| -rw-r--r-- | src/egl_common.h | 1 | ||||
| -rw-r--r-- | src/poll_common.c | 4 | ||||
| -rw-r--r-- | src/window.c | 35 | ||||
| -rw-r--r-- | src/window.h | 27 | ||||
| -rw-r--r-- | src/window_glfw.c | 32 | ||||
| -rw-r--r-- | src/window_wayland.c | 237 | ||||
| -rw-r--r-- | src/window_wayland.h | 3 | ||||
| -rw-r--r-- | src/window_x11.c | 156 | ||||
| -rw-r--r-- | src/window_x11.h | 6 |
10 files changed, 300 insertions, 215 deletions
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, ®istry_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 |