Skip to content

Commit

Permalink
Merge pull request #8 from guzba/master
Browse files Browse the repository at this point in the history
some window properties
  • Loading branch information
treeform authored Oct 17, 2021
2 parents 83d8df2 + c009ce1 commit 4b45ec5
Show file tree
Hide file tree
Showing 7 changed files with 429 additions and 65 deletions.
7 changes: 7 additions & 0 deletions bindings/bindings.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ exportProcs:
takeError

exportRefObject Window:
fields:
visible
decorated
resizable
size
pos
constructor:
newWindow
procs:
Expand All @@ -22,6 +28,7 @@ exportRefObject Window:

exportProcs:
init
pollEvents

writeFiles("bindings/generated", "Windy")

Expand Down
2 changes: 1 addition & 1 deletion examples/basic.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ init()

let
windowSize = ivec2(1280, 800)
window = newWindow("Windy + Boxy", windowSize.x, windowSize.y)
window = newWindow("Windy + Boxy", windowSize)

window.makeContextCurrent()
loadExtensions()
Expand Down
56 changes: 36 additions & 20 deletions src/windy.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import windy/common
import vmath, windy/common

export common
export common, vmath

when defined(windows):
import windy/platforms/win32/platform
Expand All @@ -18,22 +18,19 @@ proc init*() {.raises: [WindyError]} =

proc newWindow*(
title: string,
w: int,
h: int,
size: IVec2,
vsync = true,
openglMajorVersion = 4,
openglMinorVersion = 1,
msaa = msaaDisabled,
depthBits = 24,
stencilBits = 8
): Window {.raises: [WindyError]} =
# resizeable, fullscreen, transparent, decorated, floating
result = Window()
try:
result.platform = newPlatformWindow(
title,
w,
h,
size,
vsync,
openglMajorVersion,
openglMinorVersion,
Expand All @@ -42,28 +39,47 @@ proc newWindow*(
stencilBits
)
except:
raise newException(WindyError, "Creating native window failed: " & getCurrentExceptionMsg())
raise newException(
WindyError,
"Creating native window failed",
getCurrentException()
)

proc makeContextCurrent*(window: Window) {.raises: [WindyError]} =
window.platform.makeContextCurrent()

proc swapBuffers*(window: Window) {.raises: [WindyError]} =
window.platform.swapBuffers()

proc show*(window: PlatformWindow) =
discard

proc hide*(window: PlatformWindow) =
discard

proc pollEvents*() =
platformPollEvents()

proc `visible`*(window: Window): bool =
discard
proc visible*(window: Window): bool =
window.platform.visible

proc `visible=`*(window: Window, visible: bool) =
if visible:
window.platform.show()
else:
window.platform.hide()
window.platform.visible = visible

proc decorated*(window: Window): bool =
window.platform.decorated

proc `decorated=`*(window: Window, decorated: bool) =
window.platform.decorated = decorated

proc resizable*(window: Window): bool =
window.platform.resizable

proc `resizable=`*(window: Window, resizable: bool) =
window.platform.resizable = resizable

proc size*(window: Window): IVec2 =
window.platform.size

proc `size=`*(window: Window, size: IVec2) =
window.platform.size = size

proc pos*(window: Window): IVec2 =
window.platform.pos

proc `pos=`*(window: Window, pos: Ivec2) =
window.platform.pos = pos
171 changes: 147 additions & 24 deletions src/windy/platforms/win32/platform.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import ../../common, windefs
import ../../common, utils, vmath, windefs

const
windowClassName = "WINDY0"
defaultScreenDpi = 96
decoratedWindowStyle = WS_OVERLAPPEDWINDOW
undecoratedWindowStyle = WS_POPUP

WGL_DRAW_TO_WINDOW_ARB = 0x2001
WGL_ACCELERATION_ARB = 0x2003
Expand Down Expand Up @@ -31,8 +34,6 @@ type
hglrc: HGLRC

var
initialized: bool
windows*: seq[PlatformWindow]
wglCreateContext: wglCreateContext
wglDeleteContext: wglDeleteContext
wglGetProcAddress: wglGetProcAddress
Expand All @@ -42,6 +43,13 @@ var
wglCreateContextAttribsARB: wglCreateContextAttribsARB
wglChoosePixelFormatARB: wglChoosePixelFormatARB
wglSwapIntervalEXT: wglSwapIntervalEXT
SetProcessDpiAwarenessContext: SetProcessDpiAwarenessContext
GetDpiForWindow: GetDpiForWindow
AdjustWindowRectExForDpi: AdjustWindowRectExForDpi

var
initialized: bool
windows*: seq[PlatformWindow]

proc wstr*(str: string): string =
let wlen = MultiByteToWideChar(
Expand Down Expand Up @@ -84,22 +92,34 @@ proc registerWindowClass(windowClassName: string, wndProc: WNDPROC) =
if RegisterClassExW(wc.addr) == 0:
raise newException(WindyError, "Error registering window class")

proc createWindow(
windowClassName, title: string, x, y, w, h: int
): HWND =
proc createWindow(windowClassName, title: string, size: IVec2): HWND =
let
windowClassName = windowClassName.wstr()
title = title.wstr()

var size = size
if size != ivec2(CW_USEDEFAULT, CW_USEDEFAULT):
# Adjust the window creation size for window styles (border, etc)
var rect = Rect(top: 0, left: 0, right: size.x, bottom: size.y)
discard AdjustWindowRectExForDpi(
rect.addr,
decoratedWindowStyle,
0,
WS_EX_APPWINDOW,
defaultScreenDpi
)
size.x = rect.right - rect.left
size.y = rect.bottom - rect.top

result = CreateWindowExW(
WS_EX_APPWINDOW,
cast[ptr WCHAR](windowClassName[0].unsafeAddr),
cast[ptr WCHAR](title[0].unsafeAddr),
WS_OVERLAPPEDWINDOW,
x.int32,
y.int32,
w.int32,
h.int32,
decoratedWindowStyle,
CW_USEDEFAULT,
CW_USEDEFAULT,
size.x,
size.y,
0,
0,
GetModuleHandleW(nil),
Expand Down Expand Up @@ -155,10 +175,7 @@ proc loadOpenGL() =
hWnd = createWindow(
dummyWindowClassName,
dummyWindowClassName,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT
ivec2(CW_USEDEFAULT, CW_USEDEFAULT)
)
hdc = getDC(hWnd)

Expand Down Expand Up @@ -203,17 +220,35 @@ proc loadOpenGL() =
discard ReleaseDC(hWnd, hdc)
discard DestroyWindow(hWnd)

proc loadLibraries() =
let user32 = LoadLibraryA("user32.dll")
if user32 == 0:
raise newException(WindyError, "Error loading user32.dll")

SetProcessDpiAwarenessContext = cast[SetProcessDpiAwarenessContext](
GetProcAddress(user32, "SetProcessDpiAwarenessContext")
)
GetDpiForWindow = cast[GetDpiForWindow](
GetProcAddress(user32, "GetDpiForWindow")
)
AdjustWindowRectExForDpi = cast[AdjustWindowRectExForDpi](
GetProcAddress(user32, "AdjustWindowRectExForDpi")
)

proc wndProc(
hWnd: HWND,
uMsg: UINT,
wParam: WPARAM,
lParam: LPARAM
): LRESULT {.stdcall.} =
# echo wmEventName(uMsg)
DefWindowProcW(hWnd, uMsg, wParam, lParam)

proc platformInit*() =
if initialized:
raise newException(WindyError, "Windy is already initialized")
loadLibraries()
discard SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)
loadOpenGL()
registerWindowClass(windowClassName, wndProc)
initialized = true
Expand Down Expand Up @@ -241,10 +276,10 @@ proc destroy(window: PlatformWindow) =
discard DestroyWindow(window.hWnd)
window.hWnd = 0

proc show*(window: PlatformWindow) =
proc show(window: PlatformWindow) =
discard ShowWindow(window.hWnd, SW_SHOW)

proc hide*(window: PlatformWindow) =
proc hide(window: PlatformWindow) =
discard ShowWindow(window.hWnd, SW_HIDE)

proc makeContextCurrent*(window: PlatformWindow) =
Expand All @@ -256,8 +291,7 @@ proc swapBuffers*(window: PlatformWindow) =

proc newPlatformWindow*(
title: string,
w: int,
h: int,
size: IVec2,
vsync: bool,
openglMajorVersion: int,
openglMinorVersion: int,
Expand All @@ -269,10 +303,7 @@ proc newPlatformWindow*(
result.hWnd = createWindow(
windowClassName,
title,
CW_USEDEFAULT,
CW_USEDEFAULT,
w,
h
size
)

try:
Expand Down Expand Up @@ -359,5 +390,97 @@ proc newPlatformWindow*(

windows.add(result)
except WindyError as e:
result.destroy()
destroy result
raise e

proc visible*(window: PlatformWindow): bool =
IsWindowVisible(window.hWnd) != 0

proc `visible=`*(window: PlatformWindow, visible: bool) =
if visible:
window.show()
else:
window.hide()

proc decorated*(window: PlatformWindow): bool =
let style = GetWindowLongW(window.hWnd, GWL_STYLE)
(style and WS_BORDER) != 0

proc `decorated=`*(window: PlatformWindow, decorated: bool) =
var style: DWORD
if decorated:
style = decoratedWindowStyle
else:
style = undecoratedWindowStyle

if window.visible:
style = style or WS_VISIBLE

discard SetWindowLongW(window.hWnd, GWL_STYLE, style)

proc resizable*(window: PlatformWindow): bool =
let style = GetWindowLongW(window.hWnd, GWL_STYLE)
(style and WS_THICKFRAME) != 0

proc `resizable=`*(window: PlatformWindow, resizable: bool) =
if not window.decorated:
return

var style = decoratedWindowStyle.DWORD
if resizable:
style = style or (WS_MAXIMIZEBOX or WS_THICKFRAME)
else:
style = style and not (WS_MAXIMIZEBOX or WS_THICKFRAME)

if window.visible:
style = style or WS_VISIBLE

discard SetWindowLongW(window.hWnd, GWL_STYLE, style)

proc size*(window: PlatformWindow): IVec2 =
var rect: RECT
discard GetClientRect(window.hWnd, rect.addr)
ivec2(rect.right, rect.bottom)

proc `size=`*(window: PlatformWindow, size: IVec2) =
var rect = RECT(top: 0, left: 0, right: size.x, bottom: size.y)
discard AdjustWindowRectExForDpi(
rect.addr,
decoratedWindowStyle,
0,
WS_EX_APPWINDOW,
GetDpiForWindow(window.hWnd)
)
discard SetWindowPos(
window.hWnd,
HWND_TOP,
0,
0,
rect.right - rect.left,
rect.bottom - rect.top,
SWP_NOACTIVATE or SWP_NOZORDER or SWP_NOMOVE
)

proc pos*(window: PlatformWindow): IVec2 =
var pos: POINT
discard ClientToScreen(window.hWnd, pos.addr)
ivec2(pos.x, pos.y)

proc `pos=`*(window: PlatformWindow, pos: IVec2) =
var rect = RECT(top: pos.x, left: pos.y, bottom: pos.x, right: pos.y)
discard AdjustWindowRectExForDpi(
rect.addr,
decoratedWindowStyle,
0,
WS_EX_APPWINDOW,
GetDpiForWindow(window.hWnd)
)
discard SetWindowPos(
window.hWnd,
HWND_TOP,
rect.left,
rect.top,
0,
0,
SWP_NOACTIVATE or SWP_NOZORDER or SWP_NOSIZE
)
Loading

0 comments on commit 4b45ec5

Please sign in to comment.