mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-13 22:47:26 +01:00
Compare commits
9 Commits
bde384b707
...
1642d4d664
Author | SHA1 | Date | |
---|---|---|---|
|
1642d4d664 | ||
|
11223d9fae | ||
|
9cd7b34a77 | ||
|
6df42f1a4b | ||
|
86e0bcc264 | ||
|
d5f15f9354 | ||
|
6ff9e2b44c | ||
|
4dfb3d2fc1 | ||
|
4647e9de53 |
@ -152,6 +152,14 @@ func (g *nativeGamepadsImpl) addDevice(device _IOHIDDeviceRef, gamepads *gamepad
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elements := _IOHIDDeviceCopyMatchingElements(device, 0, kIOHIDOptionsTypeNone)
|
||||||
|
// It is reportedly possible for this to fail on macOS 13 Ventura
|
||||||
|
// if the application does not have input monitoring permissions
|
||||||
|
if elements == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer _CFRelease(_CFTypeRef(elements))
|
||||||
|
|
||||||
name := "Unknown"
|
name := "Unknown"
|
||||||
if prop := _IOHIDDeviceGetProperty(device, _CFStringCreateWithCString(kCFAllocatorDefault, kIOHIDProductKey, kCFStringEncodingUTF8)); prop != 0 {
|
if prop := _IOHIDDeviceGetProperty(device, _CFStringCreateWithCString(kCFAllocatorDefault, kIOHIDProductKey, kCFStringEncodingUTF8)); prop != 0 {
|
||||||
var cstr [256]byte
|
var cstr [256]byte
|
||||||
@ -189,9 +197,6 @@ func (g *nativeGamepadsImpl) addDevice(device _IOHIDDeviceRef, gamepads *gamepad
|
|||||||
bs[0], bs[1], bs[2], bs[3], bs[4], bs[5], bs[6], bs[7], bs[8], bs[9], bs[10], bs[11])
|
bs[0], bs[1], bs[2], bs[3], bs[4], bs[5], bs[6], bs[7], bs[8], bs[9], bs[10], bs[11])
|
||||||
}
|
}
|
||||||
|
|
||||||
elements := _IOHIDDeviceCopyMatchingElements(device, 0, kIOHIDOptionsTypeNone)
|
|
||||||
defer _CFRelease(_CFTypeRef(elements))
|
|
||||||
|
|
||||||
n := &nativeGamepadImpl{
|
n := &nativeGamepadImpl{
|
||||||
device: device,
|
device: device,
|
||||||
}
|
}
|
||||||
|
@ -794,6 +794,16 @@ func (g *nativeGamepadDesktop) hatState(hat int) int {
|
|||||||
if g.xinputState.Gamepad.wButtons&_XINPUT_GAMEPAD_DPAD_LEFT != 0 {
|
if g.xinputState.Gamepad.wButtons&_XINPUT_GAMEPAD_DPAD_LEFT != 0 {
|
||||||
v |= hatLeft
|
v |= hatLeft
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Treat invalid combinations as neither being pressed
|
||||||
|
// while preserving what data can be preserved
|
||||||
|
if (v&hatRight) != 0 && (v&hatLeft) != 0 {
|
||||||
|
v &^= hatRight | hatLeft
|
||||||
|
}
|
||||||
|
if (v&hatUp) != 0 && (v&hatDown) != 0 {
|
||||||
|
v &^= hatUp | hatDown
|
||||||
|
}
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,13 +140,6 @@ func (*nativeGamepadsImpl) openGamepad(gamepads *gamepads, path string) (err err
|
|||||||
return fmt.Errorf("gamepad: ioctl for an ID failed: %w", err)
|
return fmt.Errorf("gamepad: ioctl for an ID failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isBitSet(evBits, unix.EV_KEY) {
|
|
||||||
if err := unix.Close(fd); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if !isBitSet(evBits, unix.EV_ABS) {
|
if !isBitSet(evBits, unix.EV_ABS) {
|
||||||
if err := unix.Close(fd); err != nil {
|
if err := unix.Close(fd); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -100,6 +100,7 @@ const (
|
|||||||
_MAPVK_VSC_TO_VK = 1
|
_MAPVK_VSC_TO_VK = 1
|
||||||
_MONITOR_DEFAULTTONEAREST = 0x00000002
|
_MONITOR_DEFAULTTONEAREST = 0x00000002
|
||||||
_MOUSE_MOVE_ABSOLUTE = 0x01
|
_MOUSE_MOVE_ABSOLUTE = 0x01
|
||||||
|
_MOUSE_VIRTUAL_DESKTOP = 0x02
|
||||||
_MSGFLT_ALLOW = 1
|
_MSGFLT_ALLOW = 1
|
||||||
_OCR_CROSS = 32515
|
_OCR_CROSS = 32515
|
||||||
_OCR_HAND = 32649
|
_OCR_HAND = 32649
|
||||||
@ -121,6 +122,7 @@ const (
|
|||||||
_PFD_SUPPORT_OPENGL = 0x00000020
|
_PFD_SUPPORT_OPENGL = 0x00000020
|
||||||
_PFD_TYPE_RGBA = 0
|
_PFD_TYPE_RGBA = 0
|
||||||
_QS_ALLEVENTS = _QS_INPUT | _QS_POSTMESSAGE | _QS_TIMER | _QS_PAINT | _QS_HOTKEY
|
_QS_ALLEVENTS = _QS_INPUT | _QS_POSTMESSAGE | _QS_TIMER | _QS_PAINT | _QS_HOTKEY
|
||||||
|
_QS_ALLINPUT = _QS_INPUT | _QS_POSTMESSAGE | _QS_TIMER | _QS_PAINT | _QS_HOTKEY | _QS_SENDMESSAGE
|
||||||
_QS_HOTKEY = 0x0080
|
_QS_HOTKEY = 0x0080
|
||||||
_QS_INPUT = _QS_MOUSE | _QS_KEY | _QS_RAWINPUT
|
_QS_INPUT = _QS_MOUSE | _QS_KEY | _QS_RAWINPUT
|
||||||
_QS_KEY = 0x0001
|
_QS_KEY = 0x0001
|
||||||
@ -130,6 +132,7 @@ const (
|
|||||||
_QS_PAINT = 0x0020
|
_QS_PAINT = 0x0020
|
||||||
_QS_POSTMESSAGE = 0x0008
|
_QS_POSTMESSAGE = 0x0008
|
||||||
_QS_RAWINPUT = 0x0400
|
_QS_RAWINPUT = 0x0400
|
||||||
|
_QS_SENDMESSAGE = 0x0040
|
||||||
_QS_TIMER = 0x0010
|
_QS_TIMER = 0x0010
|
||||||
_RID_INPUT = 0x10000003
|
_RID_INPUT = 0x10000003
|
||||||
_RIDEV_REMOVE = 0x00000001
|
_RIDEV_REMOVE = 0x00000001
|
||||||
@ -139,11 +142,18 @@ const (
|
|||||||
_SIZE_MAXIMIZED = 2
|
_SIZE_MAXIMIZED = 2
|
||||||
_SIZE_MINIMIZED = 1
|
_SIZE_MINIMIZED = 1
|
||||||
_SIZE_RESTORED = 0
|
_SIZE_RESTORED = 0
|
||||||
|
_SM_CXCURSOR = 13
|
||||||
_SM_CXICON = 11
|
_SM_CXICON = 11
|
||||||
|
_SM_CXSCREEN = 0
|
||||||
_SM_CXSMICON = 49
|
_SM_CXSMICON = 49
|
||||||
_SM_CYCAPTION = 4
|
_SM_CYCAPTION = 4
|
||||||
|
_SM_CYCURSOR = 14
|
||||||
_SM_CYICON = 12
|
_SM_CYICON = 12
|
||||||
|
_SM_CYSCREEN = 1
|
||||||
_SM_CYSMICON = 50
|
_SM_CYSMICON = 50
|
||||||
|
_SM_CXVIRTUALSCREEN = 78
|
||||||
|
_SM_CYVIRTUALSCREEN = 79
|
||||||
|
_SM_REMOTESESSION = 0x1000
|
||||||
_SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000
|
_SPI_GETFOREGROUNDLOCKTIMEOUT = 0x2000
|
||||||
_SPI_GETMOUSETRAILS = 94
|
_SPI_GETMOUSETRAILS = 94
|
||||||
_SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001
|
_SPI_SETFOREGROUNDLOCKTIMEOUT = 0x2001
|
||||||
@ -753,9 +763,11 @@ var (
|
|||||||
procChangeWindowMessageFilterEx = user32.NewProc("ChangeWindowMessageFilterEx")
|
procChangeWindowMessageFilterEx = user32.NewProc("ChangeWindowMessageFilterEx")
|
||||||
procClientToScreen = user32.NewProc("ClientToScreen")
|
procClientToScreen = user32.NewProc("ClientToScreen")
|
||||||
procClipCursor = user32.NewProc("ClipCursor")
|
procClipCursor = user32.NewProc("ClipCursor")
|
||||||
|
procCreateCursor = user32.NewProc("CreateCursor")
|
||||||
procCreateIconIndirect = user32.NewProc("CreateIconIndirect")
|
procCreateIconIndirect = user32.NewProc("CreateIconIndirect")
|
||||||
procCreateWindowExW = user32.NewProc("CreateWindowExW")
|
procCreateWindowExW = user32.NewProc("CreateWindowExW")
|
||||||
procDefWindowProcW = user32.NewProc("DefWindowProcW")
|
procDefWindowProcW = user32.NewProc("DefWindowProcW")
|
||||||
|
procDestroyCursor = user32.NewProc("DestroyCursor")
|
||||||
procDestroyIcon = user32.NewProc("DestroyIcon")
|
procDestroyIcon = user32.NewProc("DestroyIcon")
|
||||||
procDestroyWindow = user32.NewProc("DestroyWindow")
|
procDestroyWindow = user32.NewProc("DestroyWindow")
|
||||||
procDispatchMessageW = user32.NewProc("DispatchMessageW")
|
procDispatchMessageW = user32.NewProc("DispatchMessageW")
|
||||||
@ -913,6 +925,26 @@ func _ClipCursor(lpRect *_RECT) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _CreateCursor(hInst _HINSTANCE, xHotSpot int32, yHotSpot int32, nWidth int32, nHeight int32, pvANDPlane, pvXORPlane []byte) (_HCURSOR, error) {
|
||||||
|
var andPlane *byte
|
||||||
|
if len(pvANDPlane) > 0 {
|
||||||
|
andPlane = &pvANDPlane[0]
|
||||||
|
}
|
||||||
|
var xorPlane *byte
|
||||||
|
if len(pvXORPlane) > 0 {
|
||||||
|
xorPlane = &pvXORPlane[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
r, _, e := procCreateCursor.Call(uintptr(hInst), uintptr(xHotSpot), uintptr(yHotSpot), uintptr(nWidth), uintptr(nHeight), uintptr(unsafe.Pointer(andPlane)), uintptr(unsafe.Pointer(xorPlane)))
|
||||||
|
runtime.KeepAlive(pvANDPlane)
|
||||||
|
runtime.KeepAlive(pvXORPlane)
|
||||||
|
|
||||||
|
if _HCURSOR(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {
|
||||||
|
return 0, fmt.Errorf("glfw: CreateCursor failed: %w", e)
|
||||||
|
}
|
||||||
|
return _HCURSOR(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
func _CreateBitmap(nWidth int32, nHeight int32, nPlanes uint32, nBitCount uint32, lpBits unsafe.Pointer) (_HBITMAP, error) {
|
func _CreateBitmap(nWidth int32, nHeight int32, nPlanes uint32, nBitCount uint32, lpBits unsafe.Pointer) (_HBITMAP, error) {
|
||||||
r, _, e := procCreateBitmap.Call(uintptr(nWidth), uintptr(nHeight), uintptr(nPlanes), uintptr(nBitCount), uintptr(lpBits))
|
r, _, e := procCreateBitmap.Call(uintptr(nWidth), uintptr(nHeight), uintptr(nPlanes), uintptr(nBitCount), uintptr(lpBits))
|
||||||
if _HBITMAP(r) == 0 {
|
if _HBITMAP(r) == 0 {
|
||||||
@ -984,6 +1016,14 @@ func _DefWindowProcW(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPA
|
|||||||
return _LRESULT(r)
|
return _LRESULT(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _DestroyCursor(hCursor _HCURSOR) error {
|
||||||
|
r, _, e := procDestroyCursor.Call(uintptr(hCursor))
|
||||||
|
if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {
|
||||||
|
return fmt.Errorf("glfw: DestroyCursor failed: %w", e)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func _DestroyIcon(hIcon _HICON) error {
|
func _DestroyIcon(hIcon _HICON) error {
|
||||||
r, _, e := procDestroyIcon.Call(uintptr(hIcon))
|
r, _, e := procDestroyIcon.Call(uintptr(hIcon))
|
||||||
if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {
|
if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {
|
||||||
|
@ -227,7 +227,7 @@ static void createKeyTables(void)
|
|||||||
_glfw.ns.keycodes[0x6D] = GLFW_KEY_F10;
|
_glfw.ns.keycodes[0x6D] = GLFW_KEY_F10;
|
||||||
_glfw.ns.keycodes[0x67] = GLFW_KEY_F11;
|
_glfw.ns.keycodes[0x67] = GLFW_KEY_F11;
|
||||||
_glfw.ns.keycodes[0x6F] = GLFW_KEY_F12;
|
_glfw.ns.keycodes[0x6F] = GLFW_KEY_F12;
|
||||||
_glfw.ns.keycodes[0x69] = GLFW_KEY_F13;
|
_glfw.ns.keycodes[0x69] = GLFW_KEY_PRINT_SCREEN;
|
||||||
_glfw.ns.keycodes[0x6B] = GLFW_KEY_F14;
|
_glfw.ns.keycodes[0x6B] = GLFW_KEY_F14;
|
||||||
_glfw.ns.keycodes[0x71] = GLFW_KEY_F15;
|
_glfw.ns.keycodes[0x71] = GLFW_KEY_F15;
|
||||||
_glfw.ns.keycodes[0x6A] = GLFW_KEY_F16;
|
_glfw.ns.keycodes[0x6A] = GLFW_KEY_F16;
|
||||||
@ -420,7 +420,6 @@ static GLFWbool initializeTIS(void)
|
|||||||
|
|
||||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||||
{
|
{
|
||||||
_glfw.ns.finishedLaunching = GLFW_TRUE;
|
|
||||||
_glfwPlatformPostEmptyEvent();
|
_glfwPlatformPostEmptyEvent();
|
||||||
|
|
||||||
// In case we are unbundled, make us a proper UI application
|
// In case we are unbundled, make us a proper UI application
|
||||||
@ -455,9 +454,6 @@ int _glfwPlatformInit(void)
|
|||||||
toTarget:_glfw.ns.helper
|
toTarget:_glfw.ns.helper
|
||||||
withObject:nil];
|
withObject:nil];
|
||||||
|
|
||||||
if (NSApp)
|
|
||||||
_glfw.ns.finishedLaunching = GLFW_TRUE;
|
|
||||||
|
|
||||||
[NSApplication sharedApplication];
|
[NSApplication sharedApplication];
|
||||||
|
|
||||||
_glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
|
_glfw.ns.delegate = [[GLFWApplicationDelegate alloc] init];
|
||||||
@ -509,6 +505,10 @@ int _glfwPlatformInit(void)
|
|||||||
_glfwInitTimerNS();
|
_glfwInitTimerNS();
|
||||||
|
|
||||||
_glfwPollMonitorsNS();
|
_glfwPollMonitorsNS();
|
||||||
|
|
||||||
|
if (![[NSRunningApplication currentApplication] isFinishedLaunching])
|
||||||
|
[NSApp run];
|
||||||
|
|
||||||
return GLFW_TRUE;
|
return GLFW_TRUE;
|
||||||
|
|
||||||
} // autoreleasepool
|
} // autoreleasepool
|
||||||
|
@ -109,7 +109,6 @@ typedef struct _GLFWlibraryNS
|
|||||||
{
|
{
|
||||||
CGEventSourceRef eventSource;
|
CGEventSourceRef eventSource;
|
||||||
id delegate;
|
id delegate;
|
||||||
GLFWbool finishedLaunching;
|
|
||||||
GLFWbool cursorHidden;
|
GLFWbool cursorHidden;
|
||||||
TISInputSourceRef inputSource;
|
TISInputSourceRef inputSource;
|
||||||
id unicodeData;
|
id unicodeData;
|
||||||
|
@ -285,10 +285,15 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
|
|||||||
|
|
||||||
- (void)windowDidChangeOcclusionState:(NSNotification* )notification
|
- (void)windowDidChangeOcclusionState:(NSNotification* )notification
|
||||||
{
|
{
|
||||||
|
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
|
||||||
|
if ([window->ns.object respondsToSelector:@selector(occlusionState)])
|
||||||
|
{
|
||||||
if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible)
|
if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible)
|
||||||
window->ns.occluded = GLFW_FALSE;
|
window->ns.occluded = GLFW_FALSE;
|
||||||
else
|
else
|
||||||
window->ns.occluded = GLFW_TRUE;
|
window->ns.occluded = GLFW_TRUE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@ -878,9 +883,6 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
|||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
if (!_glfw.ns.finishedLaunching)
|
|
||||||
[NSApp run];
|
|
||||||
|
|
||||||
if (!createNativeWindow(window, wndconfig, fbconfig))
|
if (!createNativeWindow(window, wndconfig, fbconfig))
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
|
|
||||||
@ -1239,7 +1241,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
|
|||||||
|
|
||||||
if (window->monitor)
|
if (window->monitor)
|
||||||
{
|
{
|
||||||
styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);
|
styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable);
|
||||||
styleMask |= NSWindowStyleMaskBorderless;
|
styleMask |= NSWindowStyleMaskBorderless;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1472,9 +1474,6 @@ void _glfwPlatformPollEvents(void)
|
|||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
if (!_glfw.ns.finishedLaunching)
|
|
||||||
[NSApp run];
|
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
|
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
|
||||||
@ -1494,9 +1493,6 @@ void _glfwPlatformWaitEvents(void)
|
|||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
if (!_glfw.ns.finishedLaunching)
|
|
||||||
[NSApp run];
|
|
||||||
|
|
||||||
// I wanted to pass NO to dequeue:, and rely on PollEvents to
|
// I wanted to pass NO to dequeue:, and rely on PollEvents to
|
||||||
// dequeue and send. For reasons not at all clear to me, passing
|
// dequeue and send. For reasons not at all clear to me, passing
|
||||||
// NO to dequeue: causes this method never to return.
|
// NO to dequeue: causes this method never to return.
|
||||||
@ -1515,9 +1511,6 @@ void _glfwPlatformWaitEventsTimeout(double timeout)
|
|||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
if (!_glfw.ns.finishedLaunching)
|
|
||||||
[NSApp run];
|
|
||||||
|
|
||||||
NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout];
|
NSDate* date = [NSDate dateWithTimeIntervalSinceNow:timeout];
|
||||||
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
|
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
|
||||||
untilDate:date
|
untilDate:date
|
||||||
@ -1535,9 +1528,6 @@ void _glfwPlatformPostEmptyEvent(void)
|
|||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
if (!_glfw.ns.finishedLaunching)
|
|
||||||
[NSApp run];
|
|
||||||
|
|
||||||
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
|
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined
|
||||||
location:NSMakePoint(0, 0)
|
location:NSMakePoint(0, 0)
|
||||||
modifierFlags:0
|
modifierFlags:0
|
||||||
@ -1616,14 +1606,15 @@ const char* _glfwPlatformGetScancodeName(int scancode)
|
|||||||
{
|
{
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
if (scancode < 0 || scancode > 0xff ||
|
if (scancode < 0 || scancode > 0xff)
|
||||||
_glfw.ns.keycodes[scancode] == GLFW_KEY_UNKNOWN)
|
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode);
|
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int key = _glfw.ns.keycodes[scancode];
|
const int key = _glfw.ns.keycodes[scancode];
|
||||||
|
if (key == GLFW_KEY_UNKNOWN)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
UInt32 deadKeyState = 0;
|
UInt32 deadKeyState = 0;
|
||||||
UniChar characters[4];
|
UniChar characters[4];
|
||||||
|
@ -26,16 +26,6 @@
|
|||||||
//
|
//
|
||||||
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
||||||
{
|
{
|
||||||
if (ctxconfig->share)
|
|
||||||
{
|
|
||||||
if (ctxconfig->client == GLFW_NO_API ||
|
|
||||||
ctxconfig->share->context.client == GLFW_NO_API)
|
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
|
||||||
return GLFW_FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API &&
|
if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API &&
|
||||||
ctxconfig->source != GLFW_EGL_CONTEXT_API &&
|
ctxconfig->source != GLFW_EGL_CONTEXT_API &&
|
||||||
ctxconfig->source != GLFW_OSMESA_CONTEXT_API)
|
ctxconfig->source != GLFW_OSMESA_CONTEXT_API)
|
||||||
@ -56,6 +46,23 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
|
|||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->share)
|
||||||
|
{
|
||||||
|
if (ctxconfig->client == GLFW_NO_API ||
|
||||||
|
ctxconfig->share->context.client == GLFW_NO_API)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->source != ctxconfig->share->context.source)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM,
|
||||||
|
"Context creation APIs do not match between contexts");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ctxconfig->client == GLFW_OPENGL_API)
|
if (ctxconfig->client == GLFW_OPENGL_API)
|
||||||
{
|
{
|
||||||
if ((ctxconfig->major < 1 || ctxconfig->minor < 0) ||
|
if ((ctxconfig->major < 1 || ctxconfig->minor < 0) ||
|
||||||
@ -334,6 +341,8 @@ GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window,
|
|||||||
|
|
||||||
previous = _glfwPlatformGetTls(&_glfw.contextSlot);
|
previous = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
glfwMakeContextCurrent((GLFWwindow*) window);
|
glfwMakeContextCurrent((GLFWwindow*) window);
|
||||||
|
if (_glfwPlatformGetTls(&_glfw.contextSlot) != window)
|
||||||
|
return GLFW_FALSE;
|
||||||
|
|
||||||
window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
|
window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
|
||||||
window->context.getProcAddress("glGetIntegerv");
|
window->context.getProcAddress("glGetIntegerv");
|
||||||
|
@ -17,12 +17,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func checkValidContextConfig(ctxconfig *ctxconfig) error {
|
func checkValidContextConfig(ctxconfig *ctxconfig) error {
|
||||||
if ctxconfig.share != nil {
|
|
||||||
if ctxconfig.client == NoAPI || ctxconfig.share.context.client == NoAPI {
|
|
||||||
return NoWindowContext
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ctxconfig.source != NativeContextAPI &&
|
if ctxconfig.source != NativeContextAPI &&
|
||||||
ctxconfig.source != EGLContextAPI &&
|
ctxconfig.source != EGLContextAPI &&
|
||||||
ctxconfig.source != OSMesaContextAPI {
|
ctxconfig.source != OSMesaContextAPI {
|
||||||
@ -35,6 +29,15 @@ func checkValidContextConfig(ctxconfig *ctxconfig) error {
|
|||||||
return fmt.Errorf("glfw: invalid client API 0x%08X: %w", ctxconfig.client, InvalidEnum)
|
return fmt.Errorf("glfw: invalid client API 0x%08X: %w", ctxconfig.client, InvalidEnum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ctxconfig.share != nil {
|
||||||
|
if ctxconfig.client == NoAPI || ctxconfig.share.context.client == NoAPI {
|
||||||
|
return NoWindowContext
|
||||||
|
}
|
||||||
|
if ctxconfig.source != ctxconfig.share.context.source {
|
||||||
|
return fmt.Errorf("glfw: context creation APIs do not match between contexts: %w", InvalidEnum)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ctxconfig.client == OpenGLAPI {
|
if ctxconfig.client == OpenGLAPI {
|
||||||
if (ctxconfig.major < 1 || ctxconfig.minor < 0) ||
|
if (ctxconfig.major < 1 || ctxconfig.minor < 0) ||
|
||||||
(ctxconfig.major == 1 && ctxconfig.minor > 5) ||
|
(ctxconfig.major == 1 && ctxconfig.minor > 5) ||
|
||||||
@ -249,11 +252,11 @@ func (w *Window) refreshContextAttribs(ctxconfig *ctxconfig) (ferr error) {
|
|||||||
w.context.source = ctxconfig.source
|
w.context.source = ctxconfig.source
|
||||||
w.context.client = OpenGLAPI
|
w.context.client = OpenGLAPI
|
||||||
|
|
||||||
p, err := _glfw.contextSlot.get()
|
p1, err := _glfw.contextSlot.get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
previous := (*Window)(unsafe.Pointer(p))
|
previous := (*Window)(unsafe.Pointer(p1))
|
||||||
defer func() {
|
defer func() {
|
||||||
err := previous.MakeContextCurrent()
|
err := previous.MakeContextCurrent()
|
||||||
if ferr == nil {
|
if ferr == nil {
|
||||||
@ -264,6 +267,14 @@ func (w *Window) refreshContextAttribs(ctxconfig *ctxconfig) (ferr error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p2, err := _glfw.contextSlot.get()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if (*Window)(unsafe.Pointer(p2)) != w {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
getIntegerv := w.context.getProcAddress("glGetIntegerv")
|
getIntegerv := w.context.getProcAddress("glGetIntegerv")
|
||||||
getString := w.context.getProcAddress("glGetString")
|
getString := w.context.getProcAddress("glGetString")
|
||||||
if getIntegerv == 0 || getString == 0 {
|
if getIntegerv == 0 || getString == 0 {
|
||||||
|
@ -66,13 +66,30 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib)
|
|||||||
// Return the EGLConfig most closely matching the specified hints
|
// Return the EGLConfig most closely matching the specified hints
|
||||||
//
|
//
|
||||||
static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
||||||
const _GLFWfbconfig* desired,
|
const _GLFWfbconfig* fbconfig,
|
||||||
EGLConfig* result)
|
EGLConfig* result)
|
||||||
{
|
{
|
||||||
EGLConfig* nativeConfigs;
|
EGLConfig* nativeConfigs;
|
||||||
_GLFWfbconfig* usableConfigs;
|
_GLFWfbconfig* usableConfigs;
|
||||||
const _GLFWfbconfig* closest;
|
const _GLFWfbconfig* closest;
|
||||||
int i, nativeCount, usableCount;
|
int i, nativeCount, usableCount, apiBit;
|
||||||
|
GLFWbool wrongApiAvailable = GLFW_FALSE;
|
||||||
|
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||||
|
{
|
||||||
|
if (ctxconfig->major == 1)
|
||||||
|
apiBit = EGL_OPENGL_ES_BIT;
|
||||||
|
else
|
||||||
|
apiBit = EGL_OPENGL_ES2_BIT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
apiBit = EGL_OPENGL_BIT;
|
||||||
|
|
||||||
|
if (fbconfig->stereo)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Stereo rendering not supported");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
|
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
|
||||||
if (!nativeCount)
|
if (!nativeCount)
|
||||||
@ -109,7 +126,7 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
|||||||
if (!vi.visualid)
|
if (!vi.visualid)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (desired->transparent)
|
if (fbconfig->transparent)
|
||||||
{
|
{
|
||||||
int count;
|
int count;
|
||||||
XVisualInfo* vis =
|
XVisualInfo* vis =
|
||||||
@ -123,22 +140,9 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
|||||||
}
|
}
|
||||||
#endif // _GLFW_X11
|
#endif // _GLFW_X11
|
||||||
|
|
||||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & apiBit))
|
||||||
{
|
{
|
||||||
if (ctxconfig->major == 1)
|
wrongApiAvailable = GLFW_TRUE;
|
||||||
{
|
|
||||||
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ctxconfig->client == GLFW_OPENGL_API)
|
|
||||||
{
|
|
||||||
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,15 +155,44 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
|
|||||||
u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
|
u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
|
||||||
|
|
||||||
u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
|
u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
|
||||||
u->doublebuffer = desired->doublebuffer;
|
u->doublebuffer = fbconfig->doublebuffer;
|
||||||
|
|
||||||
u->handle = (uintptr_t) n;
|
u->handle = (uintptr_t) n;
|
||||||
usableCount++;
|
usableCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
|
closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount);
|
||||||
if (closest)
|
if (closest)
|
||||||
*result = (EGLConfig) closest->handle;
|
*result = (EGLConfig) closest->handle;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (wrongApiAvailable)
|
||||||
|
{
|
||||||
|
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||||
|
{
|
||||||
|
if (ctxconfig->major == 1)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"EGL: Failed to find support for OpenGL ES 1.x");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"EGL: Failed to find support for OpenGL ES 2 or later");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
|
"EGL: Failed to find support for OpenGL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
||||||
|
"EGL: Failed to find a suitable EGLConfig");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
free(nativeConfigs);
|
free(nativeConfigs);
|
||||||
free(usableConfigs);
|
free(usableConfigs);
|
||||||
@ -231,6 +264,7 @@ static int extensionSupportedEGL(const char* extension)
|
|||||||
static GLFWglproc getProcAddressEGL(const char* procname)
|
static GLFWglproc getProcAddressEGL(const char* procname)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
if (window->context.egl.client)
|
if (window->context.egl.client)
|
||||||
{
|
{
|
||||||
@ -454,11 +488,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
|||||||
share = ctxconfig->share->context.egl.handle;
|
share = ctxconfig->share->context.egl.handle;
|
||||||
|
|
||||||
if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
|
if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
|
||||||
"EGL: Failed to find a suitable EGLConfig");
|
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||||
{
|
{
|
||||||
@ -515,18 +545,18 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
|||||||
flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
|
flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctxconfig->noerror)
|
|
||||||
{
|
|
||||||
if (_glfw.egl.KHR_create_context_no_error)
|
|
||||||
setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
|
||||||
{
|
{
|
||||||
setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
|
setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
|
||||||
setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
|
setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctxconfig->noerror)
|
||||||
|
{
|
||||||
|
if (_glfw.egl.KHR_create_context_no_error)
|
||||||
|
setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
if (mask)
|
if (mask)
|
||||||
setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
|
setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
|
||||||
|
|
||||||
@ -578,9 +608,6 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
|||||||
if (!fbconfig->doublebuffer)
|
if (!fbconfig->doublebuffer)
|
||||||
setAttrib(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
|
setAttrib(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
|
||||||
|
|
||||||
if (_glfw.egl.EXT_present_opaque)
|
|
||||||
setAttrib(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent);
|
|
||||||
|
|
||||||
setAttrib(EGL_NONE, EGL_NONE);
|
setAttrib(EGL_NONE, EGL_NONE);
|
||||||
|
|
||||||
window->context.egl.surface =
|
window->context.egl.surface =
|
||||||
@ -640,6 +667,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
|
|||||||
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
#elif defined(__OpenBSD__) || defined(__NetBSD__)
|
||||||
"libGL.so",
|
"libGL.so",
|
||||||
#else
|
#else
|
||||||
|
"libOpenGL.so.0",
|
||||||
"libGL.so.1",
|
"libGL.so.1",
|
||||||
#endif
|
#endif
|
||||||
NULL
|
NULL
|
||||||
@ -702,11 +730,7 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
|
|||||||
const long vimask = VisualScreenMask | VisualIDMask;
|
const long vimask = VisualScreenMask | VisualIDMask;
|
||||||
|
|
||||||
if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
|
if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
|
||||||
{
|
|
||||||
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
|
|
||||||
"EGL: Failed to find a suitable EGLConfig");
|
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
|
||||||
|
|
||||||
eglGetConfigAttrib(_glfw.egl.display, native,
|
eglGetConfigAttrib(_glfw.egl.display, native,
|
||||||
EGL_NATIVE_VISUAL_ID, &visualID);
|
EGL_NATIVE_VISUAL_ID, &visualID);
|
||||||
|
@ -249,7 +249,7 @@ extern "C" {
|
|||||||
* release is made that does not contain any API changes.
|
* release is made that does not contain any API changes.
|
||||||
* @ingroup init
|
* @ingroup init
|
||||||
*/
|
*/
|
||||||
#define GLFW_VERSION_REVISION 8
|
#define GLFW_VERSION_REVISION 10
|
||||||
/*! @} */
|
/*! @} */
|
||||||
|
|
||||||
/*! @brief One.
|
/*! @brief One.
|
||||||
@ -296,8 +296,12 @@ extern "C" {
|
|||||||
#define GLFW_REPEAT 2
|
#define GLFW_REPEAT 2
|
||||||
/*! @} */
|
/*! @} */
|
||||||
|
|
||||||
/*! @defgroup keys Keyboard keys
|
/*! @ingroup input
|
||||||
* @brief Keyboard key IDs.
|
*/
|
||||||
|
#define GLFW_KEY_UNKNOWN -1
|
||||||
|
|
||||||
|
/*! @defgroup keys Keyboard key tokens
|
||||||
|
* @brief Keyboard key tokens.
|
||||||
*
|
*
|
||||||
* See [key input](@ref input_key) for how these are used.
|
* See [key input](@ref input_key) for how these are used.
|
||||||
*
|
*
|
||||||
@ -320,8 +324,6 @@ extern "C" {
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* The unknown key */
|
|
||||||
#define GLFW_KEY_UNKNOWN -1
|
|
||||||
|
|
||||||
/* Printable keys */
|
/* Printable keys */
|
||||||
#define GLFW_KEY_SPACE 32
|
#define GLFW_KEY_SPACE 32
|
||||||
@ -1590,6 +1592,14 @@ typedef struct GLFWimage
|
|||||||
* bundle, if present. This can be disabled with the @ref
|
* bundle, if present. This can be disabled with the @ref
|
||||||
* GLFW_COCOA_CHDIR_RESOURCES init hint.
|
* GLFW_COCOA_CHDIR_RESOURCES init hint.
|
||||||
*
|
*
|
||||||
|
* @remark @macos This function will create the main menu and dock icon for the
|
||||||
|
* application. If GLFW finds a `MainMenu.nib` it is loaded and assumed to
|
||||||
|
* contain a menu bar. Otherwise a minimal menu bar is created manually with
|
||||||
|
* common commands like Hide, Quit and About. The About entry opens a minimal
|
||||||
|
* about dialog with information from the application's bundle. The menu bar
|
||||||
|
* and dock icon can be disabled entirely with the @ref GLFW_COCOA_MENUBAR init
|
||||||
|
* hint.
|
||||||
|
*
|
||||||
* @remark @x11 This function will set the `LC_CTYPE` category of the
|
* @remark @x11 This function will set the `LC_CTYPE` category of the
|
||||||
* application locale according to the current environment if that category is
|
* application locale according to the current environment if that category is
|
||||||
* still "C". This is because the "C" locale breaks Unicode text input.
|
* still "C". This is because the "C" locale breaks Unicode text input.
|
||||||
@ -2410,8 +2420,8 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value);
|
|||||||
*
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||||
* GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref
|
* GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_API_UNAVAILABLE, @ref
|
||||||
* GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE and @ref
|
* GLFW_VERSION_UNAVAILABLE, @ref GLFW_FORMAT_UNAVAILABLE, @ref
|
||||||
* GLFW_PLATFORM_ERROR.
|
* GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR.
|
||||||
*
|
*
|
||||||
* @remark @win32 Window creation will fail if the Microsoft GDI software
|
* @remark @win32 Window creation will fail if the Microsoft GDI software
|
||||||
* OpenGL implementation is the only one available.
|
* OpenGL implementation is the only one available.
|
||||||
@ -2437,13 +2447,6 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value);
|
|||||||
* [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
|
* [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/)
|
||||||
* in the Mac Developer Library.
|
* in the Mac Developer Library.
|
||||||
*
|
*
|
||||||
* @remark @macos The first time a window is created the menu bar is created.
|
|
||||||
* If GLFW finds a `MainMenu.nib` it is loaded and assumed to contain a menu
|
|
||||||
* bar. Otherwise a minimal menu bar is created manually with common commands
|
|
||||||
* like Hide, Quit and About. The About entry opens a minimal about dialog
|
|
||||||
* with information from the application's bundle. Menu bar creation can be
|
|
||||||
* disabled entirely with the @ref GLFW_COCOA_MENUBAR init hint.
|
|
||||||
*
|
|
||||||
* @remark @macos On OS X 10.10 and later the window frame will not be rendered
|
* @remark @macos On OS X 10.10 and later the window frame will not be rendered
|
||||||
* at full resolution on Retina displays unless the
|
* at full resolution on Retina displays unless the
|
||||||
* [GLFW_COCOA_RETINA_FRAMEBUFFER](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint)
|
* [GLFW_COCOA_RETINA_FRAMEBUFFER](@ref GLFW_COCOA_RETINA_FRAMEBUFFER_hint)
|
||||||
@ -3360,11 +3363,15 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib);
|
|||||||
* @param[in] value `GLFW_TRUE` or `GLFW_FALSE`.
|
* @param[in] value `GLFW_TRUE` or `GLFW_FALSE`.
|
||||||
*
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||||
* GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
|
* GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_PLATFORM_ERROR.
|
||||||
*
|
*
|
||||||
* @remark Calling @ref glfwGetWindowAttrib will always return the latest
|
* @remark Calling @ref glfwGetWindowAttrib will always return the latest
|
||||||
* value, even if that value is ignored by the current mode of the window.
|
* value, even if that value is ignored by the current mode of the window.
|
||||||
*
|
*
|
||||||
|
* @remark @wayland The [GLFW_FLOATING](@ref GLFW_FLOATING_attrib) window
|
||||||
|
* attribute is not supported. Setting this will emit @ref
|
||||||
|
* GLFW_PLATFORM_ERROR.
|
||||||
|
*
|
||||||
* @thread_safety This function must only be called from the main thread.
|
* @thread_safety This function must only be called from the main thread.
|
||||||
*
|
*
|
||||||
* @sa @ref window_attribs
|
* @sa @ref window_attribs
|
||||||
@ -4039,8 +4046,8 @@ GLFWAPI int glfwRawMouseMotionSupported(void);
|
|||||||
* @param[in] scancode The scancode of the key to query.
|
* @param[in] scancode The scancode of the key to query.
|
||||||
* @return The UTF-8 encoded, layout-specific name of the key, or `NULL`.
|
* @return The UTF-8 encoded, layout-specific name of the key, or `NULL`.
|
||||||
*
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||||
* GLFW_PLATFORM_ERROR.
|
* GLFW_INVALID_VALUE, @ref GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
|
||||||
*
|
*
|
||||||
* @remark The contents of the returned string may change when a keyboard
|
* @remark The contents of the returned string may change when a keyboard
|
||||||
* layout change event is received.
|
* layout change event is received.
|
||||||
@ -4062,15 +4069,18 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode);
|
|||||||
*
|
*
|
||||||
* This function returns the platform-specific scancode of the specified key.
|
* This function returns the platform-specific scancode of the specified key.
|
||||||
*
|
*
|
||||||
* If the key is `GLFW_KEY_UNKNOWN` or does not exist on the keyboard this
|
* If the specified [key token](@ref keys) corresponds to a physical key not
|
||||||
* method will return `-1`.
|
* supported on the current platform then this method will return `-1`.
|
||||||
|
* Calling this function with anything other than a key token will return `-1`
|
||||||
|
* and generate a @ref GLFW_INVALID_ENUM error.
|
||||||
*
|
*
|
||||||
* @param[in] key Any [named key](@ref keys).
|
* @param[in] key Any [key token](@ref keys).
|
||||||
* @return The platform-specific scancode for the key, or `-1` if an
|
* @return The platform-specific scancode for the key, or `-1` if the key is
|
||||||
* [error](@ref error_handling) occurred.
|
* not supported on the current platform or an [error](@ref error_handling)
|
||||||
|
* occurred.
|
||||||
*
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
|
||||||
* GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
|
* GLFW_INVALID_ENUM.
|
||||||
*
|
*
|
||||||
* @thread_safety This function may be called from any thread.
|
* @thread_safety This function may be called from any thread.
|
||||||
*
|
*
|
||||||
@ -4354,10 +4364,9 @@ GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor);
|
|||||||
* [character callback](@ref glfwSetCharCallback) instead.
|
* [character callback](@ref glfwSetCharCallback) instead.
|
||||||
*
|
*
|
||||||
* When a window loses input focus, it will generate synthetic key release
|
* When a window loses input focus, it will generate synthetic key release
|
||||||
* events for all pressed keys. You can tell these events from user-generated
|
* events for all pressed keys with associated key tokens. You can tell these
|
||||||
* events by the fact that the synthetic ones are generated after the focus
|
* events from user-generated events by the fact that the synthetic ones are
|
||||||
* loss event has been processed, i.e. after the
|
* generated after the focus loss event has been processed, i.e. after the
|
||||||
* [window focus callback](@ref glfwSetWindowFocusCallback) has been called.
|
|
||||||
*
|
*
|
||||||
* The scancode of a key is specific to that platform or sometimes even to that
|
* The scancode of a key is specific to that platform or sometimes even to that
|
||||||
* machine. Scancodes are intended to allow users to bind keys that don't have
|
* machine. Scancodes are intended to allow users to bind keys that don't have
|
||||||
@ -4708,12 +4717,15 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window);
|
|||||||
* thread.
|
* thread.
|
||||||
*
|
*
|
||||||
* This function makes the OpenGL or OpenGL ES context of the specified window
|
* This function makes the OpenGL or OpenGL ES context of the specified window
|
||||||
* current on the calling thread. A context must only be made current on
|
* current on the calling thread. It can also detach the current context from
|
||||||
* a single thread at a time and each thread can have only a single current
|
* the calling thread without making a new one current by passing in `NULL`.
|
||||||
* context at a time.
|
|
||||||
*
|
*
|
||||||
* When moving a context between threads, you must make it non-current on the
|
* A context must only be made current on a single thread at a time and each
|
||||||
* old thread before making it current on the new one.
|
* thread can have only a single current context at a time. Making a context
|
||||||
|
* current detaches any previously current context on the calling thread.
|
||||||
|
*
|
||||||
|
* When moving a context between threads, you must detach it (make it
|
||||||
|
* non-current) on the old thread before making it current on the new one.
|
||||||
*
|
*
|
||||||
* By default, making a context non-current implicitly forces a pipeline flush.
|
* By default, making a context non-current implicitly forces a pipeline flush.
|
||||||
* On machines that support `GL_KHR_context_flush_control`, you can control
|
* On machines that support `GL_KHR_context_flush_control`, you can control
|
||||||
@ -4728,6 +4740,10 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window);
|
|||||||
* @param[in] window The window whose context to make current, or `NULL` to
|
* @param[in] window The window whose context to make current, or `NULL` to
|
||||||
* detach the current context.
|
* detach the current context.
|
||||||
*
|
*
|
||||||
|
* @remarks If the previously current context was created via a different
|
||||||
|
* context creation API than the one passed to this function, GLFW will still
|
||||||
|
* detach the previous one from its API before making the new one current.
|
||||||
|
*
|
||||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
|
||||||
* GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR.
|
* GLFW_NO_WINDOW_CONTEXT and @ref GLFW_PLATFORM_ERROR.
|
||||||
*
|
*
|
||||||
|
@ -99,7 +99,9 @@ extern "C" {
|
|||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
#include <objc/objc.h>
|
#include <objc/objc.h>
|
||||||
#endif
|
#endif
|
||||||
#elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX)
|
#endif
|
||||||
|
|
||||||
|
#if defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX)
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/extensions/Xrandr.h>
|
#include <X11/extensions/Xrandr.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -168,6 +168,7 @@ static void swapBuffersGLX(_GLFWwindow* window)
|
|||||||
static void swapIntervalGLX(int interval)
|
static void swapIntervalGLX(int interval)
|
||||||
{
|
{
|
||||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
|
assert(window != NULL);
|
||||||
|
|
||||||
if (_glfw.glx.EXT_swap_control)
|
if (_glfw.glx.EXT_swap_control)
|
||||||
{
|
{
|
||||||
@ -204,7 +205,10 @@ static GLFWglproc getProcAddressGLX(const char* procname)
|
|||||||
else if (_glfw.glx.GetProcAddressARB)
|
else if (_glfw.glx.GetProcAddressARB)
|
||||||
return _glfw.glx.GetProcAddressARB((const GLubyte*) procname);
|
return _glfw.glx.GetProcAddressARB((const GLubyte*) procname);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
// NOTE: glvnd provides GLX 1.4, so this can only happen with libGL
|
||||||
return _glfw_dlsym(_glfw.glx.handle, procname);
|
return _glfw_dlsym(_glfw.glx.handle, procname);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroyContextGLX(_GLFWwindow* window)
|
static void destroyContextGLX(_GLFWwindow* window)
|
||||||
|
@ -107,7 +107,6 @@ typedef struct _GLFWlibraryGLX
|
|||||||
int eventBase;
|
int eventBase;
|
||||||
int errorBase;
|
int errorBase;
|
||||||
|
|
||||||
// dlopen handle for libGL.so.1
|
|
||||||
void* handle;
|
void* handle;
|
||||||
|
|
||||||
// GLX 1.3 functions
|
// GLX 1.3 functions
|
||||||
|
@ -280,6 +280,12 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode)
|
|||||||
|
|
||||||
if (key != GLFW_KEY_UNKNOWN)
|
if (key != GLFW_KEY_UNKNOWN)
|
||||||
{
|
{
|
||||||
|
if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (key != GLFW_KEY_KP_EQUAL &&
|
if (key != GLFW_KEY_KP_EQUAL &&
|
||||||
(key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) &&
|
(key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) &&
|
||||||
(key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2))
|
(key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2))
|
||||||
@ -295,12 +301,12 @@ GLFWAPI const char* glfwGetKeyName(int key, int scancode)
|
|||||||
|
|
||||||
GLFWAPI int glfwGetKeyScancode(int key)
|
GLFWAPI int glfwGetKeyScancode(int key)
|
||||||
{
|
{
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(-1);
|
_GLFW_REQUIRE_INIT_OR_RETURN(0);
|
||||||
|
|
||||||
if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
|
if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
|
_glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
|
||||||
return GLFW_RELEASE;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _glfwPlatformGetKeyScancode(key);
|
return _glfwPlatformGetKeyScancode(key);
|
||||||
|
@ -246,6 +246,9 @@ func GetKeyName(key Key, scancode int) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if key != KeyUnknown {
|
if key != KeyUnknown {
|
||||||
|
if key < KeySpace || key > KeyLast {
|
||||||
|
return "", fmt.Errorf("glfw: invalid key %d: %w", key, InvalidEnum)
|
||||||
|
}
|
||||||
if key != KeyKPEqual && (key < KeyKP0 || key > KeyKPAdd) && (key < KeyApostrophe || key > KeyWorld2) {
|
if key != KeyKPEqual && (key < KeyKP0 || key > KeyKPAdd) && (key < KeyApostrophe || key > KeyWorld2) {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
@ -57,11 +57,10 @@ static void swapIntervalNSGL(int interval)
|
|||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
|
|
||||||
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
_GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot);
|
||||||
if (window)
|
assert(window != NULL);
|
||||||
{
|
|
||||||
[window->context.nsgl.object setValues:&interval
|
[window->context.nsgl.object setValues:&interval
|
||||||
forParameter:NSOpenGLContextParameterSwapInterval];
|
forParameter:NSOpenGLContextParameterSwapInterval];
|
||||||
}
|
|
||||||
|
|
||||||
} // autoreleasepool
|
} // autoreleasepool
|
||||||
}
|
}
|
||||||
@ -138,7 +137,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
|||||||
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
if (ctxconfig->client == GLFW_OPENGL_ES_API)
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_API_UNAVAILABLE,
|
_glfwInputError(GLFW_API_UNAVAILABLE,
|
||||||
"NSGL: OpenGL ES is not available on macOS");
|
"NSGL: OpenGL ES is not available via NSGL");
|
||||||
return GLFW_FALSE;
|
return GLFW_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,13 +5,12 @@
|
|||||||
|
|
||||||
//go:build darwin || freebsd || linux || netbsd || openbsd
|
//go:build darwin || freebsd || linux || netbsd || openbsd
|
||||||
|
|
||||||
|
#include "internal_unix.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "internal_unix.h"
|
|
||||||
|
|
||||||
|
|
||||||
static void makeContextCurrentOSMesa(_GLFWwindow* window)
|
static void makeContextCurrentOSMesa(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
if (window)
|
if (window)
|
||||||
|
@ -53,11 +53,24 @@ func (w *Window) choosePixelFormat(ctxconfig *ctxconfig, fbconfig_ *fbconfig) (i
|
|||||||
var nativeCount int32
|
var nativeCount int32
|
||||||
var attribs []int32
|
var attribs []int32
|
||||||
|
|
||||||
if _glfw.platformContext.ARB_pixel_format {
|
c, err := _DescribePixelFormat(w.context.platform.dc, 1, uint32(unsafe.Sizeof(_PIXELFORMATDESCRIPTOR{})), nil)
|
||||||
var attrib int32 = _WGL_NUMBER_PIXEL_FORMATS_ARB
|
if err != nil {
|
||||||
if err := wglGetPixelFormatAttribivARB(w.context.platform.dc, 1, 0, 1, &attrib, &nativeCount); err != nil {
|
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
nativeCount = c
|
||||||
|
|
||||||
|
if _glfw.platformContext.ARB_pixel_format {
|
||||||
|
// NOTE: In a Parallels VM WGL_ARB_pixel_format returns fewer pixel formats than
|
||||||
|
// DescribePixelFormat, violating the guarantees of the extension spec
|
||||||
|
// HACK: Iterate through the minimum of both counts
|
||||||
|
var attrib int32 = _WGL_NUMBER_PIXEL_FORMATS_ARB
|
||||||
|
var extensionCount int32
|
||||||
|
if err := wglGetPixelFormatAttribivARB(w.context.platform.dc, 1, 0, 1, &attrib, &extensionCount); err != nil {
|
||||||
|
return 0, fmt.Errorf("glfw: WGL: failed to retrieve pixel format attribute: %w", err)
|
||||||
|
}
|
||||||
|
if nativeCount > extensionCount {
|
||||||
|
nativeCount = extensionCount
|
||||||
|
}
|
||||||
|
|
||||||
attribs = append(attribs,
|
attribs = append(attribs,
|
||||||
_WGL_SUPPORT_OPENGL_ARB,
|
_WGL_SUPPORT_OPENGL_ARB,
|
||||||
@ -96,12 +109,6 @@ func (w *Window) choosePixelFormat(ctxconfig *ctxconfig, fbconfig_ *fbconfig) (i
|
|||||||
attribs = append(attribs, _WGL_COLORSPACE_EXT)
|
attribs = append(attribs, _WGL_COLORSPACE_EXT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
c, err := _DescribePixelFormat(w.context.platform.dc, 1, uint32(unsafe.Sizeof(_PIXELFORMATDESCRIPTOR{})), nil)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
nativeCount = c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
usableConfigs := make([]*fbconfig, 0, nativeCount)
|
usableConfigs := make([]*fbconfig, 0, nativeCount)
|
||||||
@ -254,19 +261,13 @@ func makeContextCurrentWGL(window *Window) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func swapBuffersWGL(window *Window) error {
|
func swapBuffersWGL(window *Window) error {
|
||||||
if window.monitor == nil && winver.IsWindowsVistaOrGreater() {
|
if window.monitor == nil {
|
||||||
// DWM Composition is always enabled on Win8+
|
// HACK: Use DwmFlush when desktop composition is enabled on Windows Vista and 7
|
||||||
enabled := winver.IsWindows8OrGreater()
|
if !winver.IsWindows8OrGreater() && winver.IsWindowsVistaOrGreater() {
|
||||||
|
enabled, err := _DwmIsCompositionEnabled()
|
||||||
if !enabled {
|
|
||||||
var err error
|
|
||||||
enabled, err = _DwmIsCompositionEnabled()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// HACK: Use DwmFlush when desktop composition is enabled
|
|
||||||
if enabled {
|
if enabled {
|
||||||
for i := 0; i < window.context.platform.interval; i++ {
|
for i := 0; i < window.context.platform.interval; i++ {
|
||||||
// Ignore an error from DWM functions as they might not be implemented e.g. on Proton (#2113).
|
// Ignore an error from DWM functions as they might not be implemented e.g. on Proton (#2113).
|
||||||
@ -274,6 +275,7 @@ func swapBuffersWGL(window *Window) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := _SwapBuffers(window.context.platform.dc); err != nil {
|
if err := _SwapBuffers(window.context.platform.dc); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -290,24 +292,20 @@ func swapIntervalWGL(interval int) error {
|
|||||||
|
|
||||||
window.context.platform.interval = interval
|
window.context.platform.interval = interval
|
||||||
|
|
||||||
if window.monitor == nil && winver.IsWindowsVistaOrGreater() {
|
if window.monitor == nil {
|
||||||
// DWM Composition is always enabled on Win8+
|
// HACK: Disable WGL swap interval when desktop composition is enabled on Windows
|
||||||
enabled := winver.IsWindows8OrGreater()
|
// Vista and 7 to avoid interfering with DWM vsync
|
||||||
|
if !winver.IsWindows8OrGreater() && winver.IsWindowsVistaOrGreater() {
|
||||||
if !enabled {
|
enabled, err := _DwmIsCompositionEnabled()
|
||||||
e, err := _DwmIsCompositionEnabled()
|
|
||||||
// Ignore an error from DWM functions as they might not be implemented e.g. on Proton (#2113).
|
// Ignore an error from DWM functions as they might not be implemented e.g. on Proton (#2113).
|
||||||
if err == nil {
|
if err == nil {
|
||||||
enabled = e
|
enabled = false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// HACK: Disable WGL swap interval when desktop composition is enabled to
|
|
||||||
// avoid interfering with DWM vsync
|
|
||||||
if enabled {
|
if enabled {
|
||||||
interval = 0
|
interval = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if _glfw.platformContext.EXT_swap_control {
|
if _glfw.platformContext.EXT_swap_control {
|
||||||
if err := wglSwapIntervalEXT(int32(interval)); err != nil {
|
if err := wglSwapIntervalEXT(int32(interval)); err != nil {
|
||||||
|
@ -239,6 +239,55 @@ func createHelperWindow() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createBlankCursor() error {
|
||||||
|
// HACK: Create a transparent cursor as using the NULL cursor breaks
|
||||||
|
// using SetCursorPos when connected over RDP
|
||||||
|
cursorWidth, err := _GetSystemMetrics(_SM_CXCURSOR)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cursorHeight, err := _GetSystemMetrics(_SM_CYCURSOR)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
andMask := make([]byte, cursorWidth*cursorHeight/8)
|
||||||
|
for i := range andMask {
|
||||||
|
andMask[i] = 0xff
|
||||||
|
}
|
||||||
|
xorMask := make([]byte, cursorWidth*cursorHeight/8)
|
||||||
|
|
||||||
|
// Cursor creation might fail, but that's fine as we get NULL in that case,
|
||||||
|
// which serves as an acceptable fallback blank cursor (other than on RDP)
|
||||||
|
c, _ := _CreateCursor(0, 0, 0, cursorWidth, cursorHeight, andMask, xorMask)
|
||||||
|
_glfw.platformWindow.blankCursor = c
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initRemoteSession() error {
|
||||||
|
if microsoftgdk.IsXbox() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the current progress was started with Remote Desktop.
|
||||||
|
r, err := _GetSystemMetrics(_SM_REMOTESESSION)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_glfw.platformWindow.isRemoteSession = r > 0
|
||||||
|
|
||||||
|
// With Remote desktop, we need to create a blank cursor because of the cursor is Set to nil
|
||||||
|
// if cannot be moved to center in capture mode. If not Remote Desktop platformWindow.blankCursor stays nil
|
||||||
|
// and will perform has before (normal).
|
||||||
|
if _glfw.platformWindow.isRemoteSession {
|
||||||
|
if err := createBlankCursor(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func platformInit() error {
|
func platformInit() error {
|
||||||
// Changing the foreground lock timeout was removed from the original code.
|
// Changing the foreground lock timeout was removed from the original code.
|
||||||
// See https://github.com/glfw/glfw/commit/58b48a3a00d9c2a5ca10cc23069a71d8773cc7a4
|
// See https://github.com/glfw/glfw/commit/58b48a3a00d9c2a5ca10cc23069a71d8773cc7a4
|
||||||
@ -293,6 +342,10 @@ func platformInit() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Some hacks are needed to support Remote Desktop...
|
||||||
|
if err := initRemoteSession(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := pollMonitorsWin32(); err != nil {
|
if err := pollMonitorsWin32(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -301,6 +354,12 @@ func platformInit() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func platformTerminate() error {
|
func platformTerminate() error {
|
||||||
|
if _glfw.platformWindow.blankCursor != 0 {
|
||||||
|
if err := _DestroyCursor(_glfw.platformWindow.blankCursor); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if _glfw.platformWindow.deviceNotificationHandle != 0 {
|
if _glfw.platformWindow.deviceNotificationHandle != 0 {
|
||||||
if err := _UnregisterDeviceNotification(_glfw.platformWindow.deviceNotificationHandle); err != nil {
|
if err := _UnregisterDeviceNotification(_glfw.platformWindow.deviceNotificationHandle); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -66,12 +66,18 @@ type platformLibraryWindowState struct {
|
|||||||
scancodes [KeyLast + 1]int
|
scancodes [KeyLast + 1]int
|
||||||
keynames [KeyLast + 1]string
|
keynames [KeyLast + 1]string
|
||||||
|
|
||||||
// Where to place the cursor when re-enabled
|
// restoreCursorPosX and restoreCursorPosY indicates where to place the cursor when re-enabled
|
||||||
restoreCursorPosX float64
|
restoreCursorPosX float64
|
||||||
restoreCursorPosY float64
|
restoreCursorPosY float64
|
||||||
|
|
||||||
// The window whose disabled cursor mode is active
|
// disabledCursorWindow is the window whose disabled cursor mode is active
|
||||||
disabledCursorWindow *Window
|
disabledCursorWindow *Window
|
||||||
|
// capturedCursorWindow is the window the cursor is captured in
|
||||||
|
capturedCursorWindow *Window
|
||||||
rawInput []byte
|
rawInput []byte
|
||||||
mouseTrailSize uint32
|
mouseTrailSize uint32
|
||||||
|
// isRemoteSession indicates if the process was started behind Remote Destop
|
||||||
|
isRemoteSession bool
|
||||||
|
// blankCursor is an invisible cursor, needed for special cases (see WM_INPUT handler)
|
||||||
|
blankCursor _HCURSOR
|
||||||
}
|
}
|
||||||
|
@ -127,48 +127,29 @@ func createIcon(image *Image, xhot, yhot int, icon bool) (_HICON, error) {
|
|||||||
return handle, nil
|
return handle, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFullWindowSize(style uint32, exStyle uint32, contentWidth, contentHeight int, dpi uint32) (fullWidth, fullHeight int, err error) {
|
func (w *Window) applyAspectRatio(edge int, area *_RECT) error {
|
||||||
if microsoftgdk.IsXbox() {
|
var frame _RECT
|
||||||
return contentWidth, contentHeight, nil
|
|
||||||
}
|
ratio := float32(w.numer) / float32(w.denom)
|
||||||
|
style := w.getWindowStyle()
|
||||||
|
exStyle := w.getWindowExStyle()
|
||||||
|
|
||||||
rect := _RECT{
|
|
||||||
left: 0,
|
|
||||||
top: 0,
|
|
||||||
right: int32(contentWidth),
|
|
||||||
bottom: int32(contentHeight),
|
|
||||||
}
|
|
||||||
if winver.IsWindows10AnniversaryUpdateOrGreater() {
|
if winver.IsWindows10AnniversaryUpdateOrGreater() {
|
||||||
if err := _AdjustWindowRectExForDpi(&rect, style, false, exStyle, dpi); err != nil {
|
if err := _AdjustWindowRectExForDpi(&frame, style, false, exStyle, _GetDpiForWindow(w.platform.handle)); err != nil {
|
||||||
return 0, 0, err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err := _AdjustWindowRectEx(&rect, style, false, exStyle); err != nil {
|
if err := _AdjustWindowRectEx(&frame, style, false, exStyle); err != nil {
|
||||||
return 0, 0, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return int(rect.right - rect.left), int(rect.bottom - rect.top), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Window) applyAspectRatio(edge int, area *_RECT) error {
|
|
||||||
ratio := float32(w.numer) / float32(w.denom)
|
|
||||||
|
|
||||||
var dpi uint32 = _USER_DEFAULT_SCREEN_DPI
|
|
||||||
if winver.IsWindows10AnniversaryUpdateOrGreater() {
|
|
||||||
dpi = _GetDpiForWindow(w.platform.handle)
|
|
||||||
}
|
|
||||||
|
|
||||||
xoff, yoff, err := getFullWindowSize(w.getWindowStyle(), w.getWindowExStyle(), 0, 0, dpi)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if edge == _WMSZ_LEFT || edge == _WMSZ_BOTTOMLEFT || edge == _WMSZ_RIGHT || edge == _WMSZ_BOTTOMRIGHT {
|
if edge == _WMSZ_LEFT || edge == _WMSZ_BOTTOMLEFT || edge == _WMSZ_RIGHT || edge == _WMSZ_BOTTOMRIGHT {
|
||||||
area.bottom = area.top + int32(yoff) + int32(float32(area.right-area.left-int32(xoff))/ratio)
|
area.bottom = area.top + int32(frame.bottom-frame.top) + int32(float32(area.right-area.left-int32(frame.right-frame.left))/ratio)
|
||||||
} else if edge == _WMSZ_TOPLEFT || edge == _WMSZ_TOPRIGHT {
|
} else if edge == _WMSZ_TOPLEFT || edge == _WMSZ_TOPRIGHT {
|
||||||
area.top = area.bottom - int32(yoff) - int32(float32(area.right-area.left-int32(xoff))/ratio)
|
area.top = area.bottom - int32(frame.bottom-frame.top) - int32(float32(area.right-area.left-int32(frame.right-frame.left))/ratio)
|
||||||
} else if edge == _WMSZ_TOP || edge == _WMSZ_BOTTOM {
|
} else if edge == _WMSZ_TOP || edge == _WMSZ_BOTTOM {
|
||||||
area.right = area.left + int32(xoff) + int32(float32(area.bottom-area.top-int32(yoff))*ratio)
|
area.right = area.left + int32(frame.right-frame.left) + int32(float32(area.bottom-area.top-int32(frame.bottom-frame.top))*ratio)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -186,7 +167,10 @@ func (w *Window) updateCursorImage() error {
|
|||||||
_SetCursor(cursor)
|
_SetCursor(cursor)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_SetCursor(0)
|
// Connected via Remote Desktop, nil cursor will present SetCursorPos the move the cursor.
|
||||||
|
// using a blank cursor fix that.
|
||||||
|
// When not via Remote Desktop, platformWindow.blankCursor should be nil.
|
||||||
|
_SetCursor(_glfw.platformWindow.blankCursor)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -214,26 +198,27 @@ func (w *Window) clientToScreen(rect _RECT) (_RECT, error) {
|
|||||||
return rect, nil
|
return rect, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateClipRect(window *Window) error {
|
func captureCursor(window *Window) error {
|
||||||
if window != nil {
|
|
||||||
clipRect, err := _GetClientRect(window.platform.handle)
|
clipRect, err := _GetClientRect(window.platform.handle)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
clipRect, err = window.clientToScreen(clipRect)
|
clipRect, err = window.clientToScreen(clipRect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := _ClipCursor(&clipRect); err != nil {
|
if err := _ClipCursor(&clipRect); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
_glfw.platformWindow.capturedCursorWindow = window
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func releaseCursor() error {
|
||||||
if err := _ClipCursor(nil); err != nil {
|
if err := _ClipCursor(nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
_glfw.platformWindow.capturedCursorWindow = nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +259,7 @@ func (w *Window) disableCursor() error {
|
|||||||
if err := w.centerCursorInContentArea(); err != nil {
|
if err := w.centerCursorInContentArea(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := updateClipRect(w); err != nil {
|
if err := captureCursor(w); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if w.rawMouseMotion {
|
if w.rawMouseMotion {
|
||||||
@ -292,7 +277,7 @@ func (w *Window) enableCursor() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_glfw.platformWindow.disabledCursorWindow = nil
|
_glfw.platformWindow.disabledCursorWindow = nil
|
||||||
if err := updateClipRect(nil); err != nil {
|
if err := releaseCursor(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := w.platformSetCursorPos(_glfw.platformWindow.restoreCursorPosX, _glfw.platformWindow.restoreCursorPosY); err != nil {
|
if err := w.platformSetCursorPos(_glfw.platformWindow.restoreCursorPosX, _glfw.platformWindow.restoreCursorPosY); err != nil {
|
||||||
@ -925,8 +910,46 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
|
|||||||
var dx, dy int
|
var dx, dy int
|
||||||
data := (*_RAWINPUT)(unsafe.Pointer(&_glfw.platformWindow.rawInput[0]))
|
data := (*_RAWINPUT)(unsafe.Pointer(&_glfw.platformWindow.rawInput[0]))
|
||||||
if data.mouse.usFlags&_MOUSE_MOVE_ABSOLUTE != 0 {
|
if data.mouse.usFlags&_MOUSE_MOVE_ABSOLUTE != 0 {
|
||||||
|
if _glfw.platformWindow.isRemoteSession {
|
||||||
|
// Remote Desktop Mode
|
||||||
|
// As per https://github.com/Microsoft/DirectXTK/commit/ef56b63f3739381e451f7a5a5bd2c9779d2a7555
|
||||||
|
// MOUSE_MOVE_ABSOLUTE is a range from 0 through 65535, based on the screen size.
|
||||||
|
// Apparently, absolute mode only occurs over RDP though.
|
||||||
|
var smx int32 = _SM_CXSCREEN
|
||||||
|
var smy int32 = _SM_CYSCREEN
|
||||||
|
if data.mouse.usFlags&_MOUSE_VIRTUAL_DESKTOP != 0 {
|
||||||
|
smx = _SM_CXVIRTUALSCREEN
|
||||||
|
smy = _SM_CYVIRTUALSCREEN
|
||||||
|
}
|
||||||
|
|
||||||
|
width, err := _GetSystemMetrics(smx)
|
||||||
|
if err != nil {
|
||||||
|
_glfw.errors = append(_glfw.errors, err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
height, err := _GetSystemMetrics(smy)
|
||||||
|
if err != nil {
|
||||||
|
_glfw.errors = append(_glfw.errors, err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pos := _POINT{
|
||||||
|
x: int32(float64(data.mouse.lLastX) / 65535.0 * float64(width)),
|
||||||
|
y: int32(float64(data.mouse.lLastY) / 65535.0 * float64(height)),
|
||||||
|
}
|
||||||
|
if err := _ScreenToClient(window.platform.handle, &pos); err != nil {
|
||||||
|
_glfw.errors = append(_glfw.errors, err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = int(pos.x) - window.platform.lastCursorPosX
|
||||||
|
dy = int(pos.y) - window.platform.lastCursorPosY
|
||||||
|
} else {
|
||||||
|
// Normal mode
|
||||||
|
// We should have the right absolute coords in data.mouse
|
||||||
dx = int(data.mouse.lLastX) - window.platform.lastCursorPosX
|
dx = int(data.mouse.lLastX) - window.platform.lastCursorPosX
|
||||||
dy = int(data.mouse.lLastY) - window.platform.lastCursorPosY
|
dy = int(data.mouse.lLastY) - window.platform.lastCursorPosY
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
dx = int(data.mouse.lLastX)
|
dx = int(data.mouse.lLastX)
|
||||||
dy = int(data.mouse.lLastY)
|
dy = int(data.mouse.lLastY)
|
||||||
@ -986,8 +1009,8 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
|
|||||||
iconified := wParam == _SIZE_MINIMIZED
|
iconified := wParam == _SIZE_MINIMIZED
|
||||||
maximized := wParam == _SIZE_MAXIMIZED || (window.platform.maximized && wParam != _SIZE_RESTORED)
|
maximized := wParam == _SIZE_MAXIMIZED || (window.platform.maximized && wParam != _SIZE_RESTORED)
|
||||||
|
|
||||||
if _glfw.platformWindow.disabledCursorWindow == window {
|
if _glfw.platformWindow.capturedCursorWindow == window {
|
||||||
if err := updateClipRect(window); err != nil {
|
if err := captureCursor(window); err != nil {
|
||||||
_glfw.errors = append(_glfw.errors, err)
|
_glfw.errors = append(_glfw.errors, err)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -1032,8 +1055,8 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
case _WM_MOVE:
|
case _WM_MOVE:
|
||||||
if _glfw.platformWindow.disabledCursorWindow == window {
|
if _glfw.platformWindow.capturedCursorWindow == window {
|
||||||
if err := updateClipRect(window); err != nil {
|
if err := captureCursor(window); err != nil {
|
||||||
_glfw.errors = append(_glfw.errors, err)
|
_glfw.errors = append(_glfw.errors, err)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -1056,31 +1079,35 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
case _WM_GETMINMAXINFO:
|
case _WM_GETMINMAXINFO:
|
||||||
var dpi uint32 = _USER_DEFAULT_SCREEN_DPI
|
var frame _RECT
|
||||||
mmi := (*_MINMAXINFO)(unsafe.Pointer(lParam))
|
mmi := (*_MINMAXINFO)(unsafe.Pointer(lParam))
|
||||||
|
style := window.getWindowStyle()
|
||||||
|
exStyle := window.getWindowExStyle()
|
||||||
|
|
||||||
if window.monitor != nil {
|
if window.monitor != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if winver.IsWindows10AnniversaryUpdateOrGreater() {
|
if winver.IsWindows10AnniversaryUpdateOrGreater() {
|
||||||
dpi = _GetDpiForWindow(window.platform.handle)
|
if err := _AdjustWindowRectExForDpi(&frame, style, false, exStyle, _GetDpiForWindow(window.platform.handle)); err != nil {
|
||||||
}
|
|
||||||
|
|
||||||
xoff, yoff, err := getFullWindowSize(window.getWindowStyle(), window.getWindowExStyle(), 0, 0, dpi)
|
|
||||||
if err != nil {
|
|
||||||
_glfw.errors = append(_glfw.errors, err)
|
_glfw.errors = append(_glfw.errors, err)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if err := _AdjustWindowRectEx(&frame, style, false, exStyle); err != nil {
|
||||||
|
_glfw.errors = append(_glfw.errors, err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if window.minwidth != DontCare && window.minheight != DontCare {
|
if window.minwidth != DontCare && window.minheight != DontCare {
|
||||||
mmi.ptMinTrackSize.x = int32(window.minwidth + xoff)
|
mmi.ptMinTrackSize.x = int32(window.minwidth) + (frame.right - frame.left)
|
||||||
mmi.ptMinTrackSize.y = int32(window.minheight + yoff)
|
mmi.ptMinTrackSize.y = int32(window.minheight) + (frame.bottom - frame.top)
|
||||||
}
|
}
|
||||||
|
|
||||||
if window.maxwidth != DontCare && window.maxheight != DontCare {
|
if window.maxwidth != DontCare && window.maxheight != DontCare {
|
||||||
mmi.ptMaxTrackSize.x = int32(window.maxwidth + xoff)
|
mmi.ptMaxTrackSize.x = int32(window.maxwidth) + (frame.right - frame.left)
|
||||||
mmi.ptMaxTrackSize.y = int32(window.maxheight + yoff)
|
mmi.ptMaxTrackSize.y = int32(window.maxheight) + (frame.bottom - frame.top)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !window.decorated {
|
if !window.decorated {
|
||||||
@ -1205,7 +1232,7 @@ func (w *Window) createNativeWindow(wndconfig *wndconfig, fbconfig *fbconfig) er
|
|||||||
style := w.getWindowStyle()
|
style := w.getWindowStyle()
|
||||||
exStyle := w.getWindowExStyle()
|
exStyle := w.getWindowExStyle()
|
||||||
|
|
||||||
var xpos, ypos, fullWidth, fullHeight int32
|
var frameX, frameY, frameWidth, frameHeight int32
|
||||||
if w.monitor != nil {
|
if w.monitor != nil {
|
||||||
mi, ok := _GetMonitorInfoW(w.monitor.platform.handle)
|
mi, ok := _GetMonitorInfoW(w.monitor.platform.handle)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -1214,27 +1241,29 @@ func (w *Window) createNativeWindow(wndconfig *wndconfig, fbconfig *fbconfig) er
|
|||||||
// NOTE: This window placement is temporary and approximate, as the
|
// NOTE: This window placement is temporary and approximate, as the
|
||||||
// correct position and size cannot be known until the monitor
|
// correct position and size cannot be known until the monitor
|
||||||
// video mode has been picked in _glfwSetVideoModeWin32
|
// video mode has been picked in _glfwSetVideoModeWin32
|
||||||
xpos = mi.rcMonitor.left
|
frameX = mi.rcMonitor.left
|
||||||
ypos = mi.rcMonitor.top
|
frameY = mi.rcMonitor.top
|
||||||
fullWidth = mi.rcMonitor.right - mi.rcMonitor.left
|
frameWidth = mi.rcMonitor.right - mi.rcMonitor.left
|
||||||
fullHeight = mi.rcMonitor.bottom - mi.rcMonitor.top
|
frameHeight = mi.rcMonitor.bottom - mi.rcMonitor.top
|
||||||
} else {
|
} else {
|
||||||
xpos = _CW_USEDEFAULT
|
rect := _RECT{0, 0, int32(wndconfig.width), int32(wndconfig.height)}
|
||||||
ypos = _CW_USEDEFAULT
|
|
||||||
|
|
||||||
w.platform.maximized = wndconfig.maximized
|
w.platform.maximized = wndconfig.maximized
|
||||||
if wndconfig.maximized {
|
if wndconfig.maximized {
|
||||||
style |= _WS_MAXIMIZE
|
style |= _WS_MAXIMIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
w, h, err := getFullWindowSize(style, exStyle, wndconfig.width, wndconfig.height, _USER_DEFAULT_SCREEN_DPI)
|
if err := _AdjustWindowRectEx(&rect, style, false, exStyle); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fullWidth, fullHeight = int32(w), int32(h)
|
|
||||||
|
frameX = _CW_USEDEFAULT
|
||||||
|
frameY = _CW_USEDEFAULT
|
||||||
|
frameWidth = rect.right - rect.left
|
||||||
|
frameHeight = rect.bottom - rect.top
|
||||||
}
|
}
|
||||||
|
|
||||||
h, err := _CreateWindowExW(exStyle, _GLFW_WNDCLASSNAME, wndconfig.title, style, xpos, ypos, fullWidth, fullHeight,
|
h, err := _CreateWindowExW(exStyle, _GLFW_WNDCLASSNAME, wndconfig.title, style, frameX, frameY, frameWidth, frameHeight,
|
||||||
0, // No parent window
|
0, // No parent window
|
||||||
0, // No window menu
|
0, // No window menu
|
||||||
_glfw.platformWindow.instance, unsafe.Pointer(wndconfig))
|
_glfw.platformWindow.instance, unsafe.Pointer(wndconfig))
|
||||||
@ -1459,7 +1488,15 @@ func (w *Window) platformDestroyWindow() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _glfw.platformWindow.disabledCursorWindow == w {
|
if _glfw.platformWindow.disabledCursorWindow == w {
|
||||||
_glfw.platformWindow.disabledCursorWindow = nil
|
if err := w.enableCursor(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _glfw.platformWindow.capturedCursorWindow == w {
|
||||||
|
if err := releaseCursor(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if w.platform.handle != 0 {
|
if w.platform.handle != 0 {
|
||||||
@ -2163,6 +2200,7 @@ func platformPollEvents() error {
|
|||||||
|
|
||||||
// NOTE: Re-center the cursor only if it has moved since the last call,
|
// NOTE: Re-center the cursor only if it has moved since the last call,
|
||||||
// to avoid breaking glfwWaitEvents with WM_MOUSEMOVE
|
// to avoid breaking glfwWaitEvents with WM_MOUSEMOVE
|
||||||
|
// The re-center is required in order to prevent the mouse cursor stopping at the edges of the screen.
|
||||||
if window.platform.lastCursorPosX != width/2 || window.platform.lastCursorPosY != height/2 {
|
if window.platform.lastCursorPosX != width/2 || window.platform.lastCursorPosY != height/2 {
|
||||||
if err := window.platformSetCursorPos(float64(width/2), float64(height/2)); err != nil {
|
if err := window.platformSetCursorPos(float64(width/2), float64(height/2)); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -2184,7 +2222,7 @@ func platformWaitEvents() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func platformWaitEventsTimeout(timeout float64) error {
|
func platformWaitEventsTimeout(timeout float64) error {
|
||||||
if _, err := _MsgWaitForMultipleObjects(0, nil, false, uint32(timeout*1e3), _QS_ALLEVENTS); err != nil {
|
if _, err := _MsgWaitForMultipleObjects(0, nil, false, uint32(timeout*1e3), _QS_ALLINPUT); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := platformPollEvents(); err != nil {
|
if err := platformPollEvents(); err != nil {
|
||||||
@ -2235,20 +2273,48 @@ func (w *Window) platformSetCursorPos(xpos, ypos float64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *Window) platformSetCursorMode(mode int) error {
|
func (w *Window) platformSetCursorMode(mode int) error {
|
||||||
if mode == CursorDisabled {
|
|
||||||
if w.platformWindowFocused() {
|
if w.platformWindowFocused() {
|
||||||
if err := w.disableCursor(); err != nil {
|
if mode == CursorDisabled {
|
||||||
|
xpos, ypos, err := w.platformGetCursorPos()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_glfw.platformWindow.restoreCursorPosX = xpos
|
||||||
|
_glfw.platformWindow.restoreCursorPosY = ypos
|
||||||
|
if err := w.centerCursorInContentArea(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if w.rawMouseMotion {
|
||||||
|
if err := w.enableRawMouseMotion(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if _glfw.platformWindow.disabledCursorWindow == w {
|
||||||
|
if w.rawMouseMotion {
|
||||||
|
if err := w.disableRawMouseMotion(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if _glfw.platformWindow.disabledCursorWindow == w {
|
if mode == CursorDisabled {
|
||||||
if err := w.enableCursor(); err != nil {
|
if err := captureCursor(w); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
} else {
|
||||||
|
if err := releaseCursor(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mode == CursorDisabled {
|
||||||
|
_glfw.platformWindow.disabledCursorWindow = w
|
||||||
|
} else {
|
||||||
|
_glfw.platformWindow.disabledCursorWindow = nil
|
||||||
|
if err := w.platformSetCursorPos(_glfw.platformWindow.restoreCursorPosX, _glfw.platformWindow.restoreCursorPosY); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
in, err := w.cursorInContentArea()
|
in, err := w.cursorInContentArea()
|
||||||
@ -2265,10 +2331,14 @@ func (w *Window) platformSetCursorMode(mode int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func platformGetScancodeName(scancode int) (string, error) {
|
func platformGetScancodeName(scancode int) (string, error) {
|
||||||
if scancode < 0 || scancode > (_KF_EXTENDED|0xff) || _glfw.platformWindow.keycodes[scancode] == KeyUnknown {
|
if scancode < 0 || scancode > (_KF_EXTENDED|0xff) {
|
||||||
return "", fmt.Errorf("glwfwin: invalid scancode %d: %w", scancode, InvalidValue)
|
return "", fmt.Errorf("glwfwin: invalid scancode %d: %w", scancode, InvalidValue)
|
||||||
}
|
}
|
||||||
return _glfw.platformWindow.keynames[_glfw.platformWindow.keycodes[scancode]], nil
|
key := _glfw.platformWindow.keycodes[scancode]
|
||||||
|
if key == KeyUnknown {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return _glfw.platformWindow.keynames[key], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func platformGetKeyScancode(key Key) int {
|
func platformGetKeyScancode(key Key) int {
|
||||||
|
@ -676,7 +676,7 @@ GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle)
|
|||||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||||
assert(window != NULL);
|
assert(window != NULL);
|
||||||
|
|
||||||
_GLFW_REQUIRE_INIT_OR_RETURN(1.f);
|
_GLFW_REQUIRE_INIT_OR_RETURN(0.f);
|
||||||
return _glfwPlatformGetWindowOpacity(window);
|
return _glfwPlatformGetWindowOpacity(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,6 +357,11 @@ static void updateNormalHints(_GLFWwindow* window, int width, int height)
|
|||||||
{
|
{
|
||||||
XSizeHints* hints = XAllocSizeHints();
|
XSizeHints* hints = XAllocSizeHints();
|
||||||
|
|
||||||
|
long supplied;
|
||||||
|
XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied);
|
||||||
|
|
||||||
|
hints->flags &= ~(PMinSize | PMaxSize | PAspect);
|
||||||
|
|
||||||
if (!window->monitor)
|
if (!window->monitor)
|
||||||
{
|
{
|
||||||
if (window->resizable)
|
if (window->resizable)
|
||||||
@ -393,9 +398,6 @@ static void updateNormalHints(_GLFWwindow* window, int width, int height)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
hints->flags |= PWinGravity;
|
|
||||||
hints->win_gravity = StaticGravity;
|
|
||||||
|
|
||||||
XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
|
XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
|
||||||
XFree(hints);
|
XFree(hints);
|
||||||
|
|
||||||
@ -561,6 +563,25 @@ static void updateCursorImage(_GLFWwindow* window)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grabs the cursor and confines it to the window
|
||||||
|
//
|
||||||
|
static void captureCursor(_GLFWwindow* window)
|
||||||
|
{
|
||||||
|
XGrabPointer(_glfw.x11.display, window->x11.handle, True,
|
||||||
|
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
|
||||||
|
GrabModeAsync, GrabModeAsync,
|
||||||
|
window->x11.handle,
|
||||||
|
None,
|
||||||
|
CurrentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ungrabs the cursor
|
||||||
|
//
|
||||||
|
static void releaseCursor(void)
|
||||||
|
{
|
||||||
|
XUngrabPointer(_glfw.x11.display, CurrentTime);
|
||||||
|
}
|
||||||
|
|
||||||
// Enable XI2 raw mouse motion events
|
// Enable XI2 raw mouse motion events
|
||||||
//
|
//
|
||||||
static void enableRawMouseMotion(_GLFWwindow* window)
|
static void enableRawMouseMotion(_GLFWwindow* window)
|
||||||
@ -603,12 +624,7 @@ static void disableCursor(_GLFWwindow* window)
|
|||||||
&_glfw.x11.restoreCursorPosY);
|
&_glfw.x11.restoreCursorPosY);
|
||||||
updateCursorImage(window);
|
updateCursorImage(window);
|
||||||
_glfwCenterCursorInContentArea(window);
|
_glfwCenterCursorInContentArea(window);
|
||||||
XGrabPointer(_glfw.x11.display, window->x11.handle, True,
|
captureCursor(window);
|
||||||
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
|
|
||||||
GrabModeAsync, GrabModeAsync,
|
|
||||||
window->x11.handle,
|
|
||||||
_glfw.x11.hiddenCursorHandle,
|
|
||||||
CurrentTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exit disabled cursor mode for the specified window
|
// Exit disabled cursor mode for the specified window
|
||||||
@ -619,7 +635,7 @@ static void enableCursor(_GLFWwindow* window)
|
|||||||
disableRawMouseMotion(window);
|
disableRawMouseMotion(window);
|
||||||
|
|
||||||
_glfw.x11.disabledCursorWindow = NULL;
|
_glfw.x11.disabledCursorWindow = NULL;
|
||||||
XUngrabPointer(_glfw.x11.display, CurrentTime);
|
releaseCursor();
|
||||||
_glfwPlatformSetCursorPos(window,
|
_glfwPlatformSetCursorPos(window,
|
||||||
_glfw.x11.restoreCursorPosX,
|
_glfw.x11.restoreCursorPosX,
|
||||||
_glfw.x11.restoreCursorPosY);
|
_glfw.x11.restoreCursorPosY);
|
||||||
@ -764,7 +780,28 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
|
|||||||
XFree(hints);
|
XFree(hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateNormalHints(window, width, height);
|
// Set ICCCM WM_NORMAL_HINTS property
|
||||||
|
{
|
||||||
|
XSizeHints* hints = XAllocSizeHints();
|
||||||
|
if (!hints)
|
||||||
|
{
|
||||||
|
_glfwInputError(GLFW_OUT_OF_MEMORY, "X11: Failed to allocate size hints");
|
||||||
|
return GLFW_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wndconfig->resizable)
|
||||||
|
{
|
||||||
|
hints->flags |= (PMinSize | PMaxSize);
|
||||||
|
hints->min_width = hints->max_width = width;
|
||||||
|
hints->min_height = hints->max_height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
hints->flags |= PWinGravity;
|
||||||
|
hints->win_gravity = StaticGravity;
|
||||||
|
|
||||||
|
XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
|
||||||
|
XFree(hints);
|
||||||
|
}
|
||||||
|
|
||||||
// Set ICCCM WM_CLASS property
|
// Set ICCCM WM_CLASS property
|
||||||
{
|
{
|
||||||
@ -1563,6 +1600,9 @@ static void processEvent(XEvent *event)
|
|||||||
if (event->xconfigure.width != window->x11.width ||
|
if (event->xconfigure.width != window->x11.width ||
|
||||||
event->xconfigure.height != window->x11.height)
|
event->xconfigure.height != window->x11.height)
|
||||||
{
|
{
|
||||||
|
window->x11.width = event->xconfigure.width;
|
||||||
|
window->x11.height = event->xconfigure.height;
|
||||||
|
|
||||||
_glfwInputFramebufferSize(window,
|
_glfwInputFramebufferSize(window,
|
||||||
event->xconfigure.width,
|
event->xconfigure.width,
|
||||||
event->xconfigure.height);
|
event->xconfigure.height);
|
||||||
@ -1570,9 +1610,6 @@ static void processEvent(XEvent *event)
|
|||||||
_glfwInputWindowSize(window,
|
_glfwInputWindowSize(window,
|
||||||
event->xconfigure.width,
|
event->xconfigure.width,
|
||||||
event->xconfigure.height);
|
event->xconfigure.height);
|
||||||
|
|
||||||
window->x11.width = event->xconfigure.width;
|
|
||||||
window->x11.height = event->xconfigure.height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int xpos = event->xconfigure.x;
|
int xpos = event->xconfigure.x;
|
||||||
@ -1600,9 +1637,10 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
if (xpos != window->x11.xpos || ypos != window->x11.ypos)
|
if (xpos != window->x11.xpos || ypos != window->x11.ypos)
|
||||||
{
|
{
|
||||||
_glfwInputWindowPos(window, xpos, ypos);
|
|
||||||
window->x11.xpos = xpos;
|
window->x11.xpos = xpos;
|
||||||
window->x11.ypos = ypos;
|
window->x11.ypos = ypos;
|
||||||
|
|
||||||
|
_glfwInputWindowPos(window, xpos, ypos);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -2085,7 +2123,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
|
|||||||
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
void _glfwPlatformDestroyWindow(_GLFWwindow* window)
|
||||||
{
|
{
|
||||||
if (_glfw.x11.disabledCursorWindow == window)
|
if (_glfw.x11.disabledCursorWindow == window)
|
||||||
_glfw.x11.disabledCursorWindow = NULL;
|
enableCursor(window);
|
||||||
|
|
||||||
if (window->monitor)
|
if (window->monitor)
|
||||||
releaseMonitor(window);
|
releaseMonitor(window);
|
||||||
@ -2891,16 +2929,40 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
|
|||||||
|
|
||||||
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
|
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
|
||||||
{
|
{
|
||||||
|
if (_glfwPlatformWindowFocused(window))
|
||||||
|
{
|
||||||
if (mode == GLFW_CURSOR_DISABLED)
|
if (mode == GLFW_CURSOR_DISABLED)
|
||||||
{
|
{
|
||||||
if (_glfwPlatformWindowFocused(window))
|
_glfwPlatformGetCursorPos(window,
|
||||||
disableCursor(window);
|
&_glfw.x11.restoreCursorPosX,
|
||||||
|
&_glfw.x11.restoreCursorPosY);
|
||||||
|
_glfwCenterCursorInContentArea(window);
|
||||||
|
if (window->rawMouseMotion)
|
||||||
|
enableRawMouseMotion(window);
|
||||||
}
|
}
|
||||||
else if (_glfw.x11.disabledCursorWindow == window)
|
else if (_glfw.x11.disabledCursorWindow == window)
|
||||||
enableCursor(window);
|
{
|
||||||
else
|
if (window->rawMouseMotion)
|
||||||
updateCursorImage(window);
|
disableRawMouseMotion(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == GLFW_CURSOR_DISABLED)
|
||||||
|
captureCursor(window);
|
||||||
|
else
|
||||||
|
releaseCursor();
|
||||||
|
|
||||||
|
if (mode == GLFW_CURSOR_DISABLED)
|
||||||
|
_glfw.x11.disabledCursorWindow = window;
|
||||||
|
else if (_glfw.x11.disabledCursorWindow == window)
|
||||||
|
{
|
||||||
|
_glfw.x11.disabledCursorWindow = NULL;
|
||||||
|
_glfwPlatformSetCursorPos(window,
|
||||||
|
_glfw.x11.restoreCursorPosX,
|
||||||
|
_glfw.x11.restoreCursorPosY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCursorImage(window);
|
||||||
XFlush(_glfw.x11.display);
|
XFlush(_glfw.x11.display);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2909,14 +2971,15 @@ const char* _glfwPlatformGetScancodeName(int scancode)
|
|||||||
if (!_glfw.x11.xkb.available)
|
if (!_glfw.x11.xkb.available)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (scancode < 0 || scancode > 0xff ||
|
if (scancode < 0 || scancode > 0xff)
|
||||||
_glfw.x11.keycodes[scancode] == GLFW_KEY_UNKNOWN)
|
|
||||||
{
|
{
|
||||||
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode);
|
_glfwInputError(GLFW_INVALID_VALUE, "Invalid scancode %i", scancode);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int key = _glfw.x11.keycodes[scancode];
|
const int key = _glfw.x11.keycodes[scancode];
|
||||||
|
if (key == GLFW_KEY_UNKNOWN)
|
||||||
|
return NULL;
|
||||||
const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display,
|
const KeySym keysym = XkbKeycodeToKeysym(_glfw.x11.display,
|
||||||
scancode, _glfw.x11.xkb.group, 0);
|
scancode, _glfw.x11.xkb.group, 0);
|
||||||
if (keysym == NoSymbol)
|
if (keysym == NoSymbol)
|
||||||
|
@ -68,6 +68,9 @@ func (c *defaultContext) init() error {
|
|||||||
// Try OpenGL first. OpenGL is preferable as this doesn't cause context losses.
|
// Try OpenGL first. OpenGL is preferable as this doesn't cause context losses.
|
||||||
if !preferES {
|
if !preferES {
|
||||||
// Usually libGL.so or libGL.so.1 is used. libGL.so.2 might exist only on NetBSD.
|
// Usually libGL.so or libGL.so.1 is used. libGL.so.2 might exist only on NetBSD.
|
||||||
|
// TODO: Should "libOpenGL.so.0" [1] and "libGLX.so.0" [2] be added? These were added as of GLFW 3.3.9.
|
||||||
|
// [1] https://github.com/glfw/glfw/commit/55aad3c37b67f17279378db52da0a3ab81bbf26d
|
||||||
|
// [2] https://github.com/glfw/glfw/commit/c18851f52ec9704eb06464058a600845ec1eada1
|
||||||
for _, name := range []string{"libGL.so", "libGL.so.2", "libGL.so.1", "libGL.so.0"} {
|
for _, name := range []string{"libGL.so", "libGL.so.2", "libGL.so.1", "libGL.so.0"} {
|
||||||
cname := C.CString(name)
|
cname := C.CString(name)
|
||||||
lib := C.dlopen(cname, C.RTLD_LAZY|C.RTLD_GLOBAL)
|
lib := C.dlopen(cname, C.RTLD_LAZY|C.RTLD_GLOBAL)
|
||||||
|
@ -71,6 +71,8 @@ type GoTextFaceSource struct {
|
|||||||
|
|
||||||
addr *GoTextFaceSource
|
addr *GoTextFaceSource
|
||||||
|
|
||||||
|
shaper shaping.HarfbuzzShaper
|
||||||
|
|
||||||
m sync.Mutex
|
m sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +205,7 @@ func (g *GoTextFaceSource) shape(text string, face *GoTextFace) ([]shaping.Outpu
|
|||||||
outputs := make([]shaping.Output, len(inputs))
|
outputs := make([]shaping.Output, len(inputs))
|
||||||
var gs []glyph
|
var gs []glyph
|
||||||
for i, input := range inputs {
|
for i, input := range inputs {
|
||||||
out := (&shaping.HarfbuzzShaper{}).Shape(input)
|
out := g.shaper.Shape(input)
|
||||||
outputs[i] = out
|
outputs[i] = out
|
||||||
|
|
||||||
(shaping.Line{out}).AdjustBaselines()
|
(shaping.Line{out}).AdjustBaselines()
|
||||||
|
Loading…
Reference in New Issue
Block a user