Merge branch 'glfw:master' into taskbar-progress

This commit is contained in:
Jan Schürkamp 2022-08-06 16:38:09 +02:00 committed by GitHub
commit fb4c22ed9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 530 additions and 187 deletions

View File

@ -166,6 +166,7 @@ video tutorials.
- Peoro - Peoro
- Braden Pellett - Braden Pellett
- Christopher Pelloux - Christopher Pelloux
- Michael Pennington
- Arturo J. Pérez - Arturo J. Pérez
- Vladimir Perminov - Vladimir Perminov
- Olivier Perret - Olivier Perret

View File

@ -139,9 +139,16 @@ information on what to include when reporting a bug.
- Added `GLFW_POINTING_HAND_CURSOR` alias for `GLFW_HAND_CURSOR` (#427) - Added `GLFW_POINTING_HAND_CURSOR` alias for `GLFW_HAND_CURSOR` (#427)
- Added `GLFW_MOUSE_PASSTHROUGH` window hint for letting mouse input pass - Added `GLFW_MOUSE_PASSTHROUGH` window hint for letting mouse input pass
through the window (#1236,#1568) through the window (#1236,#1568)
- Added `GLFW_CURSOR_CAPTURED` cursor mode to confine the cursor to the window
content area (#58)
- Added `GLFW_POSITION_X` and `GLFW_POSITION_Y` window hints for initial position
(#1603,#1747)
- Added `GLFW_ANY_POSITION` hint value for letting the window manager choose (#1603,#1747)
- Added `GLFW_PLATFORM_UNAVAILABLE` error for platform detection failures (#1958) - Added `GLFW_PLATFORM_UNAVAILABLE` error for platform detection failures (#1958)
- Added `GLFW_FEATURE_UNAVAILABLE` error for platform limitations (#1692) - Added `GLFW_FEATURE_UNAVAILABLE` error for platform limitations (#1692)
- Added `GLFW_FEATURE_UNIMPLEMENTED` error for incomplete backends (#1692) - Added `GLFW_FEATURE_UNIMPLEMENTED` error for incomplete backends (#1692)
- Added `GLFW_WAYLAND_APP_ID` window hint string for Wayland app\_id selection
(#2121,#2122)
- Added `GLFW_ANGLE_PLATFORM_TYPE` init hint and `GLFW_ANGLE_PLATFORM_TYPE_*` - Added `GLFW_ANGLE_PLATFORM_TYPE` init hint and `GLFW_ANGLE_PLATFORM_TYPE_*`
values to select ANGLE backend (#1380) values to select ANGLE backend (#1380)
- Added `GLFW_X11_XCB_VULKAN_SURFACE` init hint for selecting X11 Vulkan - Added `GLFW_X11_XCB_VULKAN_SURFACE` init hint for selecting X11 Vulkan
@ -387,7 +394,9 @@ information on what to include when reporting a bug.
(#442) (#442)
- [EGL] Added ANGLE backend selection via `EGL_ANGLE_platform_angle` extension - [EGL] Added ANGLE backend selection via `EGL_ANGLE_platform_angle` extension
(#1380) (#1380)
[EGL] Added loading of glvnd `libOpenGL.so.0` where available for OpenGL
- [EGL] Bugfix: The `GLFW_DOUBLEBUFFER` context attribute was ignored (#1843) - [EGL] Bugfix: The `GLFW_DOUBLEBUFFER` context attribute was ignored (#1843)
- [GLX] Added loading of glvnd `libGLX.so.0` where available
- [GLX] Bugfix: Context creation failed if GLX 1.4 was not exported by GLX library - [GLX] Bugfix: Context creation failed if GLX 1.4 was not exported by GLX library

View File

@ -26,7 +26,7 @@ GLFW.
@endcode @endcode
This header defines all the constants and declares all the types and function This header defines all the constants and declares all the types and function
prototypes of the GLFW API. By default it also includes the OpenGL header from prototypes of the GLFW API. By default, it also includes the OpenGL header from
your development environment. See [option macros](@ref build_macros) below for your development environment. See [option macros](@ref build_macros) below for
how to select OpenGL ES headers and more. how to select OpenGL ES headers and more.

View File

@ -152,7 +152,7 @@ formats. If GLX 1.3 is not supported, @ref glfwInit will fail.
GLFW uses the `GLX_MESA_swap_control,` `GLX_EXT_swap_control` and GLFW uses the `GLX_MESA_swap_control,` `GLX_EXT_swap_control` and
`GLX_SGI_swap_control` extensions to provide vertical retrace synchronization `GLX_SGI_swap_control` extensions to provide vertical retrace synchronization
(or _vsync_), in that order of preference. Where none of these extension are (or _vsync_), in that order of preference. When none of these extensions are
available, calling @ref glfwSwapInterval will have no effect. available, calling @ref glfwSwapInterval will have no effect.
GLFW uses the `GLX_ARB_multisample` extension to create contexts with GLFW uses the `GLX_ARB_multisample` extension to create contexts with
@ -219,8 +219,8 @@ extension is unavailable, the `GLFW_CONTEXT_RELEASE_BEHAVIOR` hint will have no
effect and the context will always be flushed when released. effect and the context will always be flushed when released.
GLFW uses the `WGL_ARB_framebuffer_sRGB` and `WGL_EXT_framebuffer_sRGB` GLFW uses the `WGL_ARB_framebuffer_sRGB` and `WGL_EXT_framebuffer_sRGB`
extensions to provide support for sRGB framebuffers. Where both of these extensions to provide support for sRGB framebuffers. When both of these
extension are unavailable, the `GLFW_SRGB_CAPABLE` hint will have no effect. extensions are unavailable, the `GLFW_SRGB_CAPABLE` hint will have no effect.
@section compat_osx OpenGL on macOS @section compat_osx OpenGL on macOS

View File

@ -45,7 +45,7 @@ Linux and FreeBSD you will need a few extra packages.
To compile GLFW for X11, you need to have the X11 development packages To compile GLFW for X11, you need to have the X11 development packages
installed. They are not needed to build or run programs that use GLFW. installed. They are not needed to build or run programs that use GLFW.
On Debian and derivates like Ubuntu and Linux Mint the `xorg-dev` meta-package On Debian and derivatives like Ubuntu and Linux Mint the `xorg-dev` meta-package
pulls in the development packages for all of X11. pulls in the development packages for all of X11.
@code{.sh} @code{.sh}
@ -83,7 +83,7 @@ development packages installed. They are not needed to build or run programs th
GLFW. You will also need to set the @ref GLFW_BUILD_WAYLAND CMake option in the next GLFW. You will also need to set the @ref GLFW_BUILD_WAYLAND CMake option in the next
step when generating build files. step when generating build files.
On Debian and derivates like Ubuntu and Linux Mint you will need the `libwayland-dev`, On Debian and derivatives like Ubuntu and Linux Mint you will need the `libwayland-dev`,
`libxkbcommon-dev` and `wayland-protocols` packages and the `xorg-dev` meta-package. `libxkbcommon-dev` and `wayland-protocols` packages and the `xorg-dev` meta-package.
These will pull in all other dependencies. These will pull in all other dependencies.
@ -142,7 +142,7 @@ If you wish change any CMake variables in the list, press _Configure_ and then
_Generate_ to have the new values take effect. The variable list will be _Generate_ to have the new values take effect. The variable list will be
populated after the first configure step. populated after the first configure step.
By default GLFW will use X11 on Linux and other Unix-like systems other than macOS. To By default, GLFW will use X11 on Linux and other Unix-like systems other than macOS. To
include support for Wayland as well, set the @ref GLFW_BUILD_WAYLAND option in the GLFW include support for Wayland as well, set the @ref GLFW_BUILD_WAYLAND option in the GLFW
section of the variable list, then apply the new value as described above. section of the variable list, then apply the new value as described above.
@ -176,7 +176,7 @@ flag.
cmake -S path/to/glfw -B path/to/build -G Xcode cmake -S path/to/glfw -B path/to/build -G Xcode
@endcode @endcode
By default GLFW will use X11 on Linux and other Unix-like systems other By default, GLFW will use X11 on Linux and other Unix-like systems other
than macOS. To also include support for Wayland, set the @ref GLFW_BUILD_WAYLAND CMake than macOS. To also include support for Wayland, set the @ref GLFW_BUILD_WAYLAND CMake
option. option.
@ -263,12 +263,12 @@ build GLFW as a static library, `SHARED` to build it as a shared library
@anchor GLFW_BUILD_EXAMPLES @anchor GLFW_BUILD_EXAMPLES
__GLFW_BUILD_EXAMPLES__ determines whether the GLFW examples are built __GLFW_BUILD_EXAMPLES__ determines whether the GLFW examples are built
along with the library. This is enabled by default unless GLFW is being built along with the library. This is enabled by default unless GLFW is being built
as a sub-project of a larger CMake project. as a subproject of a larger CMake project.
@anchor GLFW_BUILD_TESTS @anchor GLFW_BUILD_TESTS
__GLFW_BUILD_TESTS__ determines whether the GLFW test programs are __GLFW_BUILD_TESTS__ determines whether the GLFW test programs are
built along with the library. This is enabled by default unless GLFW is being built along with the library. This is enabled by default unless GLFW is being
built as a sub-project of a larger CMake project. built as a subproject of a larger CMake project.
@anchor GLFW_BUILD_DOCS @anchor GLFW_BUILD_DOCS
__GLFW_BUILD_DOCS__ determines whether the GLFW documentation is built along __GLFW_BUILD_DOCS__ determines whether the GLFW documentation is built along
@ -358,7 +358,7 @@ For more details see the
@section compile_manual Compiling GLFW manually @section compile_manual Compiling GLFW manually
If you wish to compile GLFW without its CMake build environment then you will have to do If you wish to compile GLFW without its CMake build environment then you will have to do
at least some of the platform detection yourself. There are preprocessor macros for at least some platform-detection yourself. There are preprocessor macros for
enabling support for the platforms (window systems) available. There are also optional, enabling support for the platforms (window systems) available. There are also optional,
platform-specific macros for various features. platform-specific macros for various features.

View File

@ -61,7 +61,7 @@ information. The name and number of this chapter unfortunately varies between
versions and APIs, but has at times been named _Shared Objects and Multiple versions and APIs, but has at times been named _Shared Objects and Multiple
Contexts_. Contexts_.
GLFW comes with a barebones object sharing example program called `sharing`. GLFW comes with a bare-bones object sharing example program called `sharing`.
@subsection context_offscreen Offscreen contexts @subsection context_offscreen Offscreen contexts
@ -189,7 +189,7 @@ it suppresses the development environment's OpenGL or OpenGL ES header.
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
@endcode @endcode
Finally you need to initialize glad once you have a suitable current context. Finally, you need to initialize glad once you have a suitable current context.
@code @code
window = glfwCreateWindow(640, 480, "My Window", NULL, NULL); window = glfwCreateWindow(640, 480, "My Window", NULL, NULL);
@ -205,7 +205,7 @@ gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
Once glad has been loaded, you have access to all OpenGL core and extension Once glad has been loaded, you have access to all OpenGL core and extension
functions supported by both the context you created and the glad loader you functions supported by both the context you created and the glad loader you
generated and you are ready to start rendering. generated. After that, you are ready to start rendering.
You can specify a minimum required OpenGL or OpenGL ES version with You can specify a minimum required OpenGL or OpenGL ES version with
[context hints](@ref window_hints_ctx). If your needs are more complex, you can [context hints](@ref window_hints_ctx). If your needs are more complex, you can

View File

@ -24,7 +24,7 @@ All input callbacks receive a window handle. By using the
or objects from your callbacks. or objects from your callbacks.
To get a better feel for how the various events callbacks behave, run the To get a better feel for how the various events callbacks behave, run the
`events` test program. It register every callback supported by GLFW and prints `events` test program. It registers every callback supported by GLFW and prints
out all arguments provided for every event, along with time and sequence out all arguments provided for every event, along with time and sequence
information. information.
@ -312,6 +312,16 @@ glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
This mode puts no limit on the motion of the cursor. This mode puts no limit on the motion of the cursor.
If you wish the cursor to be visible but confined to the content area of the
window, set the cursor mode to `GLFW_CURSOR_CAPTURED`.
@code
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_CAPTURED);
@endcode
The cursor will behave normally inside the content area but will not be able to
leave unless the window loses focus.
To exit out of either of these special modes, restore the `GLFW_CURSOR_NORMAL` To exit out of either of these special modes, restore the `GLFW_CURSOR_NORMAL`
cursor mode. cursor mode.
@ -319,6 +329,8 @@ cursor mode.
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
@endcode @endcode
If the cursor was disabled, this will move it back to its last visible position.
@anchor GLFW_RAW_MOUSE_MOTION @anchor GLFW_RAW_MOUSE_MOTION
@subsection raw_mouse_motion Raw mouse motion @subsection raw_mouse_motion Raw mouse motion
@ -382,7 +394,7 @@ sequential rows, starting from the top-left corner.
@subsubsection cursor_standard Standard cursor creation @subsubsection cursor_standard Standard cursor creation
A cursor with a [standard shape](@ref shapes) from the current system cursor A cursor with a [standard shape](@ref shapes) from the current system cursor
theme can be can be created with @ref glfwCreateStandardCursor. theme can be created with @ref glfwCreateStandardCursor.
@code @code
GLFWcursor* url_cursor = glfwCreateStandardCursor(GLFW_POINTING_HAND_CURSOR); GLFWcursor* url_cursor = glfwCreateStandardCursor(GLFW_POINTING_HAND_CURSOR);

View File

@ -162,7 +162,7 @@ GLFW can be compiled for more than one platform (window system) at once. This l
a single library binary support both X11 and Wayland on Linux and other Unix-like systems. a single library binary support both X11 and Wayland on Linux and other Unix-like systems.
You can control platform selection via the @ref GLFW_PLATFORM initialization hint. By You can control platform selection via the @ref GLFW_PLATFORM initialization hint. By
default this is set to @ref GLFW_ANY_PLATFORM, which will look for supported window default, this is set to @ref GLFW_ANY_PLATFORM, which will look for supported window
systems in order of priority and select the first one it finds. It can also be set to any systems in order of priority and select the first one it finds. It can also be set to any
specific platform to have GLFW only look for that one. specific platform to have GLFW only look for that one.
@ -269,9 +269,9 @@ This will destroy any remaining window, monitor and cursor objects, restore any
modified gamma ramps, re-enable the screensaver if it had been disabled and free modified gamma ramps, re-enable the screensaver if it had been disabled and free
any other resources allocated by GLFW. any other resources allocated by GLFW.
Once the library is terminated, it is as if it had never been initialized and Once the library is terminated, it is as if it had never been initialized, therefore
you will need to initialize it again before being able to use GLFW. If the you will need to initialize it again before being able to use GLFW. If the
library was not initialized or had already been terminated, it return library was not initialized or had already been terminated, it returns
immediately. immediately.
@ -391,14 +391,14 @@ which monitor the window is currently considered to be on.
This section describes the conditions under which GLFW can be expected to This section describes the conditions under which GLFW can be expected to
function, barring bugs in the operating system or drivers. Use of GLFW outside function, barring bugs in the operating system or drivers. Use of GLFW outside
of these limits may work on some platforms, or on some machines, or some of the these limits may work on some platforms, or on some machines, or some of the
time, or on some versions of GLFW, but it may break at any time and this will time, or on some versions of GLFW, but it may break at any time and this will
not be considered a bug. not be considered a bug.
@subsection lifetime Pointer lifetimes @subsection lifetime Pointer lifetimes
GLFW will never free any pointer you provide to it and you must never free any GLFW will never free any pointer you provide to it, and you must never free any
pointer it provides to you. pointer it provides to you.
Many GLFW functions return pointers to dynamically allocated structures, strings Many GLFW functions return pointers to dynamically allocated structures, strings
@ -602,15 +602,15 @@ The format of the string is as follows:
- The names of the always supported context creation APIs EGL and OSMesa - The names of the always supported context creation APIs EGL and OSMesa
- Any additional compile-time options, APIs and (on Windows) what compiler was used - Any additional compile-time options, APIs and (on Windows) what compiler was used
For example, GLFW 3.4 compiled as a DLL for Windows with MinGW may have a version string For example, compiling GLFW 3.4 with MinGW as a DLL for Windows, may result in a version string
like this: like this:
@code @code
3.4.0 Win32 WGL Null EGL OSMesa MinGW DLL 3.4.0 Win32 WGL Null EGL OSMesa MinGW DLL
@endcode @endcode
While GLFW compiled as as static library for Linux with both Wayland and X11 enabled may Compiling GLFW as a static library for Linux, with both Wayland and X11 enabled, may
have a version string like this: result in a version string like this:
@code @code
3.4.0 Wayland X11 GLX Null EGL OSMesa monotonic 3.4.0 Wayland X11 GLX Null EGL OSMesa monotonic

View File

@ -138,7 +138,7 @@ glfwGetMonitorPhysicalSize(monitor, &width_mm, &height_mm);
@endcode @endcode
While this can be used to calculate the raw DPI of a monitor, this is often not While this can be used to calculate the raw DPI of a monitor, this is often not
useful. Instead use the [monitor content scale](@ref monitor_scale) and useful. Instead, use the [monitor content scale](@ref monitor_scale) and
[window content scale](@ref window_scale) to scale your content. [window content scale](@ref window_scale) to scale your content.
@ -261,7 +261,7 @@ To experiment with gamma correction via the @ref glfwSetGamma function, run the
`gamma` test program. `gamma` test program.
@note The software controlled gamma ramp is applied _in addition_ to the @note The software controlled gamma ramp is applied _in addition_ to the
hardware gamma correction, which today is usually an approximation of sRGB hardware gamma correction, which today is typically an approximation of sRGB
gamma. This means that setting a perfectly linear ramp, or gamma 1.0, will gamma. This means that setting a perfectly linear ramp, or gamma 1.0, will
produce the default (usually sRGB-like) behavior. produce the default (usually sRGB-like) behavior.

View File

@ -243,7 +243,7 @@ while (!glfwWindowShouldClose(window))
@endcode @endcode
The close callback no longer returns a value. Instead, it is called after the The close callback no longer returns a value. Instead, it is called after the
close flag has been set so it can override its value, if it chooses to, before close flag has been set, so it can optionally override its value, before
event processing completes. You may however not call @ref glfwDestroyWindow event processing completes. You may however not call @ref glfwDestroyWindow
from the close callback (or any other window related callback). from the close callback (or any other window related callback).
@ -350,11 +350,11 @@ from a repeat. Note that @ref glfwGetKey still returns only `GLFW_PRESS` or
GLFW 3 key tokens map to physical keys, unlike in GLFW 2 where they mapped to GLFW 3 key tokens map to physical keys, unlike in GLFW 2 where they mapped to
the values generated by the current keyboard layout. The tokens are named the values generated by the current keyboard layout. The tokens are named
according to the values they would have using the standard US layout, but this according to the values they would have in the standard US layout, but this
is only a convenience, as most programmers are assumed to know that layout. is only a convenience, as most programmers are assumed to know that layout.
This means that (for example) `GLFW_KEY_LEFT_BRACKET` is always a single key and This means that (for example) `GLFW_KEY_LEFT_BRACKET` is always a single key and
is the same key in the same place regardless of what keyboard layouts the users is the same key in the same place regardless of what keyboard layouts the users
of your program has. of your program have.
The key input facility was never meant for text input, although using it that The key input facility was never meant for text input, although using it that
way worked slightly better in GLFW 2. If you were using it to input text, you way worked slightly better in GLFW 2. If you were using it to input text, you

View File

@ -21,7 +21,7 @@ support for a given platform is compiled in with @ref glfwPlatformSupported.
GLFW now provides the standard cursor shapes @ref GLFW_RESIZE_NWSE_CURSOR and GLFW now provides the standard cursor shapes @ref GLFW_RESIZE_NWSE_CURSOR and
@ref GLFW_RESIZE_NESW_CURSOR for diagonal resizing, @ref GLFW_RESIZE_ALL_CURSOR @ref GLFW_RESIZE_NESW_CURSOR for diagonal resizing, @ref GLFW_RESIZE_ALL_CURSOR
for omni-directional resizing and @ref GLFW_NOT_ALLOWED_CURSOR for showing an for omnidirectional resizing and @ref GLFW_NOT_ALLOWED_CURSOR for showing an
action is not allowed. action is not allowed.
Unlike the original set, these shapes may not be available everywhere and Unlike the original set, these shapes may not be available everywhere and
@ -43,6 +43,12 @@ to whatever window is behind it. This can also be changed after window
creation with the matching [window attribute](@ref GLFW_MOUSE_PASSTHROUGH_attrib). creation with the matching [window attribute](@ref GLFW_MOUSE_PASSTHROUGH_attrib).
@subsubsection wayland_app_id_34 Wayland app_id specification
GLFW now supports specifying the app_id for a Wayland window using the
[GLFW_WAYLAND_APP_ID](@ref GLFW_WAYLAND_APP_ID_hint) window hint string.
@subsubsection features_34_angle_backend Support for ANGLE rendering backend selection @subsubsection features_34_angle_backend Support for ANGLE rendering backend selection
GLFW now provides the GLFW now provides the
@ -52,6 +58,14 @@ requesting a specific rendering backend when using
contexts. contexts.
@subsubsection captured_cursor_34 Captured cursor mode
GLFW now supports confining the cursor to the window content area with the @ref
GLFW_CURSOR_CAPTURED cursor mode.
For more information see @ref cursor_mode.
@subsubsection features_34_init_allocator Support for custom memory allocator @subsubsection features_34_init_allocator Support for custom memory allocator
GLFW now supports plugging a custom memory allocator at initialization with @ref GLFW now supports plugging a custom memory allocator at initialization with @ref
@ -62,6 +76,14 @@ function pointers corresponding to the standard library functions `malloc`,
For more information see @ref init_allocator. For more information see @ref init_allocator.
@subsubsection features_34_position_hint Window hints for initial position
GLFW now provides the @ref GLFW_POSITION_X and @ref GLFW_POSITION_Y window hints for
specifying the initial position of the window. This removes the need to create a hidden
window, move it and then show it. The default value of these hints is
`GLFW_ANY_POSITION`, which selects the previous behavior.
@subsubsection features_34_win32_keymenu Support for keyboard access to Windows window menu @subsubsection features_34_win32_keymenu Support for keyboard access to Windows window menu
GLFW now provides the GLFW now provides the
@ -78,7 +100,7 @@ applications.
Because GLFW now supports runtime selection of platform (window system), a library binary Because GLFW now supports runtime selection of platform (window system), a library binary
may export native access functions for multiple platforms. Starting with version 3.4 you may export native access functions for multiple platforms. Starting with version 3.4 you
must not assume that GLFW is running on a platform just because it exports native access must not assume that GLFW is running on a platform just because it exports native access
functions for it. After initialization you can query the selected platform with @ref functions for it. After initialization, you can query the selected platform with @ref
glfwGetPlatform. glfwGetPlatform.
@ -104,7 +126,7 @@ To work around this, call any joystick function before waiting for events, for
example by setting a [joystick callback](@ref joystick_event). example by setting a [joystick callback](@ref joystick_event).
@subsubsection standalone_34 Tests and examples are disabled when built as a sub-project @subsubsection standalone_34 Tests and examples are disabled when built as a subproject
GLFW now does not build the tests and examples when it is added as GLFW now does not build the tests and examples when it is added as
a subdirectory of another CMake project. To enable these, set the @ref a subdirectory of another CMake project. To enable these, set the @ref
@ -138,7 +160,7 @@ GLFW_TRANSPARENT_FRAMEBUFFER on Windows 7 if DWM transparency is off
(the Transparency setting under Personalization > Window Color). (the Transparency setting under Personalization > Window Color).
@subsubsection emptyevents_34 Empty events on X11 no longer roundtrip to server @subsubsection emptyevents_34 Empty events on X11 no longer round-trip to server
Events posted with @ref glfwPostEmptyEvent now use a separate unnamed pipe Events posted with @ref glfwPostEmptyEvent now use a separate unnamed pipe
instead of sending an X11 client event to the helper window. instead of sending an X11 client event to the helper window.
@ -228,6 +250,10 @@ then GLFW will fail to initialize.
- @ref GLFW_ANGLE_PLATFORM_TYPE_VULKAN - @ref GLFW_ANGLE_PLATFORM_TYPE_VULKAN
- @ref GLFW_ANGLE_PLATFORM_TYPE_METAL - @ref GLFW_ANGLE_PLATFORM_TYPE_METAL
- @ref GLFW_X11_XCB_VULKAN_SURFACE - @ref GLFW_X11_XCB_VULKAN_SURFACE
- @ref GLFW_CURSOR_CAPTURED
- @ref GLFW_POSITION_X
- @ref GLFW_POSITION_Y
- @ref GLFW_ANY_POSITION
@section news_archive Release notes for earlier versions @section news_archive Release notes for earlier versions

View File

@ -149,10 +149,6 @@ if (!window)
} }
@endcode @endcode
The window handle is passed to all window related functions and is provided to
along to all window related callbacks, so they can tell which window received
the event.
When a window and context is no longer needed, destroy it. When a window and context is no longer needed, destroy it.
@code @code
@ -238,7 +234,7 @@ events as described below.
@subsection quick_render Rendering with OpenGL @subsection quick_render Rendering with OpenGL
Once you have a current OpenGL context, you can use OpenGL normally. In this Once you have a current OpenGL context, you can use OpenGL normally. In this
tutorial, a multi-colored rotating triangle will be rendered. The framebuffer tutorial, a multicolored rotating triangle will be rendered. The framebuffer
size needs to be retrieved for `glViewport`. size needs to be retrieved for `glViewport`.
@code @code

View File

@ -142,7 +142,7 @@ PFN_vkGetDeviceProcAddr pfnGetDeviceProcAddr = (PFN_vkGetDeviceProcAddr)
glfwGetInstanceProcAddress(instance, "vkGetDeviceProcAddr"); glfwGetInstanceProcAddress(instance, "vkGetDeviceProcAddr");
@endcode @endcode
Device-specific functions may execute a little bit faster, due to not having to Device-specific functions may execute a little faster, due to not having to
dispatch internally based on the device passed to them. For more information dispatch internally based on the device passed to them. For more information
about `vkGetDeviceProcAddr`, see the Vulkan documentation. about `vkGetDeviceProcAddr`, see the Vulkan documentation.

View File

@ -256,6 +256,14 @@ This is only supported for undecorated windows. Decorated windows with this
enabled will behave differently between platforms. Possible values are enabled will behave differently between platforms. Possible values are
`GLFW_TRUE` and `GLFW_FALSE`. `GLFW_TRUE` and `GLFW_FALSE`.
@anchor GLFW_POSITION_X
@anchor GLFW_POSITION_Y
__GLFW_POSITION_X__ and __GLFW_POSITION_Y__ specify the desired initial position
of the window. The window manager may modify or ignore these coordinates. If
either or both of these hints are set to `GLFW_ANY_POSITION` then the window
manager will position the window where it thinks the user will prefer it.
Possible values are any valid screen coordinates and `GLFW_ANY_POSITION`.
@subsubsection window_hints_fb Framebuffer related hints @subsubsection window_hints_fb Framebuffer related hints
@ -492,6 +500,13 @@ __GLFW_X11_CLASS_NAME__ and __GLFW_X11_INSTANCE_NAME__ specifies the desired
ASCII encoded class and instance parts of the ICCCM `WM_CLASS` window property. ASCII encoded class and instance parts of the ICCCM `WM_CLASS` window property.
These are set with @ref glfwWindowHintString. These are set with @ref glfwWindowHintString.
@subsubsection window_hints_wayland Wayland specific window hints
@anchor GLFW_WAYLAND_APP_ID_hint
__GLFW_WAYLAND_APP_ID__ specifies the Wayland app_id for a window, used
by window managers to identify types of windows. This is set with
@ref glfwWindowHintString.
@subsubsection window_hints_values Supported and default values @subsubsection window_hints_values Supported and default values
@ -509,6 +524,8 @@ GLFW_TRANSPARENT_FRAMEBUFFER | `GLFW_FALSE` | `GLFW_TRUE` or `GL
GLFW_FOCUS_ON_SHOW | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_FOCUS_ON_SHOW | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE`
GLFW_SCALE_TO_MONITOR | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_SCALE_TO_MONITOR | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
GLFW_MOUSE_PASSTHROUGH | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_MOUSE_PASSTHROUGH | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
GLFW_POSITION_X | `GLFW_ANY_POSITION` | Any valid screen x-coordinate or `GLFW_ANY_POSITION`
GLFW_POSITION_Y | `GLFW_ANY_POSITION` | Any valid screen y-coordinate or `GLFW_ANY_POSITION`
GLFW_RED_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` GLFW_RED_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE`
GLFW_GREEN_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` GLFW_GREEN_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE`
GLFW_BLUE_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` GLFW_BLUE_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE`
@ -540,6 +557,7 @@ GLFW_COCOA_FRAME_NAME | `""` | A UTF-8 encoded fr
GLFW_COCOA_GRAPHICS_SWITCHING | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_COCOA_GRAPHICS_SWITCHING | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE`
GLFW_X11_CLASS_NAME | `""` | An ASCII encoded `WM_CLASS` class name GLFW_X11_CLASS_NAME | `""` | An ASCII encoded `WM_CLASS` class name
GLFW_X11_INSTANCE_NAME | `""` | An ASCII encoded `WM_CLASS` instance name GLFW_X11_INSTANCE_NAME | `""` | An ASCII encoded `WM_CLASS` instance name
GLFW_WAYLAND_APP_ID | `""` | An ASCII encoded Wayland `app_id` name
@section window_events Window event processing @section window_events Window event processing
@ -790,7 +808,20 @@ are undefined if they conflict.
@subsection window_pos Window position @subsection window_pos Window position
The position of a windowed-mode window can be changed with @ref By default, the window manager chooses the position of new windowed mode
windows, based on its size and which monitor the user appears to be working on.
This is most often the right choice. If you need to create a window at
a specific position, you can set the desired position with the @ref
GLFW_POSITION_X and @ref GLFW_POSITION_Y window hints.
@code
glfwWindowHint(GLFW_POSITION_X, 70);
glfwWindowHint(GLFW_POSITION_Y, 83);
@endcode
To restore the previous behavior, set these hints to `GLFW_ANY_POSITION`.
The position of a windowed mode window can be changed with @ref
glfwSetWindowPos. This moves the window so that the upper-left corner of its glfwSetWindowPos. This moves the window so that the upper-left corner of its
content area has the specified [screen coordinates](@ref coordinate_systems). content area has the specified [screen coordinates](@ref coordinate_systems).
The window system may put limitations on window placement. The window system may put limitations on window placement.

View File

@ -44,7 +44,6 @@ int main(int argc, char** argv)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
glfwGetMonitorWorkarea(glfwGetPrimaryMonitor(), &xpos, &ypos, NULL, &height); glfwGetMonitorWorkarea(glfwGetPrimaryMonitor(), &xpos, &ypos, NULL, &height);
@ -66,6 +65,9 @@ int main(int argc, char** argv)
if (i > 0) if (i > 0)
glfwWindowHint(GLFW_FOCUS_ON_SHOW, GLFW_FALSE); glfwWindowHint(GLFW_FOCUS_ON_SHOW, GLFW_FALSE);
glfwWindowHint(GLFW_POSITION_X, xpos + size * (1 + (i & 1)));
glfwWindowHint(GLFW_POSITION_Y, ypos + size * (1 + (i >> 1)));
windows[i] = glfwCreateWindow(size, size, "Multi-Window Example", NULL, NULL); windows[i] = glfwCreateWindow(size, size, "Multi-Window Example", NULL, NULL);
if (!windows[i]) if (!windows[i])
{ {
@ -75,9 +77,6 @@ int main(int argc, char** argv)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
glfwSetWindowPos(windows[i],
xpos + size * (1 + (i & 1)),
ypos + size * (1 + (i >> 1)));
glfwSetInputMode(windows[i], GLFW_STICKY_KEYS, GLFW_TRUE); glfwSetInputMode(windows[i], GLFW_STICKY_KEYS, GLFW_TRUE);
glfwMakeContextCurrent(windows[i]); glfwMakeContextCurrent(windows[i]);
@ -85,9 +84,6 @@ int main(int argc, char** argv)
glClearColor(colors[i].r, colors[i].g, colors[i].b, 1.f); glClearColor(colors[i].r, colors[i].g, colors[i].b, 1.f);
} }
for (int i = 0; i < 4; i++)
glfwShowWindow(windows[i]);
for (;;) for (;;)
{ {
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)

View File

@ -927,6 +927,18 @@ extern "C" {
*/ */
#define GLFW_MOUSE_PASSTHROUGH 0x0002000D #define GLFW_MOUSE_PASSTHROUGH 0x0002000D
/*! @brief Initial position x-coordinate window hint.
*
* Initial position x-coordinate [window hint](@ref GLFW_POSITION_X).
*/
#define GLFW_POSITION_X 0x0002000E
/*! @brief Initial position y-coordinate window hint.
*
* Initial position y-coordinate [window hint](@ref GLFW_POSITION_Y).
*/
#define GLFW_POSITION_Y 0x0002000F
/*! @brief Framebuffer bit depth hint. /*! @brief Framebuffer bit depth hint.
* *
* Framebuffer bit depth [hint](@ref GLFW_RED_BITS). * Framebuffer bit depth [hint](@ref GLFW_RED_BITS).
@ -1105,6 +1117,12 @@ extern "C" {
*/ */
#define GLFW_X11_INSTANCE_NAME 0x00024002 #define GLFW_X11_INSTANCE_NAME 0x00024002
#define GLFW_WIN32_KEYBOARD_MENU 0x00025001 #define GLFW_WIN32_KEYBOARD_MENU 0x00025001
/*! @brief Wayland specific
* [window hint](@ref GLFW_WAYLAND_APP_ID_hint).
*
* Allows specification of the Wayland app_id.
*/
#define GLFW_WAYLAND_APP_ID 0x00026001
/*! @} */ /*! @} */
#define GLFW_NO_API 0 #define GLFW_NO_API 0
@ -1128,6 +1146,7 @@ extern "C" {
#define GLFW_CURSOR_NORMAL 0x00034001 #define GLFW_CURSOR_NORMAL 0x00034001
#define GLFW_CURSOR_HIDDEN 0x00034002 #define GLFW_CURSOR_HIDDEN 0x00034002
#define GLFW_CURSOR_DISABLED 0x00034003 #define GLFW_CURSOR_DISABLED 0x00034003
#define GLFW_CURSOR_CAPTURED 0x00034004
#define GLFW_ANY_RELEASE_BEHAVIOR 0 #define GLFW_ANY_RELEASE_BEHAVIOR 0
#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 #define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001
@ -1145,6 +1164,8 @@ extern "C" {
#define GLFW_ANGLE_PLATFORM_TYPE_VULKAN 0x00037007 #define GLFW_ANGLE_PLATFORM_TYPE_VULKAN 0x00037007
#define GLFW_ANGLE_PLATFORM_TYPE_METAL 0x00037008 #define GLFW_ANGLE_PLATFORM_TYPE_METAL 0x00037008
#define GLFW_ANY_POSITION 0x80000000
/*! @defgroup shapes Standard cursor shapes /*! @defgroup shapes Standard cursor shapes
* @brief Standard system cursor shapes. * @brief Standard system cursor shapes.
* *
@ -3035,10 +3056,10 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value);
* OpenGL or OpenGL ES context. * OpenGL or OpenGL ES context.
* *
* By default, newly created windows use the placement recommended by the * By default, newly created windows use the placement recommended by the
* window system. To create the window at a specific position, make it * window system. To create the window at a specific position, set the @ref
* initially invisible using the [GLFW_VISIBLE](@ref GLFW_VISIBLE_hint) window * GLFW_POSITION_X and @ref GLFW_POSITION_Y window hints before creation. To
* hint, set its [position](@ref window_pos) and then [show](@ref window_hide) * restore the default behavior, set either or both hints back to
* it. * `GLFW_ANY_POSITION`.
* *
* As long as at least one full screen window is not iconified, the screensaver * As long as at least one full screen window is not iconified, the screensaver
* is prohibited from starting. * is prohibited from starting.
@ -4568,6 +4589,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
* - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual
* and unlimited cursor movement. This is useful for implementing for * and unlimited cursor movement. This is useful for implementing for
* example 3D camera controls. * example 3D camera controls.
* - `GLFW_CURSOR_CAPTURED` makes the cursor visible and confines it to the
* content area of the window.
* *
* If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to
* enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are * enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are

View File

@ -103,17 +103,23 @@ extern "C" {
#undef GLFW_APIENTRY_DEFINED #undef GLFW_APIENTRY_DEFINED
#endif #endif
#include <windows.h> #include <windows.h>
#elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL) #endif
#if defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL)
#if defined(__OBJC__) #if defined(__OBJC__)
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
#else #else
#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>
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) #endif
#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
#include <wayland-client.h> #include <wayland-client.h>
#endif #endif

View File

@ -791,7 +791,19 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
contentRect = NSMakeRect(xpos, ypos, mode.width, mode.height); contentRect = NSMakeRect(xpos, ypos, mode.width, mode.height);
} }
else else
contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height); {
if (wndconfig->xpos == GLFW_ANY_POSITION ||
wndconfig->ypos == GLFW_ANY_POSITION)
{
contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height);
}
else
{
const int xpos = wndconfig->xpos;
const int ypos = _glfwTransformYCocoa(wndconfig->ypos + wndconfig->height - 1);
contentRect = NSMakeRect(xpos, ypos, wndconfig->width, wndconfig->height);
}
}
NSUInteger styleMask = NSWindowStyleMaskMiniaturizable; NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;
@ -821,10 +833,14 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
[window->ns.object setLevel:NSMainMenuWindowLevel + 1]; [window->ns.object setLevel:NSMainMenuWindowLevel + 1];
else else
{ {
[(NSWindow*) window->ns.object center]; if (wndconfig->xpos == GLFW_ANY_POSITION ||
_glfw.ns.cascadePoint = wndconfig->ypos == GLFW_ANY_POSITION)
NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint: {
NSPointFromCGPoint(_glfw.ns.cascadePoint)]); [(NSWindow*) window->ns.object center];
_glfw.ns.cascadePoint =
NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint:
NSPointFromCGPoint(_glfw.ns.cascadePoint)]);
}
if (wndconfig->resizable) if (wndconfig->resizable)
{ {
@ -1625,8 +1641,16 @@ void _glfwSetCursorPosCocoa(_GLFWwindow* window, double x, double y)
void _glfwSetCursorModeCocoa(_GLFWwindow* window, int mode) void _glfwSetCursorModeCocoa(_GLFWwindow* window, int mode)
{ {
@autoreleasepool { @autoreleasepool {
if (mode == GLFW_CURSOR_CAPTURED)
{
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
"Cocoa: Captured cursor mode not yet implemented");
}
if (_glfwWindowFocusedCocoa(window)) if (_glfwWindowFocusedCocoa(window))
updateCursorMode(window); updateCursorMode(window);
} // autoreleasepool } // autoreleasepool
} }

View File

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

View File

@ -226,7 +226,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 _glfwPlatformGetModuleSymbol(_glfw.glx.handle, procname); return _glfwPlatformGetModuleSymbol(_glfw.glx.handle, procname);
}
} }
static void destroyContextGLX(_GLFWwindow* window) static void destroyContextGLX(_GLFWwindow* window)
@ -262,6 +265,7 @@ GLFWbool _glfwInitGLX(void)
#elif defined(__OpenBSD__) || defined(__NetBSD__) #elif defined(__OpenBSD__) || defined(__NetBSD__)
"libGL.so", "libGL.so",
#else #else
"libGLX.so.0",
"libGL.so.1", "libGL.so.1",
"libGL.so", "libGL.so",
#endif #endif

View File

@ -596,7 +596,8 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
{ {
if (value != GLFW_CURSOR_NORMAL && if (value != GLFW_CURSOR_NORMAL &&
value != GLFW_CURSOR_HIDDEN && value != GLFW_CURSOR_HIDDEN &&
value != GLFW_CURSOR_DISABLED) value != GLFW_CURSOR_DISABLED &&
value != GLFW_CURSOR_CAPTURED)
{ {
_glfwInputError(GLFW_INVALID_ENUM, _glfwInputError(GLFW_INVALID_ENUM,
"Invalid cursor mode 0x%08X", "Invalid cursor mode 0x%08X",

View File

@ -396,6 +396,8 @@ struct _GLFWinitconfig
// //
struct _GLFWwndconfig struct _GLFWwndconfig
{ {
int xpos;
int ypos;
int width; int width;
int height; int height;
const char* title; const char* title;
@ -421,6 +423,9 @@ struct _GLFWwndconfig
struct { struct {
GLFWbool keymenu; GLFWbool keymenu;
} win32; } win32;
struct {
char appId[256];
} wl;
}; };
// Context configuration // Context configuration

View File

@ -82,8 +82,17 @@ static int createNativeWindow(_GLFWwindow* window,
fitToMonitor(window); fitToMonitor(window);
else else
{ {
window->null.xpos = 17; if (wndconfig->xpos == GLFW_ANY_POSITION && wndconfig->ypos == GLFW_ANY_POSITION)
window->null.ypos = 17; {
window->null.xpos = 17;
window->null.ypos = 17;
}
else
{
window->null.xpos = wndconfig->xpos;
window->null.ypos = wndconfig->ypos;
}
window->null.width = wndconfig->width; window->null.width = wndconfig->width;
window->null.height = wndconfig->height; window->null.height = wndconfig->height;
} }

View File

@ -456,6 +456,8 @@ typedef struct _GLFWlibraryWin32
double restoreCursorPosX, restoreCursorPosY; double restoreCursorPosX, restoreCursorPosY;
// The window whose disabled cursor mode is active // The window whose disabled cursor mode is active
_GLFWwindow* disabledCursorWindow; _GLFWwindow* disabledCursorWindow;
// The window the cursor is captured in
_GLFWwindow* capturedCursorWindow;
RAWINPUT* rawInput; RAWINPUT* rawInput;
int rawInputSize; int rawInputSize;
UINT mouseTrailSize; UINT mouseTrailSize;

View File

@ -238,7 +238,8 @@ static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
// //
static void updateCursorImage(_GLFWwindow* window) static void updateCursorImage(_GLFWwindow* window)
{ {
if (window->cursorMode == GLFW_CURSOR_NORMAL) if (window->cursorMode == GLFW_CURSOR_NORMAL ||
window->cursorMode == GLFW_CURSOR_CAPTURED)
{ {
if (window->cursor) if (window->cursor)
SetCursor(window->cursor->win32.handle); SetCursor(window->cursor->win32.handle);
@ -249,20 +250,24 @@ static void updateCursorImage(_GLFWwindow* window)
SetCursor(NULL); SetCursor(NULL);
} }
// Updates the cursor clip rect // Sets the cursor clip rect to the window content area
// //
static void updateClipRect(_GLFWwindow* window) static void captureCursor(_GLFWwindow* window)
{ {
if (window) RECT clipRect;
{ GetClientRect(window->win32.handle, &clipRect);
RECT clipRect; ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);
GetClientRect(window->win32.handle, &clipRect); ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);
ClientToScreen(window->win32.handle, (POINT*) &clipRect.left); ClipCursor(&clipRect);
ClientToScreen(window->win32.handle, (POINT*) &clipRect.right); _glfw.win32.capturedCursorWindow = window;
ClipCursor(&clipRect); }
}
else // Disabled clip cursor
ClipCursor(NULL); //
static void releaseCursor(void)
{
ClipCursor(NULL);
_glfw.win32.capturedCursorWindow = NULL;
} }
// Enables WM_INPUT messages for the mouse for the specified window // Enables WM_INPUT messages for the mouse for the specified window
@ -301,7 +306,7 @@ static void disableCursor(_GLFWwindow* window)
&_glfw.win32.restoreCursorPosY); &_glfw.win32.restoreCursorPosY);
updateCursorImage(window); updateCursorImage(window);
_glfwCenterCursorInContentArea(window); _glfwCenterCursorInContentArea(window);
updateClipRect(window); captureCursor(window);
if (window->rawMouseMotion) if (window->rawMouseMotion)
enableRawMouseMotion(window); enableRawMouseMotion(window);
@ -315,7 +320,7 @@ static void enableCursor(_GLFWwindow* window)
disableRawMouseMotion(window); disableRawMouseMotion(window);
_glfw.win32.disabledCursorWindow = NULL; _glfw.win32.disabledCursorWindow = NULL;
updateClipRect(NULL); releaseCursor();
_glfwSetCursorPosWin32(window, _glfwSetCursorPosWin32(window,
_glfw.win32.restoreCursorPosX, _glfw.win32.restoreCursorPosX,
_glfw.win32.restoreCursorPosY); _glfw.win32.restoreCursorPosY);
@ -582,6 +587,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
{ {
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
disableCursor(window); disableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
window->win32.frameAction = GLFW_FALSE; window->win32.frameAction = GLFW_FALSE;
} }
@ -600,6 +607,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
disableCursor(window); disableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
return 0; return 0;
} }
@ -608,6 +617,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
{ {
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
enableCursor(window); enableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
releaseCursor();
if (window->monitor && window->autoIconify) if (window->monitor && window->autoIconify)
_glfwIconifyWindowWin32(window); _glfwIconifyWindowWin32(window);
@ -977,6 +988,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
// resizing the window or using the window menu // resizing the window or using the window menu
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
enableCursor(window); enableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
releaseCursor();
break; break;
} }
@ -991,6 +1004,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
// resizing the window or using the menu // resizing the window or using the menu
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
disableCursor(window); disableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
break; break;
} }
@ -1004,8 +1019,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
(window->win32.maximized && (window->win32.maximized &&
wParam != SIZE_RESTORED); wParam != SIZE_RESTORED);
if (_glfw.win32.disabledCursorWindow == window) if (_glfw.win32.capturedCursorWindow == window)
updateClipRect(window); captureCursor(window);
if (window->win32.iconified != iconified) if (window->win32.iconified != iconified)
_glfwInputWindowIconify(window, iconified); _glfwInputWindowIconify(window, iconified);
@ -1040,8 +1055,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
case WM_MOVE: case WM_MOVE:
{ {
if (_glfw.win32.disabledCursorWindow == window) if (_glfw.win32.capturedCursorWindow == window)
updateClipRect(window); captureCursor(window);
// NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as // NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as
// those macros do not handle negative window positions correctly // those macros do not handle negative window positions correctly
@ -1313,17 +1328,27 @@ static int createNativeWindow(_GLFWwindow* window,
} }
else else
{ {
xpos = CW_USEDEFAULT; RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
ypos = CW_USEDEFAULT;
window->win32.maximized = wndconfig->maximized; window->win32.maximized = wndconfig->maximized;
if (wndconfig->maximized) if (wndconfig->maximized)
style |= WS_MAXIMIZE; style |= WS_MAXIMIZE;
getFullWindowSize(style, exStyle, AdjustWindowRectEx(&rect, style, FALSE, exStyle);
wndconfig->width, wndconfig->height,
&fullWidth, &fullHeight, if (wndconfig->xpos == GLFW_ANY_POSITION && wndconfig->ypos == GLFW_ANY_POSITION)
USER_DEFAULT_SCREEN_DPI); {
xpos = CW_USEDEFAULT;
ypos = CW_USEDEFAULT;
}
else
{
xpos = wndconfig->xpos + rect.left;
ypos = wndconfig->ypos + rect.top;
}
fullWidth = rect.right - rect.left;
fullHeight = rect.bottom - rect.top;
} }
wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title); wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);
@ -1511,7 +1536,10 @@ void _glfwDestroyWindowWin32(_GLFWwindow* window)
window->context.destroy(window); window->context.destroy(window);
if (_glfw.win32.disabledCursorWindow == window) if (_glfw.win32.disabledCursorWindow == window)
_glfw.win32.disabledCursorWindow = NULL; enableCursor(window);
if (_glfw.win32.capturedCursorWindow == window)
releaseCursor();
if (window->win32.TaskbarList) if (window->win32.TaskbarList)
window->win32.TaskbarList->lpVtbl->Release(window->win32.TaskbarList); window->win32.TaskbarList->lpVtbl->Release(window->win32.TaskbarList);
@ -2178,14 +2206,40 @@ void _glfwSetCursorPosWin32(_GLFWwindow* window, double xpos, double ypos)
void _glfwSetCursorModeWin32(_GLFWwindow* window, int mode) void _glfwSetCursorModeWin32(_GLFWwindow* window, int mode)
{ {
if (mode == GLFW_CURSOR_DISABLED) if (_glfwWindowFocusedWin32(window))
{ {
if (_glfwWindowFocusedWin32(window)) if (mode == GLFW_CURSOR_DISABLED)
disableCursor(window); {
_glfwGetCursorPosWin32(window,
&_glfw.win32.restoreCursorPosX,
&_glfw.win32.restoreCursorPosY);
_glfwCenterCursorInContentArea(window);
if (window->rawMouseMotion)
enableRawMouseMotion(window);
}
else if (_glfw.win32.disabledCursorWindow == window)
{
if (window->rawMouseMotion)
disableRawMouseMotion(window);
}
if (mode == GLFW_CURSOR_DISABLED || mode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
else
releaseCursor();
if (mode == GLFW_CURSOR_DISABLED)
_glfw.win32.disabledCursorWindow = window;
else if (_glfw.win32.disabledCursorWindow == window)
{
_glfw.win32.disabledCursorWindow = NULL;
_glfwSetCursorPosWin32(window,
_glfw.win32.restoreCursorPosX,
_glfw.win32.restoreCursorPosY);
}
} }
else if (_glfw.win32.disabledCursorWindow == window)
enableCursor(window); if (cursorInContentArea(window))
else if (cursorInContentArea(window))
updateCursorImage(window); updateCursorImage(window);
} }

View File

@ -274,6 +274,8 @@ void glfwDefaultWindowHints(void)
_glfw.hints.window.autoIconify = GLFW_TRUE; _glfw.hints.window.autoIconify = GLFW_TRUE;
_glfw.hints.window.centerCursor = GLFW_TRUE; _glfw.hints.window.centerCursor = GLFW_TRUE;
_glfw.hints.window.focusOnShow = GLFW_TRUE; _glfw.hints.window.focusOnShow = GLFW_TRUE;
_glfw.hints.window.xpos = GLFW_ANY_POSITION;
_glfw.hints.window.ypos = GLFW_ANY_POSITION;
// The default is 24 bits of color, 24 bits of depth and 8 bits of stencil, // The default is 24 bits of color, 24 bits of depth and 8 bits of stencil,
// double buffered // double buffered
@ -368,6 +370,12 @@ GLFWAPI void glfwWindowHint(int hint, int value)
case GLFW_VISIBLE: case GLFW_VISIBLE:
_glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE; _glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE;
return; return;
case GLFW_POSITION_X:
_glfw.hints.window.xpos = value;
return;
case GLFW_POSITION_Y:
_glfw.hints.window.ypos = value;
return;
case GLFW_COCOA_RETINA_FRAMEBUFFER: case GLFW_COCOA_RETINA_FRAMEBUFFER:
_glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE; _glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE;
return; return;
@ -447,6 +455,10 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value)
strncpy(_glfw.hints.window.x11.instanceName, value, strncpy(_glfw.hints.window.x11.instanceName, value,
sizeof(_glfw.hints.window.x11.instanceName) - 1); sizeof(_glfw.hints.window.x11.instanceName) - 1);
return; return;
case GLFW_WAYLAND_APP_ID:
strncpy(_glfw.hints.window.wl.appId, value,
sizeof(_glfw.hints.window.wl.appId) - 1);
return;
} }
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint); _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint);

View File

@ -258,6 +258,7 @@ typedef struct _GLFWwindowWayland
double cursorPosX, cursorPosY; double cursorPosX, cursorPosY;
char* title; char* title;
char* appId;
// We need to track the monitors the window spans on to calculate the // We need to track the monitors the window spans on to calculate the
// optimal scaling factor. // optimal scaling factor.
@ -266,10 +267,9 @@ typedef struct _GLFWwindowWayland
int monitorsCount; int monitorsCount;
int monitorsSize; int monitorsSize;
struct { struct zwp_relative_pointer_v1* relativePointer;
struct zwp_relative_pointer_v1* relativePointer; struct zwp_locked_pointer_v1* lockedPointer;
struct zwp_locked_pointer_v1* lockedPointer; struct zwp_confined_pointer_v1* confinedPointer;
} pointerLock;
struct zwp_idle_inhibitor_v1* idleInhibitor; struct zwp_idle_inhibitor_v1* idleInhibitor;

View File

@ -614,6 +614,9 @@ static GLFWbool createShellObjects(_GLFWwindow* window)
xdg_toplevel_add_listener(window->wl.xdg.toplevel, &xdgToplevelListener, window); xdg_toplevel_add_listener(window->wl.xdg.toplevel, &xdgToplevelListener, window);
if (window->wl.appId)
xdg_toplevel_set_app_id(window->wl.xdg.toplevel, window->wl.appId);
if (window->wl.title) if (window->wl.title)
xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title); xdg_toplevel_set_title(window->wl.xdg.toplevel, window->wl.title);
@ -728,6 +731,7 @@ static GLFWbool createNativeSurface(_GLFWwindow* window,
window->wl.height = wndconfig->height; window->wl.height = wndconfig->height;
window->wl.scale = 1; window->wl.scale = 1;
window->wl.title = _glfw_strdup(wndconfig->title); window->wl.title = _glfw_strdup(wndconfig->title);
window->wl.appId = _glfw_strdup(wndconfig->wl.appId);
window->wl.maximized = wndconfig->maximized; window->wl.maximized = wndconfig->maximized;
@ -1850,6 +1854,15 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window)
if (window->wl.idleInhibitor) if (window->wl.idleInhibitor)
zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor); zwp_idle_inhibitor_v1_destroy(window->wl.idleInhibitor);
if (window->wl.relativePointer)
zwp_relative_pointer_v1_destroy(window->wl.relativePointer);
if (window->wl.lockedPointer)
zwp_locked_pointer_v1_destroy(window->wl.lockedPointer);
if (window->wl.confinedPointer)
zwp_confined_pointer_v1_destroy(window->wl.confinedPointer);
if (window->context.destroy) if (window->context.destroy)
window->context.destroy(window); window->context.destroy(window);
@ -1865,6 +1878,7 @@ void _glfwDestroyWindowWayland(_GLFWwindow* window)
wl_surface_destroy(window->wl.surface); wl_surface_destroy(window->wl.surface);
_glfw_free(window->wl.title); _glfw_free(window->wl.title);
_glfw_free(window->wl.appId);
_glfw_free(window->wl.monitors); _glfw_free(window->wl.monitors);
} }
@ -2242,16 +2256,10 @@ void _glfwGetCursorPosWayland(_GLFWwindow* window, double* xpos, double* ypos)
*ypos = window->wl.cursorPosY; *ypos = window->wl.cursorPosY;
} }
static GLFWbool isPointerLocked(_GLFWwindow* window);
void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y) void _glfwSetCursorPosWayland(_GLFWwindow* window, double x, double y)
{ {
if (isPointerLocked(window)) _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
{ "Wayland: The platform does not support setting the cursor position");
zwp_locked_pointer_v1_set_cursor_position_hint(
window->wl.pointerLock.lockedPointer,
wl_fixed_from_double(x), wl_fixed_from_double(y));
}
} }
void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode) void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode)
@ -2485,22 +2493,6 @@ static void lockedPointerHandleLocked(void* userData,
{ {
} }
static void unlockPointer(_GLFWwindow* window)
{
struct zwp_relative_pointer_v1* relativePointer =
window->wl.pointerLock.relativePointer;
struct zwp_locked_pointer_v1* lockedPointer =
window->wl.pointerLock.lockedPointer;
zwp_relative_pointer_v1_destroy(relativePointer);
zwp_locked_pointer_v1_destroy(lockedPointer);
window->wl.pointerLock.relativePointer = NULL;
window->wl.pointerLock.lockedPointer = NULL;
}
static void lockPointer(_GLFWwindow* window);
static void lockedPointerHandleUnlocked(void* userData, static void lockedPointerHandleUnlocked(void* userData,
struct zwp_locked_pointer_v1* lockedPointer) struct zwp_locked_pointer_v1* lockedPointer)
{ {
@ -2514,52 +2506,81 @@ static const struct zwp_locked_pointer_v1_listener lockedPointerListener =
static void lockPointer(_GLFWwindow* window) static void lockPointer(_GLFWwindow* window)
{ {
struct zwp_relative_pointer_v1* relativePointer;
struct zwp_locked_pointer_v1* lockedPointer;
if (!_glfw.wl.relativePointerManager) if (!_glfw.wl.relativePointerManager)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_FEATURE_UNAVAILABLE,
"Wayland: no relative pointer manager"); "Wayland: The compositor does not support pointer locking");
return; return;
} }
relativePointer = window->wl.relativePointer =
zwp_relative_pointer_manager_v1_get_relative_pointer( zwp_relative_pointer_manager_v1_get_relative_pointer(
_glfw.wl.relativePointerManager, _glfw.wl.relativePointerManager,
_glfw.wl.pointer); _glfw.wl.pointer);
zwp_relative_pointer_v1_add_listener(relativePointer, zwp_relative_pointer_v1_add_listener(window->wl.relativePointer,
&relativePointerListener, &relativePointerListener,
window); window);
lockedPointer = window->wl.lockedPointer =
zwp_pointer_constraints_v1_lock_pointer( zwp_pointer_constraints_v1_lock_pointer(
_glfw.wl.pointerConstraints, _glfw.wl.pointerConstraints,
window->wl.surface, window->wl.surface,
_glfw.wl.pointer, _glfw.wl.pointer,
NULL, NULL,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
zwp_locked_pointer_v1_add_listener(lockedPointer, zwp_locked_pointer_v1_add_listener(window->wl.lockedPointer,
&lockedPointerListener, &lockedPointerListener,
window); window);
window->wl.pointerLock.relativePointer = relativePointer;
window->wl.pointerLock.lockedPointer = lockedPointer;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
NULL, 0, 0);
} }
static GLFWbool isPointerLocked(_GLFWwindow* window) static void unlockPointer(_GLFWwindow* window)
{ {
return window->wl.pointerLock.lockedPointer != NULL; zwp_relative_pointer_v1_destroy(window->wl.relativePointer);
window->wl.relativePointer = NULL;
zwp_locked_pointer_v1_destroy(window->wl.lockedPointer);
window->wl.lockedPointer = NULL;
}
static void confinedPointerHandleConfined(void* userData,
struct zwp_confined_pointer_v1* confinedPointer)
{
}
static void confinedPointerHandleUnconfined(void* userData,
struct zwp_confined_pointer_v1* confinedPointer)
{
}
static const struct zwp_confined_pointer_v1_listener confinedPointerListener =
{
confinedPointerHandleConfined,
confinedPointerHandleUnconfined
};
static void confinePointer(_GLFWwindow* window)
{
window->wl.confinedPointer =
zwp_pointer_constraints_v1_confine_pointer(
_glfw.wl.pointerConstraints,
window->wl.surface,
_glfw.wl.pointer,
NULL,
ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
zwp_confined_pointer_v1_add_listener(window->wl.confinedPointer,
&confinedPointerListener,
window);
}
static void unconfinePointer(_GLFWwindow* window)
{
zwp_confined_pointer_v1_destroy(window->wl.confinedPointer);
window->wl.confinedPointer = NULL;
} }
void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor) void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor)
{ {
struct wl_cursor* defaultCursor;
struct wl_cursor* defaultCursorHiDPI = NULL;
if (!_glfw.wl.pointer) if (!_glfw.wl.pointer)
return; return;
@ -2570,29 +2591,55 @@ void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor)
if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != mainWindow) if (window != _glfw.wl.pointerFocus || window->wl.decorations.focus != mainWindow)
return; return;
// Unlock possible pointer lock if no longer disabled. // Update pointer lock to match cursor mode
if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window)) if (window->cursorMode == GLFW_CURSOR_DISABLED)
unlockPointer(window); {
if (window->wl.confinedPointer)
unconfinePointer(window);
if (!window->wl.lockedPointer)
lockPointer(window);
}
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
{
if (window->wl.lockedPointer)
unlockPointer(window);
if (!window->wl.confinedPointer)
confinePointer(window);
}
else if (window->cursorMode == GLFW_CURSOR_NORMAL ||
window->cursorMode == GLFW_CURSOR_HIDDEN)
{
if (window->wl.lockedPointer)
unlockPointer(window);
else if (window->wl.confinedPointer)
unconfinePointer(window);
}
if (window->cursorMode == GLFW_CURSOR_NORMAL) if (window->cursorMode == GLFW_CURSOR_NORMAL ||
window->cursorMode == GLFW_CURSOR_CAPTURED)
{ {
if (cursor) if (cursor)
setCursorImage(window, &cursor->wl); setCursorImage(window, &cursor->wl);
else else
{ {
defaultCursor = wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, struct wl_cursor* defaultCursor =
"left_ptr"); wl_cursor_theme_get_cursor(_glfw.wl.cursorTheme, "left_ptr");
if (!defaultCursor) if (!defaultCursor)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Standard cursor not found"); "Wayland: Standard cursor not found");
return; return;
} }
struct wl_cursor* defaultCursorHiDPI = NULL;
if (_glfw.wl.cursorThemeHiDPI) if (_glfw.wl.cursorThemeHiDPI)
{
defaultCursorHiDPI = defaultCursorHiDPI =
wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, wl_cursor_theme_get_cursor(_glfw.wl.cursorThemeHiDPI, "left_ptr");
"left_ptr"); }
_GLFWcursorWayland cursorWayland = {
_GLFWcursorWayland cursorWayland =
{
defaultCursor, defaultCursor,
defaultCursorHiDPI, defaultCursorHiDPI,
NULL, NULL,
@ -2600,15 +2647,12 @@ void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor)
0, 0, 0, 0,
0 0
}; };
setCursorImage(window, &cursorWayland); setCursorImage(window, &cursorWayland);
} }
} }
else if (window->cursorMode == GLFW_CURSOR_DISABLED) else if (window->cursorMode == GLFW_CURSOR_HIDDEN ||
{ window->cursorMode == GLFW_CURSOR_DISABLED)
if (!isPointerLocked(window))
lockPointer(window);
}
else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
{ {
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial, NULL, 0, 0); wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial, NULL, 0, 0);
} }

View File

@ -480,7 +480,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

@ -270,6 +270,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)
@ -306,9 +311,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);
} }
@ -453,7 +455,8 @@ static char* convertLatin1toUTF8(const char* source)
// //
static void updateCursorImage(_GLFWwindow* window) static void updateCursorImage(_GLFWwindow* window)
{ {
if (window->cursorMode == GLFW_CURSOR_NORMAL) if (window->cursorMode == GLFW_CURSOR_NORMAL ||
window->cursorMode == GLFW_CURSOR_CAPTURED)
{ {
if (window->cursor) if (window->cursor)
{ {
@ -470,6 +473,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)
@ -512,12 +534,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
@ -528,7 +545,7 @@ static void enableCursor(_GLFWwindow* window)
disableRawMouseMotion(window); disableRawMouseMotion(window);
_glfw.x11.disabledCursorWindow = NULL; _glfw.x11.disabledCursorWindow = NULL;
XUngrabPointer(_glfw.x11.display, CurrentTime); releaseCursor();
_glfwSetCursorPosX11(window, _glfwSetCursorPosX11(window,
_glfw.x11.restoreCursorPosX, _glfw.x11.restoreCursorPosX,
_glfw.x11.restoreCursorPosY); _glfw.x11.restoreCursorPosY);
@ -558,6 +575,14 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
height *= _glfw.x11.contentScaleY; height *= _glfw.x11.contentScaleY;
} }
int xpos = 0, ypos = 0;
if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION)
{
xpos = wndconfig->xpos;
ypos = wndconfig->ypos;
}
// Create a colormap based on the visual used by the current context // Create a colormap based on the visual used by the current context
window->x11.colormap = XCreateColormap(_glfw.x11.display, window->x11.colormap = XCreateColormap(_glfw.x11.display,
_glfw.x11.root, _glfw.x11.root,
@ -578,7 +603,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
window->x11.parent = _glfw.x11.root; window->x11.parent = _glfw.x11.root;
window->x11.handle = XCreateWindow(_glfw.x11.display, window->x11.handle = XCreateWindow(_glfw.x11.display,
_glfw.x11.root, _glfw.x11.root,
0, 0, // Position xpos, ypos,
width, height, width, height,
0, // Border width 0, // Border width
depth, // Color depth depth, // Color depth
@ -681,7 +706,37 @@ 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;
}
// HACK: Explicitly setting PPosition to any value causes some WMs, notably
// Compiz and Metacity, to honor the position of unmapped windows
if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION)
{
hints->flags |= PPosition;
hints->x = 0;
hints->y = 0;
}
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
{ {
@ -1691,6 +1746,8 @@ static void processEvent(XEvent *event)
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
disableCursor(window); disableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
if (window->x11.ic) if (window->x11.ic)
XSetICFocus(window->x11.ic); XSetICFocus(window->x11.ic);
@ -1711,6 +1768,8 @@ static void processEvent(XEvent *event)
if (window->cursorMode == GLFW_CURSOR_DISABLED) if (window->cursorMode == GLFW_CURSOR_DISABLED)
enableCursor(window); enableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
releaseCursor();
if (window->x11.ic) if (window->x11.ic)
XUnsetICFocus(window->x11.ic); XUnsetICFocus(window->x11.ic);
@ -1986,7 +2045,7 @@ GLFWbool _glfwCreateWindowX11(_GLFWwindow* window,
void _glfwDestroyWindowX11(_GLFWwindow* window) void _glfwDestroyWindowX11(_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);
@ -2805,16 +2864,40 @@ void _glfwSetCursorPosX11(_GLFWwindow* window, double x, double y)
void _glfwSetCursorModeX11(_GLFWwindow* window, int mode) void _glfwSetCursorModeX11(_GLFWwindow* window, int mode)
{ {
if (mode == GLFW_CURSOR_DISABLED) if (_glfwWindowFocusedX11(window))
{ {
if (_glfwWindowFocusedX11(window)) if (mode == GLFW_CURSOR_DISABLED)
disableCursor(window); {
} _glfwGetCursorPosX11(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 || mode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
else
releaseCursor();
if (mode == GLFW_CURSOR_DISABLED)
_glfw.x11.disabledCursorWindow = window;
else if (_glfw.x11.disabledCursorWindow == window)
{
_glfw.x11.disabledCursorWindow = NULL;
_glfwSetCursorPosX11(window,
_glfw.x11.restoreCursorPosX,
_glfw.x11.restoreCursorPosY);
}
}
updateCursorImage(window);
XFlush(_glfw.x11.display); XFlush(_glfw.x11.display);
} }
@ -2970,7 +3053,8 @@ void _glfwDestroyCursorX11(_GLFWcursor* cursor)
void _glfwSetCursorX11(_GLFWwindow* window, _GLFWcursor* cursor) void _glfwSetCursorX11(_GLFWwindow* window, _GLFWcursor* cursor)
{ {
if (window->cursorMode == GLFW_CURSOR_NORMAL) if (window->cursorMode == GLFW_CURSOR_NORMAL ||
window->cursorMode == GLFW_CURSOR_CAPTURED)
{ {
updateCursorImage(window); updateCursorImage(window);
XFlush(_glfw.x11.display); XFlush(_glfw.x11.display);

View File

@ -172,7 +172,8 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
case GLFW_KEY_ESCAPE: case GLFW_KEY_ESCAPE:
{ {
if (glfwGetInputMode(window, GLFW_CURSOR) != GLFW_CURSOR_DISABLED) const int mode = glfwGetInputMode(window, GLFW_CURSOR);
if (mode != GLFW_CURSOR_DISABLED && mode != GLFW_CURSOR_CAPTURED)
{ {
glfwSetWindowShouldClose(window, GLFW_TRUE); glfwSetWindowShouldClose(window, GLFW_TRUE);
break; break;
@ -197,6 +198,11 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
printf("(( cursor is hidden ))\n"); printf("(( cursor is hidden ))\n");
break; break;
case GLFW_KEY_C:
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_CAPTURED);
printf("(( cursor is captured ))\n");
break;
case GLFW_KEY_R: case GLFW_KEY_R:
if (!glfwRawMouseMotionSupported()) if (!glfwRawMouseMotionSupported())
break; break;

View File

@ -96,10 +96,11 @@ int main(void)
if (!glfwInit()) if (!glfwInit())
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
{ {
glfwWindowHint(GLFW_POSITION_X, 200 + 250 * i);
glfwWindowHint(GLFW_POSITION_Y, 200);
threads[i].window = glfwCreateWindow(200, 200, threads[i].window = glfwCreateWindow(200, 200,
threads[i].title, threads[i].title,
NULL, NULL); NULL, NULL);
@ -110,9 +111,6 @@ int main(void)
} }
glfwSetKeyCallback(threads[i].window, key_callback); glfwSetKeyCallback(threads[i].window, key_callback);
glfwSetWindowPos(threads[i].window, 200 + 250 * i, 200);
glfwShowWindow(threads[i].window);
} }
glfwMakeContextCurrent(threads[0].window); glfwMakeContextCurrent(threads[0].window);