internal/glfw, internal/gamepad: update GLFW to v3.3.9

Updates #2960
This commit is contained in:
Hajime Hoshi 2024-04-13 22:23:50 +09:00
parent 88dae9c7d4
commit 4647e9de53
21 changed files with 393 additions and 225 deletions

View File

@ -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,
} }

View File

@ -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
} }

View File

@ -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

View File

@ -121,6 +121,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 +131,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

View File

@ -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;

View File

@ -285,10 +285,15 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
- (void)windowDidChangeOcclusionState:(NSNotification* )notification - (void)windowDidChangeOcclusionState:(NSNotification* )notification
{ {
if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible) #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
window->ns.occluded = GLFW_FALSE; if ([window->ns.object respondsToSelector:@selector(occlusionState)])
else {
window->ns.occluded = GLFW_TRUE; if ([window->ns.object occlusionState] & NSWindowOcclusionStateVisible)
window->ns.occluded = GLFW_FALSE;
else
window->ns.occluded = GLFW_TRUE;
}
#endif
} }
@end @end
@ -1239,7 +1244,7 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
if (window->monitor) if (window->monitor)
{ {
styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable); styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable);
styleMask |= NSWindowStyleMaskBorderless; styleMask |= NSWindowStyleMaskBorderless;
} }
else else

View File

@ -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");

View File

@ -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 {

View File

@ -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,23 +140,10 @@ 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;
{ continue;
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;
} }
u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE); u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
@ -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);

View File

@ -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 9
/*! @} */ /*! @} */
/*! @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
@ -4039,8 +4041,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 +4064,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 +4359,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 +4712,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 +4735,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.
* *

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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))
@ -300,7 +306,7 @@ GLFWAPI int glfwGetKeyScancode(int key)
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);

View File

@ -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
} }

View File

@ -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
} }

View File

@ -53,12 +53,13 @@ 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 {
attribs = append(attribs, attribs = append(attribs,
_WGL_SUPPORT_OPENGL_ARB, _WGL_SUPPORT_OPENGL_ARB,
_WGL_DRAW_TO_WINDOW_ARB, _WGL_DRAW_TO_WINDOW_ARB,
@ -96,12 +97,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)

View File

@ -72,6 +72,8 @@ type platformLibraryWindowState struct {
// The window whose disabled cursor mode is active // The window whose disabled cursor mode is active
disabledCursorWindow *Window disabledCursorWindow *Window
// The window the cursor is captured in
capturedCursorWindow *Window
rawInput []byte rawInput []byte
mouseTrailSize uint32 mouseTrailSize uint32
} }

View File

@ -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 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
}
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
@ -214,26 +195,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)
if err != nil {
return err
}
if err := _ClipCursor(&clipRect); err != nil {
return err
}
} else {
if err := _ClipCursor(nil); err != nil {
return err
}
} }
clipRect, err = window.clientToScreen(clipRect)
if err != nil {
return err
}
if err := _ClipCursor(&clipRect); err != nil {
return err
}
_glfw.platformWindow.capturedCursorWindow = window
return nil
}
func releaseCursor() error {
if err := _ClipCursor(nil); err != nil {
return err
}
_glfw.platformWindow.capturedCursorWindow = nil
return nil return nil
} }
@ -274,7 +256,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 +274,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 {
@ -986,8 +968,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 +1014,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 +1038,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 {
} _glfw.errors = append(_glfw.errors, err)
return 0
xoff, yoff, err := getFullWindowSize(window.getWindowStyle(), window.getWindowExStyle(), 0, 0, dpi) }
if err != nil { } else {
_glfw.errors = append(_glfw.errors, err) if err := _AdjustWindowRectEx(&frame, style, false, exStyle); err != nil {
return 0 _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 +1191,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 +1200,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 +1447,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 {
@ -2184,7 +2180,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 +2231,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 mode == CursorDisabled {
if err := w.disableCursor(); err != nil { 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
}
}
}
if mode == CursorDisabled {
if err := captureCursor(w); err != nil {
return err
}
} else {
if err := releaseCursor(); err != nil {
return err return err
} }
} }
return nil
}
if _glfw.platformWindow.disabledCursorWindow == w { if mode == CursorDisabled {
if err := w.enableCursor(); err != nil { _glfw.platformWindow.disabledCursorWindow = w
return err } else {
_glfw.platformWindow.disabledCursorWindow = nil
if err := w.platformSetCursorPos(_glfw.platformWindow.restoreCursorPosX, _glfw.platformWindow.restoreCursorPosY); err != nil {
return err
}
} }
return nil
} }
in, err := w.cursorInContentArea() in, err := w.cursorInContentArea()

View File

@ -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
{ {
@ -2085,7 +2122,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 +2928,40 @@ void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode) void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
{ {
if (mode == GLFW_CURSOR_DISABLED) if (_glfwPlatformWindowFocused(window))
{ {
if (_glfwPlatformWindowFocused(window)) if (mode == GLFW_CURSOR_DISABLED)
disableCursor(window); {
} _glfwPlatformGetCursorPos(window,
else if (_glfw.x11.disabledCursorWindow == window) &_glfw.x11.restoreCursorPosX,
enableCursor(window); &_glfw.x11.restoreCursorPosY);
else _glfwCenterCursorInContentArea(window);
updateCursorImage(window); if (window->rawMouseMotion)
enableRawMouseMotion(window);
}
else if (_glfw.x11.disabledCursorWindow == window)
{
if (window->rawMouseMotion)
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);
} }

View File

@ -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)