mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-23 20:57:12 -04:00
Finish porting WinGLNative to C.
This commit is contained in:
parent
44ec23c931
commit
d6a8b7d35c
@ -339,11 +339,7 @@ namespace OpenTK.Platform.Windows
|
|||||||
if (Closing != null)
|
if (Closing != null)
|
||||||
Closing(this, e);
|
Closing(this, e);
|
||||||
|
|
||||||
if (!e.Cancel)
|
if (!e.Cancel) {
|
||||||
{
|
|
||||||
if (Unload != null)
|
|
||||||
Unload(this, EventArgs.Empty);
|
|
||||||
|
|
||||||
DestroyWindow();
|
DestroyWindow();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -403,7 +399,7 @@ namespace OpenTK.Platform.Windows
|
|||||||
wc.Icon = Icon != null ? Icon.Handle : IntPtr.Zero;
|
wc.Icon = Icon != null ? Icon.Handle : IntPtr.Zero;
|
||||||
#warning "This seems to resize one of the 'large' icons, rather than using a small icon directly (multi-icon files). Investigate!"
|
#warning "This seems to resize one of the 'large' icons, rather than using a small icon directly (multi-icon files). Investigate!"
|
||||||
wc.IconSm = Icon != null ? new Icon(Icon, 16, 16).Handle : IntPtr.Zero;
|
wc.IconSm = Icon != null ? new Icon(Icon, 16, 16).Handle : IntPtr.Zero;
|
||||||
wc.Cursor = API.LoadCursor(IntPtr.Zero, (IntPtr)32512); // CursorName.Arrow
|
//wc.Cursor = API.LoadCursor(IntPtr.Zero, (IntPtr)32512); // CursorName.Arrow
|
||||||
ushort atom = API.RegisterClassEx(ref wc);
|
ushort atom = API.RegisterClassEx(ref wc);
|
||||||
|
|
||||||
if (atom == 0)
|
if (atom == 0)
|
||||||
@ -701,8 +697,6 @@ namespace OpenTK.Platform.Windows
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public event EventHandler<EventArgs> Load;
|
|
||||||
public event EventHandler<EventArgs> Unload;
|
|
||||||
public event EventHandler<EventArgs> Move;
|
public event EventHandler<EventArgs> Move;
|
||||||
public event EventHandler<EventArgs> Resize;
|
public event EventHandler<EventArgs> Resize;
|
||||||
public event EventHandler<System.ComponentModel.CancelEventArgs> Closing;
|
public event EventHandler<System.ComponentModel.CancelEventArgs> Closing;
|
||||||
|
@ -10,10 +10,22 @@ bool Rectangle2D_Contains(Rectangle2D a, Int32 x, Int32 y) {
|
|||||||
return x >= a.X && y >= a.Y && x < (a.X + a.Width) && y < (a.Y + a.Height);
|
return x >= a.X && y >= a.Y && x < (a.X + a.Width) && y < (a.Y + a.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Rectangle2D_Equals(Rectangle2D a, Rectangle2D b) {
|
||||||
|
return a.X == b.X && a.Y == b.Y && a.Width == b.Width && a.Height == b.Height;
|
||||||
|
}
|
||||||
|
|
||||||
Size2D Size2D_Make(Int32 width, Int32 height) {
|
Size2D Size2D_Make(Int32 width, Int32 height) {
|
||||||
Size2D s; s.Width = width; s.Height = height; return s;
|
Size2D s; s.Width = width; s.Height = height; return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Size2D_Equals(Size2D a, Size2D b) {
|
||||||
|
return a.Width == b.Width && a.Height == b.Height;
|
||||||
|
}
|
||||||
|
|
||||||
Point2D Point2D_Make(Int32 x, Int32 y) {
|
Point2D Point2D_Make(Int32 x, Int32 y) {
|
||||||
Point2D p; p.X = x; p.Y = y; return p;
|
Point2D p; p.X = x; p.Y = y; return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Point2D_Equals(Point2D a, Point2D b) {
|
||||||
|
return a.X == b.X && a.Y == b.Y;
|
||||||
}
|
}
|
@ -13,6 +13,9 @@ typedef struct Rectangle2D_ {
|
|||||||
Int32 Width, Height;
|
Int32 Width, Height;
|
||||||
} Rectangle2D;
|
} Rectangle2D;
|
||||||
|
|
||||||
|
/* Empty 2D rectangle. */
|
||||||
|
Rectangle2D Rectangle2D_Empty;
|
||||||
|
|
||||||
/* Stores a coordinate in 2D space.*/
|
/* Stores a coordinate in 2D space.*/
|
||||||
typedef struct Point2D_ {
|
typedef struct Point2D_ {
|
||||||
Int32 X, Y;
|
Int32 X, Y;
|
||||||
@ -30,9 +33,18 @@ Rectangle2D Rectangle2D_Make(Int32 x, Int32 y, Int32 width, Int32 height);
|
|||||||
/* Returns whether the given rectangle contains the given point. */
|
/* Returns whether the given rectangle contains the given point. */
|
||||||
bool Rectangle2D_Contains(Rectangle2D a, Int32 x, Int32 y);
|
bool Rectangle2D_Contains(Rectangle2D a, Int32 x, Int32 y);
|
||||||
|
|
||||||
|
/* Returns whether the two rectangles are equal. */
|
||||||
|
bool Rectangle2D_Equals(Rectangle2D a, Rectangle2D b);
|
||||||
|
|
||||||
/* Creates a new size. */
|
/* Creates a new size. */
|
||||||
Size2D Size2D_Make(Int32 width, Int32 height);
|
Size2D Size2D_Make(Int32 width, Int32 height);
|
||||||
|
|
||||||
|
/* Returns whether the two sizes are equal. */
|
||||||
|
bool Size2D_Equals(Size2D a, Size2D b);
|
||||||
|
|
||||||
/* Creates a new point. */
|
/* Creates a new point. */
|
||||||
Point2D Point2D_Make(Int32 x, Int32 y);
|
Point2D Point2D_Make(Int32 x, Int32 y);
|
||||||
|
|
||||||
|
/* Returns whether the two points are equal. */
|
||||||
|
bool Point2D_Equals(Point2D a, Point2D b);
|
||||||
#endif
|
#endif
|
@ -1,9 +1,17 @@
|
|||||||
#include "Typedefs.h"
|
#include "Typedefs.h"
|
||||||
#include "ErrorHandler.h"
|
#include "ErrorHandler.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
#include "Window.h"
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
ErrorHandler_Init();
|
ErrorHandler_Init();
|
||||||
Platform_Init();
|
Platform_Init();
|
||||||
|
|
||||||
|
Window_Create(0, 0, 320, 320, "TEST", NULL);
|
||||||
|
Window_SetVisible(true);
|
||||||
|
while (true) {
|
||||||
|
Window_ProcessEvents();
|
||||||
|
Platform_ThreadSleep(100);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
HINSTANCE win_Instance;
|
HINSTANCE win_Instance;
|
||||||
HWND win_Handle;
|
HWND win_Handle;
|
||||||
|
HDC win_DC;
|
||||||
WindowState win_State = WindowState_Normal;
|
WindowState win_State = WindowState_Normal;
|
||||||
bool win_Exists, win_Focused;
|
bool win_Exists, win_Focused;
|
||||||
bool mouse_outside_window = true;
|
bool mouse_outside_window = true;
|
||||||
@ -24,41 +25,157 @@ Rectangle2D win_Bounds;
|
|||||||
Rectangle2D win_ClientRect;
|
Rectangle2D win_ClientRect;
|
||||||
Rectangle2D previous_bounds; // Used to restore previous size when leaving fullscreen mode.
|
Rectangle2D previous_bounds; // Used to restore previous size when leaving fullscreen mode.
|
||||||
|
|
||||||
void Window_Create(Int32 x, Int32 y, Int32 width, Int32 height, STRING_TRANSIENT String* title, DisplayDevice* device) {
|
Rectangle2D Window_FromRect(RECT rect) {
|
||||||
win_Instance = GetModuleHandleA(NULL);
|
Rectangle2D r;
|
||||||
/* TODO: UngroupFromTaskbar(); */
|
r.X = rect.left; r.Y = rect.top;
|
||||||
|
r.Width = RECT_WIDTH(rect);
|
||||||
/* Find out the final window rectangle, after the WM has added its chrome (titlebar, sidebars etc). */
|
r.Height = RECT_HEIGHT(rect);
|
||||||
RECT rect; rect.left = x; rect.top = y; rect.right = x + width; rect.bottom = y + height;
|
return r;
|
||||||
AdjustWindowRectEx(&rect, win_Style, false, win_StyleEx);
|
|
||||||
|
|
||||||
WNDCLASSEXA wc;
|
|
||||||
Platform_MemSet(&wc, 0, sizeof(WNDCLASSEXA));
|
|
||||||
wc.cbSize = sizeof(WNDCLASSEXA);
|
|
||||||
wc.style = CS_OWNDC;
|
|
||||||
wc.hInstance = win_Instance;
|
|
||||||
wc.lpfnWndProc = Window_Procedure;
|
|
||||||
wc.lpszClassName = win_ClassName;
|
|
||||||
/* TODO: Set window icons here */
|
|
||||||
wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
|
|
||||||
|
|
||||||
ATOM atom = RegisterClassExA(&wc);
|
|
||||||
if (atom == 0) {
|
|
||||||
ErrorHandler_FailWithCode(GetLastError(), "Failed to register window class");
|
|
||||||
}
|
|
||||||
|
|
||||||
win_Handle = CreateWindowExA(
|
|
||||||
win_StyleEx, win_ClassName, title->buffer, win_Style,
|
|
||||||
rect.left, rect.top, RECT_WIDTH(rect), RECT_HEIGHT(rect),
|
|
||||||
NULL, NULL, win_Instance, NULL);
|
|
||||||
|
|
||||||
if (win_Handle == NULL) {
|
|
||||||
ErrorHandler_FailWithCode(GetLastError(), "Failed to create window");
|
|
||||||
}
|
|
||||||
win_Exists = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WNDPROC Window_Procedure(HWND handle, UINT message, WPARAM wParam, LPARAM lParam) {
|
|
||||||
|
void Window_Destroy(void) {
|
||||||
|
if (!win_Exists) return;
|
||||||
|
|
||||||
|
DestroyWindow(win_Handle);
|
||||||
|
win_Exists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window_ResetWindowState(void) {
|
||||||
|
suppress_resize++;
|
||||||
|
Window_SetWindowState(WindowState_Normal);
|
||||||
|
Window_ProcessEvents();
|
||||||
|
suppress_resize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool win_hiddenBorder;
|
||||||
|
void Window_DoSetHiddenBorder(bool value) {
|
||||||
|
if (win_hiddenBorder == value) return;
|
||||||
|
|
||||||
|
/* We wish to avoid making an invisible window visible just to change the border.
|
||||||
|
However, it's a good idea to make a visible window invisible temporarily, to
|
||||||
|
avoid garbage caused by the border change. */
|
||||||
|
bool was_visible = Window_GetVisible();
|
||||||
|
|
||||||
|
/* To ensure maximized/minimized windows work correctly, reset state to normal,
|
||||||
|
change the border, then go back to maximized/minimized. */
|
||||||
|
WindowState state = win_State;
|
||||||
|
Window_ResetWindowState();
|
||||||
|
DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
||||||
|
style |= (value ? WS_POPUP : WS_OVERLAPPEDWINDOW);
|
||||||
|
|
||||||
|
/* Make sure client size doesn't change when changing the border style.*/
|
||||||
|
RECT rect;
|
||||||
|
rect.left = win_Bounds.X; rect.top = win_Bounds.Y;
|
||||||
|
rect.right = rect.left + win_Bounds.Width;
|
||||||
|
rect.bottom = rect.top + win_Bounds.Height;
|
||||||
|
AdjustWindowRectEx(&rect, style, false, win_StyleEx);
|
||||||
|
|
||||||
|
/* This avoids leaving garbage on the background window. */
|
||||||
|
if (was_visible) Window_SetVisible(false);
|
||||||
|
|
||||||
|
SetWindowLongA(win_Handle, GWL_STYLE, style);
|
||||||
|
SetWindowPos(win_Handle, NULL, 0, 0, RECT_WIDTH(rect), RECT_HEIGHT(rect),
|
||||||
|
SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
||||||
|
|
||||||
|
/* Force window to redraw update its borders, but only if it's
|
||||||
|
already visible (invisible windows will change borders when
|
||||||
|
they become visible, so no need to make them visiable prematurely).*/
|
||||||
|
if (was_visible) Window_SetVisible(true);
|
||||||
|
|
||||||
|
Window_SetWindowState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window_SetHiddenBorder(bool hidden) {
|
||||||
|
suppress_resize++;
|
||||||
|
Window_DoSetHiddenBorder(hidden);
|
||||||
|
Window_ProcessEvents();
|
||||||
|
suppress_resize--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window_EnableMouseTracking(void) {
|
||||||
|
TRACKMOUSEEVENT me;
|
||||||
|
Platform_MemSet(&me, 0, sizeof(TRACKMOUSEEVENT));
|
||||||
|
me.cbSize = sizeof(TRACKMOUSEEVENT);
|
||||||
|
me.hwndTrack = win_Handle;
|
||||||
|
me.dwFlags = TME_LEAVE;
|
||||||
|
|
||||||
|
if (!TrackMouseEvent(&me)) {
|
||||||
|
ErrorHandler_FailWithCode(GetLastError(), "Enabling mouse tracking");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Key Window_MapKey(WPARAM key) {
|
||||||
|
if (key >= VK_F1 && key <= VK_F24) {
|
||||||
|
return Key_F1 + (key - VK_F1);
|
||||||
|
}
|
||||||
|
if (key >= '0' && key <= '9') {
|
||||||
|
return Key_Number0 + (key - '0');
|
||||||
|
}
|
||||||
|
if (key >= 'A' && key <= 'Z') {
|
||||||
|
return Key_A + (key - 'A');
|
||||||
|
}
|
||||||
|
if (key >= VK_NUMPAD0 && key <= VK_NUMPAD9) {
|
||||||
|
return Key_Keypad0 + (key - VK_NUMPAD0);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case VK_ESCAPE: return Key_Escape;
|
||||||
|
case VK_TAB: return Key_Tab;
|
||||||
|
case VK_CAPITAL: return Key_CapsLock;
|
||||||
|
case VK_LCONTROL: return Key_ControlLeft;
|
||||||
|
case VK_LSHIFT: return Key_ShiftLeft;
|
||||||
|
case VK_LWIN: return Key_WinLeft;
|
||||||
|
case VK_LMENU: return Key_AltLeft;
|
||||||
|
case VK_SPACE: return Key_Space;
|
||||||
|
case VK_RMENU: return Key_AltRight;
|
||||||
|
case VK_RWIN: return Key_WinRight;
|
||||||
|
case VK_APPS: return Key_Menu;
|
||||||
|
case VK_RCONTROL: return Key_ControlRight;
|
||||||
|
case VK_RSHIFT: return Key_ShiftRight;
|
||||||
|
case VK_RETURN: return Key_Enter;
|
||||||
|
case VK_BACK: return Key_BackSpace;
|
||||||
|
|
||||||
|
case VK_OEM_1: return Key_Semicolon; /* Varies by keyboard: return ;: on Win2K/US */
|
||||||
|
case VK_OEM_2: return Key_Slash; /* Varies by keyboard: return /? on Win2K/US */
|
||||||
|
case VK_OEM_3: return Key_Tilde; /* Varies by keyboard: return `~ on Win2K/US */
|
||||||
|
case VK_OEM_4: return Key_BracketLeft; /* Varies by keyboard: return [{ on Win2K/US */
|
||||||
|
case VK_OEM_5: return Key_BackSlash; /* Varies by keyboard: return \| on Win2K/US */
|
||||||
|
case VK_OEM_6: return Key_BracketRight; /* Varies by keyboard: return ]} on Win2K/US */
|
||||||
|
case VK_OEM_7: return Key_Quote; /* Varies by keyboard: return '" on Win2K/US */
|
||||||
|
case VK_OEM_PLUS: return Key_Plus; /* Invariant: + */
|
||||||
|
case VK_OEM_COMMA: return Key_Comma; /* Invariant: : return */
|
||||||
|
case VK_OEM_MINUS: return Key_Minus; /* Invariant: - */
|
||||||
|
case VK_OEM_PERIOD: return Key_Period; /* Invariant: . */
|
||||||
|
|
||||||
|
case VK_HOME: return Key_Home;
|
||||||
|
case VK_END: return Key_End;
|
||||||
|
case VK_DELETE: return Key_Delete;
|
||||||
|
case VK_PRIOR: return Key_PageUp;
|
||||||
|
case VK_NEXT: return Key_PageDown;
|
||||||
|
case VK_PRINT: return Key_PrintScreen;
|
||||||
|
case VK_PAUSE: return Key_Pause;
|
||||||
|
case VK_NUMLOCK: return Key_NumLock;
|
||||||
|
|
||||||
|
case VK_SCROLL: return Key_ScrollLock;
|
||||||
|
case VK_SNAPSHOT: return Key_PrintScreen;
|
||||||
|
case VK_INSERT: return Key_Insert;
|
||||||
|
|
||||||
|
case VK_DECIMAL: return Key_KeypadDecimal;
|
||||||
|
case VK_ADD: return Key_KeypadAdd;
|
||||||
|
case VK_SUBTRACT: return Key_KeypadSubtract;
|
||||||
|
case VK_DIVIDE: return Key_KeypadDivide;
|
||||||
|
case VK_MULTIPLY: return Key_KeypadMultiply;
|
||||||
|
|
||||||
|
case VK_UP: return Key_Up;
|
||||||
|
case VK_DOWN: return Key_Down;
|
||||||
|
case VK_LEFT: return Key_Left;
|
||||||
|
case VK_RIGHT: return Key_Right;
|
||||||
|
}
|
||||||
|
return Key_Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK Window_Procedure(HWND handle, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||||
bool new_focused_state;
|
bool new_focused_state;
|
||||||
Real32 wheel_delta;
|
Real32 wheel_delta;
|
||||||
WORD mouse_x, mouse_y;
|
WORD mouse_x, mouse_y;
|
||||||
@ -73,7 +190,7 @@ WNDPROC Window_Procedure(HWND handle, UINT message, WPARAM wParam, LPARAM lParam
|
|||||||
switch (message) {
|
switch (message) {
|
||||||
|
|
||||||
case WM_ACTIVATE:
|
case WM_ACTIVATE:
|
||||||
new_focused_state = LOWORD(wParam);
|
new_focused_state = LOWORD(wParam) != 0;
|
||||||
if (new_focused_state != win_Focused) {
|
if (new_focused_state != win_Focused) {
|
||||||
win_Focused = new_focused_state;
|
win_Focused = new_focused_state;
|
||||||
Event_RaiseVoid(&WindowEvents_OnFocusedChanged);
|
Event_RaiseVoid(&WindowEvents_OnFocusedChanged);
|
||||||
@ -93,18 +210,18 @@ WNDPROC Window_Procedure(HWND handle, UINT message, WPARAM wParam, LPARAM lParam
|
|||||||
pos = (WINDOWPOS*)lParam;
|
pos = (WINDOWPOS*)lParam;
|
||||||
if (pos->hwnd == win_Handle) {
|
if (pos->hwnd == win_Handle) {
|
||||||
Point2D new_location = Point2D_Make(pos->x, pos->y);
|
Point2D new_location = Point2D_Make(pos->x, pos->y);
|
||||||
if (Location != new_location) {
|
if (!Point2D_Equals(Window_GetLocation(), new_location)) {
|
||||||
win_Bounds.X = pos->x; win_Bounds.Y = pos->y;
|
win_Bounds.X = pos->x; win_Bounds.Y = pos->y;
|
||||||
Event_RaiseVoid(&WindowEvents_OnMove);
|
Event_RaiseVoid(&WindowEvents_OnMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
Size2D new_size = Size2D_Make(pos->cx, pos->cy);
|
Size2D new_size = Size2D_Make(pos->cx, pos->cy);
|
||||||
if (Size != new_size) {
|
if (!Size2D_Equals(Window_GetSize(), new_size)) {
|
||||||
win_Bounds.Width = pos->cx; win_Bounds.Height = pos->cy;
|
win_Bounds.Width = pos->cx; win_Bounds.Height = pos->cy;
|
||||||
|
|
||||||
RECT rect;
|
RECT rect;
|
||||||
GetClientRect(handle, &rect);
|
GetClientRect(handle, &rect);
|
||||||
client_rectangle = rect.ToRectangle();
|
win_ClientRect = Window_FromRect(rect);
|
||||||
|
|
||||||
SetWindowPos(win_Handle, NULL,
|
SetWindowPos(win_Handle, NULL,
|
||||||
win_Bounds.X, win_Bounds.Y, win_Bounds.Width, win_Bounds.Height,
|
win_Bounds.X, win_Bounds.Y, win_Bounds.Width, win_Bounds.Height,
|
||||||
@ -156,7 +273,7 @@ WNDPROC Window_Procedure(HWND handle, UINT message, WPARAM wParam, LPARAM lParam
|
|||||||
if (mouse_outside_window) {
|
if (mouse_outside_window) {
|
||||||
/* Once we receive a mouse move event, it means that the mouse has re-entered the window. */
|
/* Once we receive a mouse move event, it means that the mouse has re-entered the window. */
|
||||||
mouse_outside_window = false;
|
mouse_outside_window = false;
|
||||||
EnableMouseTracking();
|
Window_EnableMouseTracking();
|
||||||
Event_RaiseVoid(&WindowEvents_OnMouseEnter);
|
Event_RaiseVoid(&WindowEvents_OnMouseEnter);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -280,59 +397,59 @@ WNDPROC Window_Procedure(HWND handle, UINT message, WPARAM wParam, LPARAM lParam
|
|||||||
|
|
||||||
RECT rect;
|
RECT rect;
|
||||||
GetClientRect(handle, &rect);
|
GetClientRect(handle, &rect);
|
||||||
win_ClientRect = rect.ToRectangle();
|
win_ClientRect = Window_FromRect(rect);
|
||||||
invisible_since_creation = true;
|
invisible_since_creation = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_CLOSE:
|
case WM_CLOSE:
|
||||||
Event_RaiseVoid(&WindowEvents_OnClosing);
|
Event_RaiseVoid(&WindowEvents_OnClosing);
|
||||||
if (Unload != null)
|
Window_Destroy();
|
||||||
Unload(this, EventArgs.Empty);
|
|
||||||
DestroyWindow();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WM_DESTROY:
|
case WM_DESTROY:
|
||||||
win_Exists = false;
|
win_Exists = false;
|
||||||
UnregisterClassA(win_ClassName, win_Instance);
|
UnregisterClassA(win_ClassName, win_Instance);
|
||||||
window.Dispose();
|
if (win_DC != NULL) ReleaseDC(win_Handle, win_DC);
|
||||||
Event_RaiseVoid(&WindowEvents_OnClosed);
|
Event_RaiseVoid(&WindowEvents_OnClosed);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return DefWindowProcA(handle, message, wParam, lParam);
|
return DefWindowProcA(handle, message, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window_EnableMouseTracking(void) {
|
|
||||||
TRACKMOUSEEVENT me;
|
|
||||||
Platform_MemSet(&me, 0, sizeof(TRACKMOUSEEVENT));
|
|
||||||
me.cbSize = sizeof(TRACKMOUSEEVENT);
|
|
||||||
me.hwndTrack = win_Handle;
|
|
||||||
me.dwFlags = TME_LEAVE;
|
|
||||||
|
|
||||||
if (!TrackMouseEvent(&me)) {
|
void Window_Create(Int32 x, Int32 y, Int32 width, Int32 height, STRING_TRANSIENT String* title, DisplayDevice* device) {
|
||||||
ErrorHandler_FailWithCode(GetLastError(), "Enabling mouse tracking");
|
win_Instance = GetModuleHandleA(NULL);
|
||||||
|
/* TODO: UngroupFromTaskbar(); */
|
||||||
|
|
||||||
|
/* Find out the final window rectangle, after the WM has added its chrome (titlebar, sidebars etc). */
|
||||||
|
RECT rect; rect.left = x; rect.top = y; rect.right = x + width; rect.bottom = y + height;
|
||||||
|
AdjustWindowRectEx(&rect, win_Style, false, win_StyleEx);
|
||||||
|
|
||||||
|
WNDCLASSEXA wc;
|
||||||
|
Platform_MemSet(&wc, 0, sizeof(WNDCLASSEXA));
|
||||||
|
wc.cbSize = sizeof(WNDCLASSEXA);
|
||||||
|
wc.style = CS_OWNDC;
|
||||||
|
wc.hInstance = win_Instance;
|
||||||
|
wc.lpfnWndProc = Window_Procedure;
|
||||||
|
wc.lpszClassName = win_ClassName;
|
||||||
|
/* TODO: Set window icons here */
|
||||||
|
wc.hCursor = LoadCursorA(NULL, IDC_ARROW);
|
||||||
|
|
||||||
|
ATOM atom = RegisterClassExA(&wc);
|
||||||
|
if (atom == 0) {
|
||||||
|
ErrorHandler_FailWithCode(GetLastError(), "Failed to register window class");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Window_Destroy(void) {
|
win_Handle = CreateWindowExA(
|
||||||
if (!win_Exists) return;
|
win_StyleEx, win_ClassName, title->buffer, win_Style,
|
||||||
|
rect.left, rect.top, RECT_WIDTH(rect), RECT_HEIGHT(rect),
|
||||||
DestroyWindow(win_Handle);
|
NULL, NULL, win_Instance, NULL);
|
||||||
win_Exists = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window_SetHiddenBorder(bool hidden) {
|
if (win_Handle == NULL) {
|
||||||
suppress_resize++;
|
ErrorHandler_FailWithCode(GetLastError(), "Failed to create window");
|
||||||
Window_DoSetHiddenBorder(hidden);
|
}
|
||||||
Window_ProcessEvents();
|
win_Exists = true;
|
||||||
suppress_resize--;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window_ResetWindowState(void) {
|
|
||||||
suppress_resize++;
|
|
||||||
Window_SetWindowState(WindowState_Normal);
|
|
||||||
Window_ProcessEvents();
|
|
||||||
suppress_resize--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window_GetClipboardText(STRING_TRANSIENT String* value) {
|
void Window_GetClipboardText(STRING_TRANSIENT String* value) {
|
||||||
@ -360,7 +477,7 @@ void Window_GetClipboardText(STRING_TRANSIENT String* value) {
|
|||||||
String_Append(value, Convert_UnicodeToCP437(*text)); text++;
|
String_Append(value, Convert_UnicodeToCP437(*text)); text++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UInt8* text = (UInt16*)src;
|
UInt8* text = (UInt8*)src;
|
||||||
while (*text != 0) {
|
while (*text != 0) {
|
||||||
String_Append(value, *text); text++;
|
String_Append(value, *text); text++;
|
||||||
}
|
}
|
||||||
@ -400,6 +517,7 @@ void Window_SetClipboardText(STRING_TRANSIENT String* value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Rectangle2D Window_GetBounds(void) { return win_Bounds; }
|
Rectangle2D Window_GetBounds(void) { return win_Bounds; }
|
||||||
void Window_SetBounds(Rectangle2D rect) {
|
void Window_SetBounds(Rectangle2D rect) {
|
||||||
/* Note: the bounds variable is updated when the resize/move message arrives.*/
|
/* Note: the bounds variable is updated when the resize/move message arrives.*/
|
||||||
@ -422,35 +540,36 @@ void Window_SetClientRectangle(Rectangle2D rect) {
|
|||||||
Window_SetClientSize(size);
|
Window_SetClientSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Size2D Window_GetClientSize(void) {
|
Size2D Window_GetClientSize(void) {
|
||||||
return Size2D_Make(win_ClientRect.Width, win_ClientRect.Height);
|
return Size2D_Make(win_ClientRect.Width, win_ClientRect.Height);
|
||||||
}
|
}
|
||||||
void Window_SetClientSize(Size2D size) {
|
void Window_SetClientSize(Size2D size) {
|
||||||
DWORD style = GetWindowLongA(win_Handle, GWL_STYLE);
|
DWORD style = GetWindowLongA(win_Handle, GWL_STYLE);
|
||||||
RECT rect;
|
RECT rect;
|
||||||
rect.left = 0; rect.top = 0;
|
rect.left = 0; rect.top = 0;
|
||||||
rect.right = size.Width; rect.bottom = size.Height;
|
rect.right = size.Width; rect.bottom = size.Height;
|
||||||
|
|
||||||
AdjustWindowRect(&rect, style, false);
|
AdjustWindowRect(&rect, style, false);
|
||||||
Window_SetSize(Size2D_Make(RECT_WIDTH(rect), RECT_HEIGHT(rect)));
|
Window_SetSize(Size2D_Make(RECT_WIDTH(rect), RECT_HEIGHT(rect)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Set window icon
|
/* TODO: Set window icon
|
||||||
public Icon Icon{
|
public Icon Icon{
|
||||||
get{ return icon; }
|
get{ return icon; }
|
||||||
set{
|
set{
|
||||||
icon = value;
|
icon = value;
|
||||||
if (window.handle != IntPtr.Zero)
|
if (window.handle != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
//Icon small = new Icon( value, 16, 16 );
|
//Icon small = new Icon( value, 16, 16 );
|
||||||
//GC.KeepAlive( small );
|
//GC.KeepAlive( small );
|
||||||
API.SendMessage(window.handle, WM_SETICON, (IntPtr)0, icon == null ? IntPtr.Zero : value.Handle);
|
API.SendMessage(window.handle, WM_SETICON, (IntPtr)0, icon == null ? IntPtr.Zero : value.Handle);
|
||||||
API.SendMessage(window.handle, WM_SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : value.Handle);
|
API.SendMessage(window.handle, WM_SETICON, (IntPtr)1, icon == null ? IntPtr.Zero : value.Handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
bool Window_GetFocused(void) { return win_Focused; }
|
bool Window_GetFocused(void) { return win_Focused; }
|
||||||
|
bool Window_GetExists(void) { return win_Exists; }
|
||||||
|
|
||||||
bool Window_GetVisible(void) { return IsWindowVisible(win_Handle); }
|
bool Window_GetVisible(void) { return IsWindowVisible(win_Handle); }
|
||||||
void Window_SetVisible(bool visible) {
|
void Window_SetVisible(bool visible) {
|
||||||
@ -460,19 +579,19 @@ void Window_SetVisible(bool visible) {
|
|||||||
BringWindowToTop(win_Handle);
|
BringWindowToTop(win_Handle);
|
||||||
SetForegroundWindow(win_Handle);
|
SetForegroundWindow(win_Handle);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
ShowWindow(win_Handle, SW_HIDE);
|
ShowWindow(win_Handle, SW_HIDE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Window_GetExists(void) { return win_Exists; }
|
|
||||||
|
|
||||||
void Window_Close(void) {
|
void Window_Close(void) {
|
||||||
PostMessageA(win_Handle, WM_CLOSE, NULL, NULL);
|
PostMessageA(win_Handle, WM_CLOSE, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowState Window_GetState(void) { return win_State; }
|
WindowState Window_GetWindowState(void) { return win_State; }
|
||||||
void Window_SetState(WindowState value) {
|
void Window_SetWindowState(WindowState value) {
|
||||||
if (win_State == value) return;
|
if (win_State == value) return;
|
||||||
|
|
||||||
DWORD command = 0;
|
DWORD command = 0;
|
||||||
@ -489,7 +608,7 @@ void Window_SetState(WindowState value) {
|
|||||||
|
|
||||||
case WindowState_Maximized:
|
case WindowState_Maximized:
|
||||||
/* Reset state to avoid strange interactions with fullscreen/minimized windows. */
|
/* Reset state to avoid strange interactions with fullscreen/minimized windows. */
|
||||||
ResetWindowState();
|
Window_ResetWindowState();
|
||||||
command = SW_MAXIMIZE;
|
command = SW_MAXIMIZE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -499,13 +618,13 @@ void Window_SetState(WindowState value) {
|
|||||||
|
|
||||||
case WindowState_Fullscreen:
|
case WindowState_Fullscreen:
|
||||||
/* We achieve fullscreen by hiding the window border and sending the MAXIMIZE command.
|
/* We achieve fullscreen by hiding the window border and sending the MAXIMIZE command.
|
||||||
We cannot use the WindowState.Maximized directly, as that will not send the MAXIMIZE
|
We cannot use the WindowState.Maximized directly, as that will not send the MAXIMIZE
|
||||||
command for windows with hidden borders. */
|
command for windows with hidden borders. */
|
||||||
|
|
||||||
/* Reset state to avoid strange side-effects from maximized/minimized windows. */
|
/* Reset state to avoid strange side-effects from maximized/minimized windows. */
|
||||||
ResetWindowState();
|
Window_ResetWindowState();
|
||||||
previous_bounds = Bounds;
|
previous_bounds = win_Bounds;
|
||||||
SetHiddenBorder(true);
|
Window_SetHiddenBorder(true);
|
||||||
|
|
||||||
command = SW_MAXIMIZE;
|
command = SW_MAXIMIZE;
|
||||||
SetForegroundWindow(win_Handle);
|
SetForegroundWindow(win_Handle);
|
||||||
@ -515,64 +634,27 @@ void Window_SetState(WindowState value) {
|
|||||||
if (command != 0) ShowWindow(win_Handle, command);
|
if (command != 0) ShowWindow(win_Handle, command);
|
||||||
|
|
||||||
/* Restore previous window border or apply pending border change when leaving fullscreen mode. */
|
/* Restore previous window border or apply pending border change when leaving fullscreen mode. */
|
||||||
if (exiting_fullscreen) SetHiddenBorder(false);
|
if (exiting_fullscreen) Window_SetHiddenBorder(false);
|
||||||
|
|
||||||
/* Restore previous window size/location if necessary */
|
/* Restore previous window size/location if necessary */
|
||||||
if (command == SW_RESTORE && previous_bounds != Rectangle.Empty) {
|
if (command == SW_RESTORE && !Rectangle2D_Equals(previous_bounds, Rectangle2D_Empty)) {
|
||||||
Bounds = previous_bounds;
|
Window_SetBounds(previous_bounds);
|
||||||
previous_bounds = Rectangle.Empty;
|
previous_bounds = Rectangle2D_Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool win_hiddenBorder;
|
|
||||||
void Window_DoSetHiddenBorder(bool value) {
|
|
||||||
if (win_hiddenBorder == value) return;
|
|
||||||
|
|
||||||
/* We wish to avoid making an invisible window visible just to change the border.
|
|
||||||
However, it's a good idea to make a visible window invisible temporarily, to
|
|
||||||
avoid garbage caused by the border change. */
|
|
||||||
bool was_visible = Window_GetVisible();
|
|
||||||
|
|
||||||
/* To ensure maximized/minimized windows work correctly, reset state to normal,
|
|
||||||
change the border, then go back to maximized/minimized. */
|
|
||||||
WindowState state = win_State;
|
|
||||||
Window_ResetWindowState();
|
|
||||||
DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
|
|
||||||
style |= (value ? WS_POPUP : WS_OVERLAPPEDWINDOW);
|
|
||||||
|
|
||||||
/* Make sure client size doesn't change when changing the border style.*/
|
|
||||||
Win32Rectangle rect = Win32Rectangle.From(bounds);
|
|
||||||
AdjustWindowRectEx(&rect, style, false, win_StyleEx);
|
|
||||||
|
|
||||||
/* This avoids leaving garbage on the background window. */
|
|
||||||
if (was_visible) Window_SetVisible(false);
|
|
||||||
|
|
||||||
SetWindowLongA(win_Handle, GWL_STYLE, style);
|
|
||||||
SetWindowPos(win_Handle, NULL, 0, 0, rect.Width, rect.Height,
|
|
||||||
SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
|
|
||||||
|
|
||||||
/* Force window to redraw update its borders, but only if it's
|
|
||||||
already visible (invisible windows will change borders when
|
|
||||||
they become visible, so no need to make them visiable prematurely).*/
|
|
||||||
if (was_visible) Window_SetVisible(true);
|
|
||||||
|
|
||||||
Window_SetWindowState(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
Point2D Window_PointToClient(Point2D point) {
|
Point2D Window_PointToClient(Point2D point) {
|
||||||
if (!ScreenToClient(win_Handle, ref point)) {
|
POINT p; p.x = point.X; p.y = point.Y;
|
||||||
|
if (!ScreenToClient(win_Handle, &p)) {
|
||||||
ErrorHandler_FailWithCode(GetLastError(), "Converting point from client to screen coordinates");
|
ErrorHandler_FailWithCode(GetLastError(), "Converting point from client to screen coordinates");
|
||||||
}
|
}
|
||||||
return point;
|
return Point2D_Make(p.x, p.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point2D Window_PointToScreen(Point2D p) {
|
Point2D Window_PointToScreen(Point2D p) {
|
||||||
ErrorHandler_Fail("PointToScreen NOT IMPLEMENTED");
|
ErrorHandler_Fail("PointToScreen NOT IMPLEMENTED");
|
||||||
}
|
}
|
||||||
|
|
||||||
public event EventHandler<EventArgs> Load;
|
|
||||||
public event EventHandler<EventArgs> Unload;
|
|
||||||
|
|
||||||
MSG msg;
|
MSG msg;
|
||||||
void Window_ProcessEvents() {
|
void Window_ProcessEvents() {
|
||||||
while (PeekMessageA(&msg, NULL, 0, 0, 1)) {
|
while (PeekMessageA(&msg, NULL, 0, 0, 1)) {
|
||||||
@ -599,74 +681,4 @@ bool Window_GetCursorVisible(void) { return win_cursorVisible; }
|
|||||||
void Window_SetCursorVisible(bool visible) {
|
void Window_SetCursorVisible(bool visible) {
|
||||||
win_cursorVisible = visible;
|
win_cursorVisible = visible;
|
||||||
ShowCursor(visible ? 1 : 0);
|
ShowCursor(visible ? 1 : 0);
|
||||||
}
|
|
||||||
|
|
||||||
Key Window_MapKey(WPARAM key) {
|
|
||||||
if (key >= VK_F1 && key <= VK_F24) {
|
|
||||||
return Key_F1 + (key - VK_F1);
|
|
||||||
}
|
|
||||||
if (key >= '0' && key <= '9') {
|
|
||||||
return Key_Number0 + (key - '0');
|
|
||||||
}
|
|
||||||
if (key >= 'A' && key <= 'Z') {
|
|
||||||
return Key_A + (key - 'A');
|
|
||||||
}
|
|
||||||
if (key >= VK_NUMPAD0 && key <= VK_NUMPAD9) {
|
|
||||||
return Key_Keypad0 + (key - VK_NUMPAD0);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (key) {
|
|
||||||
case VK_ESCAPE: return Key_Escape;
|
|
||||||
case VK_TAB: return Key_Tab;
|
|
||||||
case VK_CAPITAL: return Key_CapsLock;
|
|
||||||
case VK_LCONTROL: return Key_ControlLeft;
|
|
||||||
case VK_LSHIFT: return Key_ShiftLeft;
|
|
||||||
case VK_LWIN: return Key_WinLeft;
|
|
||||||
case VK_LMENU: return Key_AltLeft;
|
|
||||||
case VK_SPACE: return Key_Space;
|
|
||||||
case VK_RMENU: return Key_AltRight;
|
|
||||||
case VK_RWIN: return Key_WinRight;
|
|
||||||
case VK_APPS: return Key_Menu;
|
|
||||||
case VK_RCONTROL: return Key_ControlRight;
|
|
||||||
case VK_RSHIFT: return Key_ShiftRight;
|
|
||||||
case VK_RETURN: return Key_Enter;
|
|
||||||
case VK_BACK: return Key_BackSpace;
|
|
||||||
|
|
||||||
case VK_OEM_1: return Key_Semicolon; /* Varies by keyboard: return ;: on Win2K/US */
|
|
||||||
case VK_OEM_2: return Key_Slash; /* Varies by keyboard: return /? on Win2K/US */
|
|
||||||
case VK_OEM_3: return Key_Tilde; /* Varies by keyboard: return `~ on Win2K/US */
|
|
||||||
case VK_OEM_4: return Key_BracketLeft; /* Varies by keyboard: return [{ on Win2K/US */
|
|
||||||
case VK_OEM_5: return Key_BackSlash; /* Varies by keyboard: return \| on Win2K/US */
|
|
||||||
case VK_OEM_6: return Key_BracketRight; /* Varies by keyboard: return ]} on Win2K/US */
|
|
||||||
case VK_OEM_7: return Key_Quote; /* Varies by keyboard: return '" on Win2K/US */
|
|
||||||
case VK_OEM_PLUS: return Key_Plus; /* Invariant: + */
|
|
||||||
case VK_OEM_COMMA: return Key_Comma; /* Invariant: : return */
|
|
||||||
case VK_OEM_MINUS: return Key_Minus; /* Invariant: - */
|
|
||||||
case VK_OEM_PERIOD: return Key_Period; /* Invariant: . */
|
|
||||||
|
|
||||||
case VK_HOME: return Key_Home;
|
|
||||||
case VK_END: return Key_End;
|
|
||||||
case VK_DELETE: return Key_Delete;
|
|
||||||
case VK_PRIOR: return Key_PageUp;
|
|
||||||
case VK_NEXT: return Key_PageDown;
|
|
||||||
case VK_PRINT: return Key_PrintScreen;
|
|
||||||
case VK_PAUSE: return Key_Pause;
|
|
||||||
case VK_NUMLOCK: return Key_NumLock;
|
|
||||||
|
|
||||||
case VK_SCROLL: return Key_ScrollLock;
|
|
||||||
case VK_SNAPSHOT: return Key_PrintScreen;
|
|
||||||
case VK_INSERT: return Key_Insert;
|
|
||||||
|
|
||||||
case VK_DECIMAL: return Key_KeypadDecimal;
|
|
||||||
case VK_ADD: return Key_KeypadAdd;
|
|
||||||
case VK_SUBTRACT: return Key_KeypadSubtract;
|
|
||||||
case VK_DIVIDE: return Key_KeypadDivide;
|
|
||||||
case VK_MULTIPLY: return Key_KeypadMultiply;
|
|
||||||
|
|
||||||
case VK_UP: return Key_Up;
|
|
||||||
case VK_DOWN: return Key_Down;
|
|
||||||
case VK_LEFT: return Key_Left;
|
|
||||||
case VK_RIGHT: return Key_Right;
|
|
||||||
}
|
|
||||||
return Key_Unknown;
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user