summaryrefslogtreecommitdiff
path: root/src/window_win32.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/window_win32.c')
-rw-r--r--src/window_win32.c168
1 files changed, 113 insertions, 55 deletions
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