summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--meson.build15
-rw-r--r--src/egl_common.c2
-rw-r--r--src/gl_versions.h2
-rw-r--r--src/window.c39
-rw-r--r--src/window.h61
-rw-r--r--src/window_glfw.c6
-rw-r--r--src/window_wayland.c21
-rw-r--r--src/window_wayland.h1
-rw-r--r--src/window_win32.c168
-rw-r--r--src/window_x11.c21
-rw-r--r--subprojects/libalabaster.wrap4
-rw-r--r--subprojects/libnaunet.wrap4
-rw-r--r--tests/window.c14
13 files changed, 238 insertions, 120 deletions
diff --git a/meson.build b/meson.build
index af738aa..3215fc2 100644
--- a/meson.build
+++ b/meson.build
@@ -4,16 +4,17 @@ project('stela', 'c', version: '0.01',
license: 'GPL-3.0-only')
compiler = meson.get_compiler('c')
-cmake = import('cmake')
is_debug = get_option('debug')
is_minsize = get_option('optimization') == 's'
-
is_linux = host_machine.system() == 'linux'
is_windows = host_machine.system() == 'windows'
is_macos = host_machine.system() == 'darwin'
is_android = host_machine.system() == 'android'
+cmake = import('cmake')
+cmake_reltype = is_minsize ? 'MinSizeRel' : 'Release'
+
if get_option('window') == 'null'
error('No window type selected.')
endif
@@ -201,8 +202,7 @@ elif get_option('window') == 'glfw'
glfw3 = dependency('glfw3', required: false, allow_fallback: false)
if not glfw3.found()
glfw_opts = cmake.subproject_options()
- reltype = is_minsize ? 'MinSizeRel' : 'Release'
- glfw_opts.add_cmake_defines({ 'CMAKE_BUILD_TYPE': is_debug ? 'Debug' : reltype })
+ glfw_opts.add_cmake_defines({ 'CMAKE_BUILD_TYPE': is_debug ? 'Debug' : cmake_reltype })
glfw_opts.add_cmake_defines({ 'GLFW_INSTALL': false })
glfw_opts.add_cmake_defines({ 'GLFW_BUILD_EXAMPLES': false })
glfw_opts.add_cmake_defines({ 'GLFW_BUILD_TESTS': false })
@@ -220,14 +220,13 @@ elif get_option('window') == 'glfm'
glfm = dependency('glfm', required: false, allow_fallback: false)
if not glfm.found()
glfm_opts = cmake.subproject_options()
- reltype = is_minsize ? 'MinSizeRel' : 'Release'
- glfm_opts.add_cmake_defines({ 'CMAKE_BUILD_TYPE': is_debug ? 'Debug' : reltype })
+ glfm_opts.add_cmake_defines({ 'CMAKE_BUILD_TYPE': is_debug ? 'Debug' : cmake_reltype })
glfm_opts.add_cmake_defines({ 'CMAKE_POSITION_INDEPENDENT_CODE': true })
glfm = cmake.subproject('glfm', options: glfm_opts).dependency('glfm')
endif
stela_src += ['src/window_glfm.c']
stela_deps += [glfm]
- stela_args += ['-DSTELA_WINDOW_GLFM']
+ stela_args += ['-DSTELA_WINDOW_GLFM', '-DSTELA_USE_PLATFORM_MAIN']
endif
stela = declare_dependency(include_directories: stela_inc,
@@ -238,6 +237,6 @@ if not meson.is_subproject()
stela_lib = shared_library('stela', dependencies: stela, install: false)
endif
-if get_option('tests').allowed() and not meson.is_subproject()
+if get_option('tests').allowed()
subdir('tests')
endif
diff --git a/src/egl_common.c b/src/egl_common.c
index 8f02afa..eb01492 100644
--- a/src/egl_common.c
+++ b/src/egl_common.c
@@ -122,7 +122,7 @@ bool stl_init_egl_context(struct stl_egl *egl, struct stl_egl_global *global, EG
STELA_LOG_GL_CONTEXT_CREATION(stl_gl_vers[i]);
- const EGLint *context_attr = stl_gl_vers[i].api == STELA_GL_API ?
+ const EGLint *context_attr = (stl_gl_vers[i].api == STELA_GL_API) ?
context_attr_gl : context_attr_gles;
eglBindAPI(stl_gl_vers[i].api);
diff --git a/src/gl_versions.h b/src/gl_versions.h
index eb53794..7b3050c 100644
--- a/src/gl_versions.h
+++ b/src/gl_versions.h
@@ -12,7 +12,7 @@
#define STELA_LOG_GL_CONTEXT_CREATION(ver) \
log_debug("Attempting to create a %s context of version %d.%d (GLSL %d).", \
- (ver).api == STELA_GL_API ? "GL" : "GLES", (ver).major, (ver).minor, (ver).glsl_ver)
+ ((ver).api == STELA_GL_API) ? "GL" : "GLES", (ver).major, (ver).minor, (ver).glsl_ver)
// https://github.com/haasn/libplacebo/blob/795600a44b03fcd52c055981a403ad60ee5d027a/demos/window_glfw.c#L194
#ifdef STELA_USE_GLES
diff --git a/src/window.c b/src/window.c
index f85f4fc..ad5ca4d 100644
--- a/src/window.c
+++ b/src/window.c
@@ -4,9 +4,10 @@
#include "window.h"
#include "keys.h"
-static bool nop_pointer_pos_callback(void *userdata, f64 x, f64 y)
+static bool nop_pointer_callback(void *userdata, u8 type, f64 x, f64 y)
{
(void)userdata;
+ (void)type;
(void)x;
(void)y;
return false;
@@ -53,6 +54,14 @@ static bool nop_key_immediate_callback(void *userdata, u8 state, u16 button)
return false;
}
+#ifdef STELA_DRAG_AND_DROP
+static void nop_drag_and_drop_callback(void *userdata, str *path)
+{
+ (void)userdata;
+ (void)path;
+}
+#endif
+
static void window_default_close(struct stl_window *window)
{
window->closed = true;
@@ -60,12 +69,15 @@ static void window_default_close(struct stl_window *window)
void stl_window_init(struct stl_window *window)
{
- window->pointer_pos_callback = nop_pointer_pos_callback;
+ window->pointer_callback = nop_pointer_callback;
window->touch_callback = nop_touch_callback;
window->scroll_callback = nop_scroll_callback;
window->mouse_button_callback = nop_mouse_button_callback;
window->key_callback = nop_key_callback;
window->key_immediate_callback = nop_key_immediate_callback;
+#ifdef STELA_DRAG_AND_DROP
+ window->drag_and_drop_callback = nop_drag_and_drop_callback;
+#endif
window->close = window_default_close;
#ifdef STELA_EVENT_BUFFER
al_ring_buffer_init(&window->events, window->data, STELA_EVENTS_SIZE);
@@ -121,18 +133,19 @@ void stl_window_send_resize_event(struct stl_window *window, u32 width, u32 heig
#endif
}
-void stl_window_send_pointer_pos_event(struct stl_window *window, f64 x, f64 y)
+void stl_window_send_pointer_event(struct stl_window *window, u8 type, f64 x, f64 y)
{
#ifdef STELA_EVENT_BUFFER
GET_EVENT_CHUNK(STELA_EVENT_POINTER_POS);
- ((f64 *)(&ptr[1]))[0] = x;
- ((f64 *)(&ptr[9]))[0] = y;
+ ptr[1] = type;
+ ((f64 *)(&ptr[2]))[0] = x;
+ ((f64 *)(&ptr[10]))[0] = y;
APPEND_EVENT_CHUNK();
#else
#ifdef STELA_PAUSE
window->pending_refresh |=
#endif
- window->pointer_pos_callback(window->userdata, x, y);
+ window->pointer_callback(window->userdata, type, x, y);
#endif
}
@@ -234,6 +247,13 @@ bool stl_window_send_key_immediate_event(struct stl_window *window, u8 state, u1
return window->key_immediate_callback(window->userdata, state, button * (stl_key_to_mod(button) == STELA_MOD_NONE));
}
+#ifdef STELA_DRAG_AND_DROP
+void stl_window_send_drag_and_drop_event(struct stl_window *window, str *path)
+{
+ window->drag_and_drop_callback(window->userdata, path);
+}
+#endif
+
void stl_window_drop_modifiers(struct stl_window *window)
{
u32 *mods = stl_all_modifiers;
@@ -282,12 +302,13 @@ bool stl_window_read_events(struct stl_window *window)
op = *bc;
switch (op) {
case STELA_EVENT_POINTER_POS: {
- f64 x = ((f64 *)(&bc[1]))[0];
- f64 y = ((f64 *)(&bc[9]))[0];
+ u8 type = bc[1];
+ f64 x = ((f64 *)(&bc[2]))[0];
+ f64 y = ((f64 *)(&bc[10]))[0];
#ifdef STELA_PAUSE
window->pending_refresh |=
#endif
- window->pointer_pos_callback(window->userdata, x, y);
+ window->pointer_callback(window->userdata, type, x, y);
break;
}
case STELA_EVENT_TOUCH: {
diff --git a/src/window.h b/src/window.h
index 16b8f2e..66d4f38 100644
--- a/src/window.h
+++ b/src/window.h
@@ -36,6 +36,18 @@
#include "egl_common.h"
#endif
+// Drag window by clicking anywhere with MOUSE2.
+#define STELA_MOUSE2_DRAG
+
+#ifdef STELA_WINDOW_WIN32
+#define STELA_DRAG_AND_DROP
+#endif
+
+#define STELA_EVENT_SIZE 24u
+#ifndef STELA_EVENTS_SIZE
+#define STELA_EVENTS_SIZE (STELA_EVENT_SIZE * 64u)
+#endif
+
#ifndef STELA_MIN_WIDTH
#define STELA_MIN_WIDTH 16u
#endif
@@ -48,21 +60,6 @@
#define STELA_ICON_AT_RUNTIME
#endif
-// Drag window by clicking anywhere with MOUSE2.
-#define STELA_MOUSE2_DRAG
-
-enum {
- STELA_WINDOW_VSYNC = 1,
- STELA_WINDOW_WALLPAPER = 1 << 1
-};
-
-enum {
- STELA_CURSOR_NORMAL = 0,
- STELA_CURSOR_MOVE,
- STELA_CURSOR_CROSSHAIR,
- STELA_CURSOR_HIDDEN
-};
-
#define STELA_MAX_MONITOR_NAME 255u
struct stl_monitor {
@@ -73,10 +70,10 @@ struct stl_monitor {
char name[STELA_MAX_MONITOR_NAME];
};
-#define STELA_EVENT_SIZE 24u
-#ifndef STELA_EVENTS_SIZE
-#define STELA_EVENTS_SIZE (STELA_EVENT_SIZE * 64u)
-#endif
+enum {
+ STELA_WINDOW_VSYNC = 1,
+ STELA_WINDOW_WALLPAPER = 1 << 1
+};
struct stl_window {
u32 width;
@@ -126,7 +123,7 @@ struct stl_window {
void (*output_discovered_callback)(void *, struct stl_monitor *);
void (*render_callback)(void *);
void (*resize_callback)(void *, u32, u32);
- bool (*pointer_pos_callback)(void *, f64, f64);
+ bool (*pointer_callback)(void *, u8, f64, f64);
bool (*touch_callback)(void *, s32, u8, f64, f64);
bool (*scroll_callback)(void *, f64);
bool (*mouse_button_callback)(void *, u8, u8);
@@ -136,6 +133,9 @@ struct stl_window {
// - Return value decides if the event should "pass through" or not.
// True = Consume, False = Passthrough.
bool (*key_immediate_callback)(void *, u8, u16);
+#ifdef STELA_DRAG_AND_DROP
+ void (*drag_and_drop_callback)(void *, str *);
+#endif
void (*should_close_callback)(void *);
void *userdata;
bool closed;
@@ -185,6 +185,11 @@ static u8 stl_all_mouse_buttons[] = {
AL_IGNORE_WARNING_END
enum {
+ STELA_POINTER_POS = 0,
+ STELA_POINTER_MOVE,
+};
+
+enum {
STELA_TOUCH_HOVER = 0,
STELA_TOUCH_BEGAN,
STELA_TOUCH_MOVED,
@@ -192,7 +197,14 @@ enum {
STELA_TOUCH_CANCELLED
};
-extern s32 stl_platform_main(u32 argc, str *argv);
+enum {
+ STELA_CURSOR_NORMAL = 0,
+ STELA_CURSOR_MOVE,
+ STELA_CURSOR_CROSSHAIR,
+ STELA_CURSOR_HIDDEN
+};
+
+extern s32 stl_platform_main(u32 argc, str *argv, void *extra);
f64 stl_scale_scroll(f64 v, f64 factor);
void stl_set_output_discovered_callback(void (*output_discovered)(void *, struct stl_monitor *), void *userdata);
@@ -209,15 +221,18 @@ void stl_global_close(void);
struct stl_window *stl_window_create(void);
void stl_window_send_render_event(struct stl_window *window);
void stl_window_send_resize_event(struct stl_window *window, u32 width, u32 height);
-void stl_window_send_pointer_pos_event(struct stl_window *window, f64 x, f64 y);
+void stl_window_send_pointer_event(struct stl_window *window, u8 type, f64 x, f64 y);
void stl_window_send_touch_event(struct stl_window *window, s32 index, u8 phase, 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);
void stl_window_drop_mouse_buttons(struct stl_window *window);
void stl_window_send_key_event(struct stl_window *window, u8 state, u16 button);
bool stl_window_send_key_immediate_event(struct stl_window *window, u8 state, u16 button);
-void stl_window_drop_modifiers(struct stl_window *window);
+#ifdef STELA_DRAG_AND_DROP
+void stl_window_send_drag_and_drop_event(struct stl_window *window, str *path);
+#endif
void stl_window_send_should_close_event(struct stl_window *window);
+void stl_window_drop_modifiers(struct stl_window *window);
#ifdef STELA_EVENT_BUFFER
bool stl_window_read_events(struct stl_window *window);
#endif
diff --git a/src/window_glfw.c b/src/window_glfw.c
index 32e0cfb..f42a99c 100644
--- a/src/window_glfw.c
+++ b/src/window_glfw.c
@@ -119,7 +119,7 @@ static void cursor_position_callback(GLFWwindow *window, f64 xpos, f64 ypos)
struct stl_window_glfw *glfw = glfwGetWindowUserPointer(window);
xpos *= glfw->scale_x;
ypos *= glfw->scale_y;
- stl_window_send_pointer_pos_event(&glfw->w, xpos, ypos);
+ stl_window_send_pointer_event(&glfw->w, STELA_POINTER_POS, xpos, ypos);
}
// @TODO: Test behavior on x11, Windows?
@@ -178,7 +178,7 @@ static void key_callback(GLFWwindow *window, s32 key, s32 scancode, s32 action,
log_warn("Unmapped GLFW key pressed (%hu).", (u16)key);
return;
}
- u8 mapped_state = action == GLFW_PRESS ? STELA_BUTTON_PRESSED : STELA_BUTTON_RELEASED;
+ u8 mapped_state = (action == GLFW_PRESS) ? STELA_BUTTON_PRESSED : STELA_BUTTON_RELEASED;
stl_window_send_key_immediate_event(&glfw->w, mapped_state, (u16)key);
stl_window_send_key_event(&glfw->w, mapped_state, (u16)key);
}
@@ -225,7 +225,7 @@ static bool window_glfw_create_window(struct stl_window *window, u32 width, u32
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
}
log_debug("Attempting to create a %s context of version %d.%d (GLSL %d).",
- stl_gl_vers[i].api == STELA_GL_API ? "GL" : "GLES",
+ (stl_gl_vers[i].api == STELA_GL_API) ? "GL" : "GLES",
stl_gl_vers[i].major, stl_gl_vers[i].minor, stl_gl_vers[i].glsl_ver);
#endif
al_assert(width >= STELA_MIN_WIDTH && height >= STELA_MIN_HEIGHT);
diff --git a/src/window_wayland.c b/src/window_wayland.c
index 2517003..e019002 100644
--- a/src/window_wayland.c
+++ b/src/window_wayland.c
@@ -118,6 +118,7 @@ static void global_add(void *data, struct wl_registry *registry, u32 name,
(void)data;
if (al_strscmp(interface, "wl_output") == 0) {
struct stl_monitor_wayland *monitor = al_alloc_object(struct stl_monitor_wayland);
+ monitor->wln = name;
al_array_push(global.monitors, (struct stl_monitor *)monitor);
monitor->output = (struct wl_output *)wl_registry_bind(registry, name, &wl_output_interface, ASSERT_MIN(4u, version));
wl_output_add_listener(monitor->output, &output_listener, monitor);
@@ -128,7 +129,16 @@ static void global_remove(void *data, struct wl_registry *registry, u32 name)
{
(void)data;
(void)registry;
- (void)name;
+ // @TODO: Untested.
+ for (u32 i = 0; i < global.monitors.count; i++) {
+ struct stl_monitor_wayland *monitor = (struct stl_monitor_wayland *)al_array_at(global.monitors, i);
+ if (monitor->wln == name) {
+ if (monitor->output) wl_output_destroy(monitor->output);
+ al_free(monitor);
+ al_array_remove_at_iter(global.monitors, i);
+ break;
+ }
+ }
}
static const struct wl_registry_listener registry_listener = {
@@ -302,7 +312,7 @@ bool stl_global_init(bool skip_graphics)
if (!skip_graphics) {
#if defined STELA_API_VULKAN
- global.vk_extensions = (const char **)al_calloc(2, sizeof(const char *const *));
+ global.vk_extensions = (const char **)al_calloc(2, sizeof(const char *));
global.vk_extensions[0] = "VK_KHR_surface";
global.vk_extensions[1] = "VK_KHR_wayland_surface";
#elif defined STELA_API_OPENGL
@@ -499,7 +509,7 @@ static void pointer_frame(void *data, struct wl_pointer *pointer)
struct stl_window_wayland *wl = (struct stl_window_wayland *)data;
(void)pointer;
if (wl->frame.pointer_x != FRAME_NO_VALUE && wl->frame.pointer_y != FRAME_NO_VALUE) {
- stl_window_send_pointer_pos_event(&wl->w, wl->frame.pointer_x, wl->frame.pointer_y);
+ stl_window_send_pointer_event(&wl->w, STELA_POINTER_POS, wl->frame.pointer_x, wl->frame.pointer_y);
wl->frame.pointer_x = FRAME_NO_VALUE;
wl->frame.pointer_y = FRAME_NO_VALUE;
}
@@ -708,6 +718,7 @@ static void context_global_add(void *data, struct wl_registry *registry, u32 nam
static void context_global_remove(void *data, struct wl_registry *registry, u32 name)
{
+ // @TODO: Probably need to handle seat here.
(void)data;
(void)registry;
(void)name;
@@ -1299,10 +1310,10 @@ static VkResult window_wayland_vk_destroy_surface(VkInstance inst, VkSurfaceKHR
return stl_vk_destroy_surface(inst, surface);
}
-static const char *const *window_wayland_vk_get_extensions(u32 *num)
+static const char * const *window_wayland_vk_get_extensions(u32 *num)
{
*num = 2;
- return global.vk_extensions;
+ return (const char * const *)global.vk_extensions;
}
#elif defined STELA_API_OPENGL
static bool window_wayland_gl_loader_load(void *window)
diff --git a/src/window_wayland.h b/src/window_wayland.h
index ad0f572..db20187 100644
--- a/src/window_wayland.h
+++ b/src/window_wayland.h
@@ -47,6 +47,7 @@ struct stl_wayland_global {
struct stl_monitor_wayland {
struct stl_monitor m;
+ u32 wln;
struct wl_output *output;
struct zxdg_output_v1 *xdg_output;
};
diff --git a/src/window_win32.c b/src/window_win32.c
index 3d5d2e8..e1cf137 100644
--- a/src/window_win32.c
+++ b/src/window_win32.c
@@ -108,10 +108,10 @@ static LRESULT CALLBACK ServiceWndProc(HWND Window, UINT Message, WPARAM WParam,
}
case DESTROY_DANGEROUS_WINDOW: {
struct stl_window_win32 *w32 = (struct stl_window_win32 *)WParam;
- if (!w32->Closed && !DestroyWindow(w32->Window)) {
+ al_assert(!w32->Closed);
+ if (!DestroyWindow(w32->Window)) {
log_error("Failed to destroy window (0x%lx).", GetLastError());
}
- UnregisterClassW(DangerousClass, Global.ModuleHandle);
break;
}
case EXIT_PROCESS:
@@ -660,6 +660,7 @@ static LRESULT CALLBACK DisplayWndProc(HWND Window, UINT Message, WPARAM WParam,
switch (Message) {
case WM_CREATE:
case WM_CLOSE:
+ case WM_DESTROY:
// Special case with Window as WParam.
PostThreadMessageW(MainThreadID, Message, (WPARAM)Window, LParam);
break;
@@ -684,55 +685,53 @@ static LRESULT CALLBACK DisplayWndProc(HWND Window, UINT Message, WPARAM WParam,
goto intercept;
case WM_LBUTTONUP:
w32->DragCapture = FALSE;
- ReleaseCapture();
+ if (!w32->WindowMoving) {
+ ReleaseCapture();
+ }
goto intercept;
case WM_RBUTTONDOWN:
case WM_NCRBUTTONDOWN:
#ifdef STELA_MOUSE2_DRAG
- if (!Global.IsWine) {
- POINT Pos;
- Pos.x = GET_X_LPARAM(LParam);
- Pos.y = GET_Y_LPARAM(LParam);
- if (Message == WM_RBUTTONDOWN) {
- ClientToScreen(w32->Window, &Pos);
- }
- w32->LastMousePos.x = Pos.x;
- w32->LastMousePos.y = Pos.y;
- w32->WindowMoving = TRUE;
- // DragCapture is a higher priority.
- if (!w32->DragCapture) {
- SetCapture(w32->Window);
+ if (!w32->w.fullscreen) {
+ if (!Global.IsWine) {
+ POINT Pos;
+ Pos.x = GET_X_LPARAM(LParam);
+ Pos.y = GET_Y_LPARAM(LParam);
+ if (Message == WM_RBUTTONDOWN) {
+ ClientToScreen(w32->Window, &Pos);
+ }
+ w32->LastMousePos.x = Pos.x;
+ w32->LastMousePos.y = Pos.y;
+ w32->WindowMoving = TRUE;
+ if (!GetCapture()) {
+ SetCapture(w32->Window);
+ }
+ } else {
+ /*
+ Message = WM_NCLBUTTONDOWN;
+ WParam = HTCAPTION;
+ */
+ // https://stackoverflow.com/a/35522584, incredible...
+ // https://gitlab.winehq.org/agusev/wine/-/blob/wine-971221/windows/nonclient.c#L1773
+ // This works on Wine but not Windows. Everything works the same, except on Windows
+ // it seems there is a special case for LBUTTON.
+ SendMessageW(w32->Window, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, LParam);
}
- return Result;
- } else {
- /*
- Message = WM_NCLBUTTONDOWN;
- WParam = HTCAPTION;
- */
- // https://stackoverflow.com/a/35522584, incredible...
- // https://gitlab.winehq.org/agusev/wine/-/blob/wine-971221/windows/nonclient.c#L1773
- // This works on Wine but not Windows. Everything works the same, except on Windows
- // it seems there is a special case for LBUTTON.
- SendMessageW(w32->Window, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, LParam);
}
- break;
-#else
- goto intercept;
#endif
+ goto intercept;
case WM_RBUTTONUP:
case WM_NCRBUTTONUP:
#ifdef STELA_MOUSE2_DRAG
- if (!Global.IsWine) {
+ if (!w32->w.fullscreen && !Global.IsWine) {
w32->WindowMoving = FALSE;
+ // DragCapture is a higher priority.
if (!w32->DragCapture) {
ReleaseCapture();
}
- return Result;
}
- break;
-#else
- goto intercept;
#endif
+ goto intercept;
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
goto intercept;
@@ -758,6 +757,8 @@ static LRESULT CALLBACK DisplayWndProc(HWND Window, UINT Message, WPARAM WParam,
return Result;
}
goto intercept;
+ case WM_INPUT:
+ goto intercept;
case WM_MOUSEWHEEL:
goto intercept;
case WM_ACTIVATE: // Don't use Wine behavior as a reference, it's too broken.
@@ -814,6 +815,10 @@ static LRESULT CALLBACK DisplayWndProc(HWND Window, UINT Message, WPARAM WParam,
ShowCursor(TRUE);
}
return 0;
+#ifdef STELA_DRAG_AND_DROP
+ case WM_DROPFILES:
+ goto intercept;
+#endif
default:
break;
}
@@ -893,15 +898,9 @@ static bool CreateWGLContext(struct stl_window_win32 *w32)
w32->GLContext = NULL;
if (CreateContextAttribsARB) {
for (u32 i = 0; i < ARRAY_SIZE(stl_gl_vers); i++) {
- s32 flags = stl_gl_vers[i].major >= 3 ? WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB : 0;
- s32 mask = 0;
- if (stl_gl_vers[i].api == STELA_GLES_API) {
- mask |= WGL_CONTEXT_ES2_PROFILE_BIT_EXT;
- } else {
- mask |= stl_gl_vers[i].profile == STELA_GL_CORE_PROFILE_BIT ?
- WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
- }
-
+ s32 flags = (stl_gl_vers[i].major >= 3) ? WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB : 0;
+ s32 mask = (stl_gl_vers[i].api == STELA_GLES_API) ? WGL_CONTEXT_ES2_PROFILE_BIT_EXT :
+ ((stl_gl_vers[i].profile == STELA_GL_CORE_PROFILE_BIT) ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);
s32 attribs[] = {
WGL_CONTEXT_FLAGS_ARB, flags,
WGL_CONTEXT_PROFILE_MASK_ARB, mask,
@@ -909,15 +908,12 @@ static bool CreateWGLContext(struct stl_window_win32 *w32)
WGL_CONTEXT_MINOR_VERSION_ARB, stl_gl_vers[i].minor,
0, 0
};
-
STELA_LOG_GL_CONTEXT_CREATION(stl_gl_vers[i]);
-
- w32->GLContext = CreateContextAttribsARB(w32->DeviceContext, NULL, attribs);
- if (w32->GLContext) break;
-
+ if ((w32->GLContext = CreateContextAttribsARB(w32->DeviceContext, NULL, attribs))) {
+ break;
+ }
log_warn("Failed to create context (0x%lx).", GetLastError());
}
-
wglDeleteContext(FakeContext);
wglMakeCurrent(w32->DeviceContext, w32->GLContext);
} else {
@@ -988,6 +984,21 @@ static bool window_win32_create_window(struct stl_window *window, u32 width, u32
return false;
}
+#define HID_USAGE_PAGE_GENERIC ((USHORT)0x01)
+#define HID_USAGE_GENERIC_MOUSE ((USHORT)0x02)
+ RAWINPUTDEVICE Rid[1];
+ Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
+ Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
+ Rid[0].dwFlags = 0;
+ Rid[0].hwndTarget = w32->Window;
+ if (!RegisterRawInputDevices(Rid, 1, sizeof(Rid[0]))) {
+ log_warn("Failed to register raw input mouse.");
+ }
+
+#ifdef STELA_DRAG_AND_DROP
+ DragAcceptFiles(w32->Window, TRUE);
+#endif
+
stl_window_created(&w32->w, width, height, flags);
w32->Closed = FALSE;
@@ -995,7 +1006,7 @@ static bool window_win32_create_window(struct stl_window *window, u32 width, u32
w32->UserDecorated = TRUE;
w32->Prev.Style = GetWindowLong(w32->Window, GWL_STYLE);
w32->Prev.ExStyle = GetWindowLong(w32->Window, GWL_EXSTYLE);
- w32->DragCapture = TRUE;
+ w32->DragCapture = FALSE;
w32->WindowMoving = FALSE;
w32->MouseButtonMask = 0;
@@ -1096,6 +1107,12 @@ static void window_win32_toggle_fullscreen(struct stl_window *window)
{
struct stl_window_win32 *w32 = (struct stl_window_win32 *)window;
if (!w32->w.fullscreen) {
+ if (w32->WindowMoving) {
+ w32->WindowMoving = FALSE;
+ if (!w32->DragCapture) {
+ ReleaseCapture();
+ }
+ }
RECT Prev;
GetWindowRect(w32->Window, &Prev);
// https://learn.microsoft.com/en-us/windows/win32/gdi/positioning-objects-on-a-multiple-display-setup
@@ -1165,8 +1182,10 @@ static void win32_handle_message(struct stl_window_win32 *w32, MSG *Message)
switch (Message->message) {
case WM_CREATE:
break;
- case WM_CLOSE:
+ case WM_CLOSE: // This is *not* sent by DestroyWindow().
w32->Closed = TRUE;
+ break;
+ case WM_DESTROY:
#ifdef STELA_API_OPENGL
wglDeleteContext(w32->GLContext); // Makes context not current.
#endif
@@ -1230,7 +1249,25 @@ static void win32_handle_message(struct stl_window_win32 *w32, MSG *Message)
if (Message->message == WM_NCMOUSEMOVE) {
ScreenToClient(w32->Window, &Pos);
}
- stl_window_send_pointer_pos_event(&w32->w, (f64)Pos.x, (f64)Pos.y);
+ stl_window_send_pointer_event(&w32->w, STELA_POINTER_POS, (f64)Pos.x, (f64)Pos.y);
+ break;
+ }
+ case WM_INPUT: {
+ UINT dwSize = sizeof(RAWINPUT);
+ BYTE lpb[sizeof(RAWINPUT)] = { 0 };
+ GetRawInputData((HRAWINPUT)Message->lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER));
+ RAWINPUT *raw = (RAWINPUT *)lpb;
+ if (raw->header.dwType == RIM_TYPEMOUSE) {
+ RAWMOUSE *mouse = &raw->data.mouse;
+ // This doesn't work from outside the WndProc on Wine (all zeros).
+ if (mouse->usFlags & MOUSE_MOVE_ABSOLUTE) {
+ } else {
+ if (mouse->lLastX != 0 || mouse->lLastY != 0) {
+ stl_window_send_pointer_event(&w32->w, STELA_POINTER_MOVE,
+ (f64)mouse->lLastX, (f64)mouse->lLastY);
+ }
+ }
+ }
break;
}
case WM_MOUSEWHEEL: {
@@ -1274,6 +1311,22 @@ static void win32_handle_message(struct stl_window_win32 *w32, MSG *Message)
w32->w.pending_refresh = true;
#endif
break;
+#ifdef STELA_DRAG_AND_DROP
+ case WM_DROPFILES: {
+ HDROP Drop = (HDROP)Message->wParam;
+ str path = AL_STR_EMPTY;
+ u32 count = DragQueryFileA(Drop, 0xffffffff, NULL, 0);
+ for (u32 i = 0; i < count; i++) {
+ path.length = DragQueryFileA(Drop, i, NULL, 0);
+ path.alloc = al_str_reserve(&path, path.length + 1);
+ DragQueryFileA(Drop, i, path.data, path.alloc);
+ stl_window_send_drag_and_drop_event(&w32->w, &path);
+ }
+ al_str_free(&path);
+ DragFinish(Drop);
+ break;
+ }
+#endif
default:
break;
}
@@ -1321,7 +1374,12 @@ static bool window_win32_should_refresh(struct stl_window *window)
static void window_win32_free(struct stl_window **window)
{
struct stl_window_win32 *w32 = (struct stl_window_win32 *)*window;
- SendMessageW(Global.ServiceWindow, DESTROY_DANGEROUS_WINDOW, (WPARAM)w32, 0);
+ if (!w32->Closed) {
+ SendMessageW(Global.ServiceWindow, DESTROY_DANGEROUS_WINDOW, (WPARAM)w32, 0);
+ // Hopefully get the WM_DESTROY event.
+ window_win32_process_events(&w32->w);
+ }
+ UnregisterClassW(DangerousClass, Global.ModuleHandle);
al_wstr_free(&w32->WindowName);
al_free(w32);
*window = NULL;
@@ -1387,7 +1445,7 @@ static void window_win32_gl_release_current(void *window)
{
struct stl_window_win32 *w32 = (struct stl_window_win32 *)window;
al_assert(w32->GLContext == w32->CurrentContext);
-#if 1
+#if 0 // Mimic our EGL behavior.
w32->CurrentContext = NULL;
wglMakeCurrent(w32->DeviceContext, NULL);
#endif
diff --git a/src/window_x11.c b/src/window_x11.c
index 17de7ae..6d9ef78 100644
--- a/src/window_x11.c
+++ b/src/window_x11.c
@@ -39,7 +39,7 @@ bool stl_global_init(bool skip_graphics)
if (!skip_graphics) {
#if defined STELA_API_VULKAN
- global.vk_extensions = (const char **)al_calloc(2, sizeof(const char *const *));
+ global.vk_extensions = (const char **)al_calloc(2, sizeof(const char *));
global.vk_extensions[0] = "VK_KHR_surface";
global.vk_extensions[1] = "VK_KHR_xlib_surface";
#elif defined STELA_API_OPENGL
@@ -60,14 +60,19 @@ bool stl_global_init(bool skip_graphics)
}
global.cursors[STELA_CURSOR_NORMAL] = None;
+ // Only cursors also defined by XC_* seem to work on Xwayland.
+ // https://tronche.com/gui/x/xlib/appendix/b/
+ global.cursors[STELA_CURSOR_CROSSHAIR] = XcursorLibraryLoadCursor(global.x11_d, "crosshair");
+ global.cursors[STELA_CURSOR_MOVE] = XcursorLibraryLoadCursor(global.x11_d, "hand2");
char *cursor_theme = XcursorGetTheme(global.x11_d);
s32 cursor_size = XcursorGetDefaultSize(global.x11_d);
- XcursorImage *image;
- if ((image = XcursorLibraryLoadImage("crosshair", cursor_theme, cursor_size))) {
+ XcursorImage *image = XcursorLibraryLoadImage("crosshair", cursor_theme, cursor_size);
+ if (image) {
global.cursors[STELA_CURSOR_CROSSHAIR] = XcursorImageLoadCursor(global.x11_d, image);
XcursorImageDestroy(image);
}
- if ((image = XcursorLibraryLoadImage("pointer", cursor_theme, cursor_size))) {
+ image = XcursorLibraryLoadImage("move", cursor_theme, cursor_size);
+ if (image) {
global.cursors[STELA_CURSOR_MOVE] = XcursorImageLoadCursor(global.x11_d, image);
XcursorImageDestroy(image);
}
@@ -535,7 +540,7 @@ static void handle_next_xevent(struct stl_window_x11 *xw)
case KeyRelease: {
KeySym sym = XkbKeycodeToKeysym(global.x11_d, xev.xkey.keycode, 0, 0);//(xev.xkey.state & ShiftMask) ? 1 : 0);
if (sym != NoSymbol) {
- u8 mapped_state = xev.type == KeyPress ? STELA_BUTTON_PRESSED : STELA_BUTTON_RELEASED;
+ u8 mapped_state = (xev.type == KeyPress) ? STELA_BUTTON_PRESSED : STELA_BUTTON_RELEASED;
u16 mapped_key = keysym_to_key(sym);
stl_window_send_key_immediate_event(&xw->w, mapped_state, mapped_key);
stl_window_send_key_event(&xw->w, mapped_state, mapped_key);
@@ -585,7 +590,7 @@ static void handle_next_xevent(struct stl_window_x11 *xw)
}
break;
case MotionNotify:
- stl_window_send_pointer_pos_event(&xw->w, (f64)xev.xmotion.x, (f64)xev.xmotion.y);
+ stl_window_send_pointer_event(&xw->w, STELA_POINTER_POS, (f64)xev.xmotion.x, (f64)xev.xmotion.y);
break;
case MapNotify:
break;
@@ -651,10 +656,10 @@ static VkResult window_x11_vk_destroy_surface(VkInstance inst, VkSurfaceKHR surf
return stl_vk_destroy_surface(inst, surface);
}
-static const char *const *window_x11_vk_get_extensions(u32 *num)
+static const char * const *window_x11_vk_get_extensions(u32 *num)
{
*num = 2;
- return global.vk_extensions;
+ return (const char * const *)global.vk_extensions;
}
#elif defined STELA_API_OPENGL
static bool window_x11_gl_loader_load(void *window)
diff --git a/subprojects/libalabaster.wrap b/subprojects/libalabaster.wrap
index c48903d..5323646 100644
--- a/subprojects/libalabaster.wrap
+++ b/subprojects/libalabaster.wrap
@@ -1,5 +1,5 @@
[wrap-git]
-directory = libalabaster-c633226
+directory = libalabaster-b617e3c
url = https://git.akon.city/libalabaster.git
-revision = c633226d2b615f46ef38cc99603775dccdf96ecd
+revision = b617e3ccb25a0ac3c22f8c02722c8108b2f78d6e
depth = 1
diff --git a/subprojects/libnaunet.wrap b/subprojects/libnaunet.wrap
index 63425dd..2c321b0 100644
--- a/subprojects/libnaunet.wrap
+++ b/subprojects/libnaunet.wrap
@@ -1,5 +1,5 @@
[wrap-git]
-directory = libnaunet-a389b8f
+directory = libnaunet-3a51988
url = https://git.akon.city/libnaunet.git
-revision = a389b8f2f9c55b76fe5a28c3f1fea798ed37aa98
+revision = 3a51988d764d54723288dc31a1779ece44cac1e9
depth = 1
diff --git a/tests/window.c b/tests/window.c
index 7ce154c..8dc9c19 100644
--- a/tests/window.c
+++ b/tests/window.c
@@ -6,7 +6,11 @@
#include <al/math.h>
#include <nnwt/common.h>
#include <stl/window.h>
+#ifdef STELA_API_OPENGL
#include <stl/gl.h>
+#else
+typedef f32 GLfloat;
+#endif
#define DEFAULT_WIDTH 720
#define DEFAULT_HEIGHT 480
@@ -22,9 +26,10 @@ static const GLfloat init_rotation[] = { -25.f, 35.f, 0.f };
static GLfloat rotation[] = { init_rotation[0], init_rotation[1], init_rotation[2] };
static GLfloat zoom = 0.5f;
-static bool pointer_pos_callback(void *userdata, f64 x, f64 y)
+static bool pointer_callback(void *userdata, u8 type, f64 x, f64 y)
{
(void)userdata;
+ (void)type;
// There's probably a "standard" way to handle dragging here
// but this works well enough.
@@ -34,7 +39,7 @@ static bool pointer_pos_callback(void *userdata, f64 x, f64 y)
dx /= 2.f;
dy /= 2.f;
rotation[0] += dy;
- rotation[1] += rotation[0] > 140.f && rotation[0] < 290.f ? -dx : dx;
+ rotation[1] += (rotation[0] > 140.f && rotation[0] < 290.f) ? -dx : dx;
if (rotation[0] > 360.f) rotation[0] -= 360.f;
else if (rotation[0] < 0.f) rotation[0] += 360.f;
if (rotation[1] > 360.f) rotation[1] -= 360.f;
@@ -171,7 +176,7 @@ s32 window_system_main(u32 argc, str *argv, void *extra)
(void)extra;
window = stl_window_create();
- window->pointer_pos_callback = pointer_pos_callback;
+ window->pointer_callback = pointer_callback;
window->scroll_callback = scroll_callback;
window->mouse_button_callback = mouse_button_callback;
window->key_callback = key_callback;
@@ -204,6 +209,9 @@ s32 window_system_main(u32 argc, str *argv, void *extra)
if (argc > 1 && al_str_cmp(&argv[1], &al_str_c("w"), 0, 1) == 0) {
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
}
+#else
+ (void)argc;
+ (void)argv;
#endif
while (!quit) {