diff --git a/.travis.yml b/.travis.yml index abb0a46e6..2448fada5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,12 +50,17 @@ matrix: - os: osx env: BUILD_SHARED_LIBS=OFF script: + - if grep -Inr '\s$' src include docs tests examples CMake *.md .gitattributes .gitignore; then echo Trailing whitespace found, aborting.; exit 1; fi - mkdir build - cd build - - if test -n "${USE_WAYLAND}"; then wget https://mirrors.kernel.org/ubuntu/pool/universe/e/extra-cmake-modules/extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb; fi - - if test -n "${USE_WAYLAND}"; then sudo dpkg -i extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb; fi - - if test -n "${USE_WAYLAND}"; then git clone git://anongit.freedesktop.org/wayland/wayland-protocols; fi - - if test -n "${USE_WAYLAND}"; then pushd wayland-protocols; ./autogen.sh --prefix=/usr; make -j; sudo make install; popd; fi + - if test -n "${USE_WAYLAND}"; + then wget https://mirrors.kernel.org/ubuntu/pool/universe/e/extra-cmake-modules/extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb; + sudo dpkg -i extra-cmake-modules_5.38.0a-0ubuntu1_amd64.deb; + git clone git://anongit.freedesktop.org/wayland/wayland-protocols; + pushd wayland-protocols; + git checkout 1.6 && ./autogen.sh --prefix=/usr && make && sudo make install; + popd; + fi - cmake -DCMAKE_VERBOSE_MAKEFILE=ON -DBUILD_SHARED_LIBS=${BUILD_SHARED_LIBS} -DGLFW_USE_WAYLAND=${USE_WAYLAND} .. - cmake --build . notifications: diff --git a/CMake/amd64-mingw32msvc.cmake b/CMake/amd64-mingw32msvc.cmake index 705e251d3..c264ff0da 100644 --- a/CMake/amd64-mingw32msvc.cmake +++ b/CMake/amd64-mingw32msvc.cmake @@ -6,7 +6,7 @@ SET(CMAKE_CXX_COMPILER "amd64-mingw32msvc-g++") SET(CMAKE_RC_COMPILER "amd64-mingw32msvc-windres") SET(CMAKE_RANLIB "amd64-mingw32msvc-ranlib") -# Configure the behaviour of the find commands +# Configure the behaviour of the find commands SET(CMAKE_FIND_ROOT_PATH "/usr/amd64-mingw32msvc") SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) diff --git a/CMake/i586-mingw32msvc.cmake b/CMake/i586-mingw32msvc.cmake index 393ddbda3..c871e5be5 100644 --- a/CMake/i586-mingw32msvc.cmake +++ b/CMake/i586-mingw32msvc.cmake @@ -6,7 +6,7 @@ SET(CMAKE_CXX_COMPILER "i586-mingw32msvc-g++") SET(CMAKE_RC_COMPILER "i586-mingw32msvc-windres") SET(CMAKE_RANLIB "i586-mingw32msvc-ranlib") -# Configure the behaviour of the find commands +# Configure the behaviour of the find commands SET(CMAKE_FIND_ROOT_PATH "/usr/i586-mingw32msvc") SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) diff --git a/CMake/i686-pc-mingw32.cmake b/CMake/i686-pc-mingw32.cmake index 9a46aef7b..b657d9448 100644 --- a/CMake/i686-pc-mingw32.cmake +++ b/CMake/i686-pc-mingw32.cmake @@ -6,7 +6,7 @@ SET(CMAKE_CXX_COMPILER "i686-pc-mingw32-g++") SET(CMAKE_RC_COMPILER "i686-pc-mingw32-windres") SET(CMAKE_RANLIB "i686-pc-mingw32-ranlib") -#Configure the behaviour of the find commands +#Configure the behaviour of the find commands SET(CMAKE_FIND_ROOT_PATH "/opt/mingw/usr/i686-pc-mingw32") SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) diff --git a/CMake/i686-w64-mingw32.cmake b/CMake/i686-w64-mingw32.cmake index 9bd60936d..bbd9f8956 100644 --- a/CMake/i686-w64-mingw32.cmake +++ b/CMake/i686-w64-mingw32.cmake @@ -6,7 +6,7 @@ SET(CMAKE_CXX_COMPILER "i686-w64-mingw32-g++") SET(CMAKE_RC_COMPILER "i686-w64-mingw32-windres") SET(CMAKE_RANLIB "i686-w64-mingw32-ranlib") -# Configure the behaviour of the find commands +# Configure the behaviour of the find commands SET(CMAKE_FIND_ROOT_PATH "/usr/i686-w64-mingw32") SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) diff --git a/CMake/x86_64-w64-mingw32.cmake b/CMake/x86_64-w64-mingw32.cmake index 84b2c701e..e629e4573 100644 --- a/CMake/x86_64-w64-mingw32.cmake +++ b/CMake/x86_64-w64-mingw32.cmake @@ -6,7 +6,7 @@ SET(CMAKE_CXX_COMPILER "x86_64-w64-mingw32-g++") SET(CMAKE_RC_COMPILER "x86_64-w64-mingw32-windres") SET(CMAKE_RANLIB "x86_64-w64-mingw32-ranlib") -# Configure the behaviour of the find commands +# Configure the behaviour of the find commands SET(CMAKE_FIND_ROOT_PATH "/usr/x86_64-w64-mingw32") SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) diff --git a/CMakeLists.txt b/CMakeLists.txt index edcf9682e..765d713c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -278,7 +278,7 @@ if (_GLFW_WAYLAND) find_package(Wayland REQUIRED Client Cursor Egl) find_package(WaylandScanner REQUIRED) - find_package(WaylandProtocols 1.1 REQUIRED) + find_package(WaylandProtocols 1.6 REQUIRED) list(APPEND glfw_PKG_DEPS "wayland-egl") diff --git a/LICENSE.md b/LICENSE.md index e4c6682eb..acdac20b9 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2002-2006 Marcus Geelnard +Copyright (c) 2002-2006 Marcus Geelnard Copyright (c) 2006-2016 Camilla Löwy This software is provided 'as-is', without any express or implied diff --git a/README.md b/README.md index 595e49ee7..8568686a4 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ creating windows, contexts and surfaces, reading input, handling events, etc. GLFW natively supports Windows, macOS and Linux and other Unix-like systems. Experimental implementations for the Wayland protocol and the Mir display server -are available but not yet officially supported. +are available but not yet officially supported. GLFW is licensed under the [zlib/libpng license](http://www.glfw.org/license.html). @@ -136,8 +136,9 @@ information on what to include when reporting a bug. gamepad mapping (#900) - Added `glfwGetGamepadState` function, `GLFW_GAMEPAD_*` and `GLFWgamepadstate` for retrieving gamepad input state (#900) -- Added `glfwGetWindowContentScale` and `glfwGetMonitorContentScale` for - DPI-aware rendering (#235,#439,#677,#845,#898) +- Added `glfwGetWindowContentScale`, `glfwGetMonitorContentScale` and + `glfwSetWindowContentScaleCallback` for DPI-aware rendering + (#235,#439,#677,#845,#898) - Added `glfwRequestWindowAttention` function for requesting attention from the user (#732,#988) - Added `glfwGetKeyScancode` function that allows retrieving platform dependent @@ -147,30 +148,38 @@ information on what to include when reporting a bug. - Added `glfwSetWindowAttrib` function for changing window attributes (#537) - Added `glfwGetJoystickHats` function for querying joystick hats (#889,#906,#934) -- Added `glfwInitHint` and `glfwInitHintString` for setting initialization hints +- Added `glfwInitHint` for setting initialization hints +- Added `glfwWindowHintString` for setting string type window hints (#893,#1139) - Added `glfwGetWindowOpacity` and `glfwSetWindowOpacity` for controlling whole window transparency (#1089) +- Added `glfwSetMonitorUserPointer` and `glfwGetMonitorUserPointer` for + per-monitor user pointers +- Added `glfwSetJoystickUserPointer` and `glfwGetJoystickUserPointer` for + per-joystick user pointers - Added `glfwGetX11SelectionString` and `glfwSetX11SelectionString` functions for accessing X11 primary selection (#894,#1056) - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850) - Added definition of `GLAPIENTRY` to public header - Added `GLFW_TRANSPARENT_FRAMEBUFFER` window hint and attribute for controlling per-pixel framebuffer transparency (#197,#663,#715,#723,#1078) +- Added `GLFW_HOVERED` window attribute for polling cursor hover state (#1166) - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering (#749,#842) - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) +- Added `GLFW_LOCK_KEY_MODS` input mode and `GLFW_MOD_*_LOCK` mod bits (#946) - Added macOS specific `GLFW_COCOA_RETINA_FRAMEBUFFER` window hint -- Added macOS specific `GLFW_COCOA_FRAME_AUTOSAVE` window hint (#195) +- Added macOS specific `GLFW_COCOA_FRAME_NAME` window hint (#195) - Added macOS specific `GLFW_COCOA_GRAPHICS_SWITCHING` window hint (#377,#935) - Added macOS specific `GLFW_COCOA_CHDIR_RESOURCES` init hint - Added macOS specific `GLFW_COCOA_MENUBAR` init hint -- Added X11 specific `GLFW_X11_WM_CLASS_NAME` and `GLFW_X11_WM_CLASS_CLASS` init - hints (#893) +- Added X11 specific `GLFW_X11_CLASS_NAME` and `GLFW_X11_INSTANCE_NAME` window + hints (#893,#1139) - Added `GLFW_INCLUDE_ES32` for including the OpenGL ES 3.2 header - Added `GLFW_OSMESA_CONTEXT_API` for creating OpenGL contexts with [OSMesa](https://www.mesa3d.org/osmesa.html) (#281) - Added `GenerateMappings.cmake` script for updating gamepad mappings - Deprecated window parameter of clipboard string functions +- Deprecated charmods callback - Removed `GLFW_USE_RETINA` compile-time option - Removed `GLFW_USE_CHDIR` compile-time option - Removed `GLFW_USE_MENUBAR` compile-time option @@ -205,6 +214,9 @@ information on what to include when reporting a bug. - [Win32] Bugfix: Returned key names did not match other platforms (#943) - [Win32] Bugfix: Undecorated windows did not maximize to workarea (#899) - [Win32] Bugfix: Window was resized twice when entering full screen (#1085) +- [Win32] Bugfix: The HID device notification was not unregistered (#1170) +- [Win32] Bugfix: `glfwCreateWindow` activated window even with `GLFW_FOCUSED` + hint set to false (#1179,#1180) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X @@ -323,6 +335,8 @@ skills. - Mário Freitas - GeO4d - Marcus Geelnard + - Stephen Gowen + - Kovid Goyal - Eloi Marín Gratacós - Stefan Gustavson - Jonathan Hale @@ -388,6 +402,7 @@ skills. - Keith Pitt - Stanislav Podgorskiy - Alexandre Pretyman + - przemekmirek - Philip Rideout - Eddie Ringle - Jorge Rodriguez diff --git a/deps/nuklear.h b/deps/nuklear.h index 333acee78..9b304a22a 100644 --- a/deps/nuklear.h +++ b/deps/nuklear.h @@ -1,6 +1,6 @@ /* - Nuklear - 1.40.0 - public domain - no warrenty implied; use at your own risk. + Nuklear - 2.00.4 - public domain + no warranty implied; use at your own risk. authored from 2015-2017 by Micha Mettke ABOUT: @@ -17,7 +17,7 @@ VALUES: - Graphical user interface toolkit - Single header library - Written in C89 (a.k.a. ANSI C or ISO C90) - - Small codebase (~17kLOC) + - Small codebase (~18kLOC) - Focus on portability, efficiency and simplicity - No dependencies (not even the standard library if not wanted) - Fully skinnable and customizable @@ -47,7 +47,7 @@ USAGE: or even worse stack corruptions. FEATURES: - - Absolutely no platform dependend code + - Absolutely no platform dependent code - Memory management control ranging from/to - Ease of use by allocating everything from standard library - Control every byte of memory inside the library @@ -128,7 +128,7 @@ OPTIONAL DEFINES: If used needs to be defined for implementation and header NK_BUTTON_TRIGGER_ON_RELEASE - Different platforms require button clicks occuring either on buttons being + Different platforms require button clicks occurring either on buttons being pressed (up to down) or released (down to up). By default this library will react on buttons being pressed, but if you define this it will only trigger if a button is released. @@ -516,7 +516,7 @@ enum nk_symbol_type { * To use a context it first has to be initialized which can be achieved by calling * one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`. * Each takes in a font handle and a specific way of handling memory. Memory control - * hereby ranges from standard library to just specifing a fixed sized block of memory + * hereby ranges from standard library to just specifying a fixed sized block of memory * which nuklear has to manage itself from. * * struct nk_context ctx; @@ -529,7 +529,7 @@ enum nk_symbol_type { * * Reference * ------------------- - * nk_init_default - Initializes context with standard library memory alloction (malloc,free) + * nk_init_default - Initializes context with standard library memory allocation (malloc,free) * nk_init_fixed - Initializes context from single fixed size memory block * nk_init - Initializes context with memory allocator callbacks for alloc and free * nk_init_custom - Initializes context from two buffers. One for draw commands the other for window/panel/table allocations @@ -549,10 +549,10 @@ enum nk_symbol_type { NK_API int nk_init_default(struct nk_context*, const struct nk_user_font*); #endif /* nk_init_fixed - Initializes a `nk_context` struct from a single fixed size memory block - * Should be used if you want complete control over nuklears memory management. + * Should be used if you want complete control over nuklear's memory management. * Especially recommended for system with little memory or systems with virtual memory. * For the later case you can just allocate for example 16MB of virtual memory - * and only the required amount of memory will actually be commited. + * and only the required amount of memory will actually be committed. * IMPORTANT: make sure the passed memory block is aligned correctly for `nk_draw_commands` * Parameters: * @ctx must point to an either stack or heap allocated `nk_context` struct @@ -700,37 +700,36 @@ enum nk_buttons { NK_BUTTON_MAX }; /* nk_input_begin - Begins the input mirroring process by resetting text, scroll - * mouse previous mouse position and movement as well as key state transistions, + * mouse previous mouse position and movement as well as key state transitions, * Parameters: * @ctx must point to an previously initialized `nk_context` struct */ NK_API void nk_input_begin(struct nk_context*); -/* nk_input_motion - Mirros current mouse position to nuklear +/* nk_input_motion - Mirrors current mouse position to nuklear * Parameters: * @ctx must point to an previously initialized `nk_context` struct - * @x must constain an integer describing the current mouse cursor x-position - * @y must constain an integer describing the current mouse cursor y-position */ + * @x must contain an integer describing the current mouse cursor x-position + * @y must contain an integer describing the current mouse cursor y-position */ NK_API void nk_input_motion(struct nk_context*, int x, int y); -/* nk_input_key - Mirros state of a specific key to nuklear +/* nk_input_key - Mirrors state of a specific key to nuklear * Parameters: * @ctx must point to an previously initialized `nk_context` struct * @key must be any value specified in enum `nk_keys` that needs to be mirrored * @down must be 0 for key is up and 1 for key is down */ NK_API void nk_input_key(struct nk_context*, enum nk_keys, int down); -/* nk_input_button - Mirros the state of a specific mouse button to nuklear +/* nk_input_button - Mirrors the state of a specific mouse button to nuklear * Parameters: * @ctx must point to an previously initialized `nk_context` struct * @nk_buttons must be any value specified in enum `nk_buttons` that needs to be mirrored - * @x must constain an integer describing mouse cursor x-position on click up/down - * @y must constain an integer describing mouse cursor y-position on click up/down + * @x must contain an integer describing mouse cursor x-position on click up/down + * @y must contain an integer describing mouse cursor y-position on click up/down * @down must be 0 for key is up and 1 for key is down */ NK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, int down); -/* nk_input_char - Copies a single ASCII character into an internal text buffer - * This is basically a helper function to quickly push ASCII characters into - * nuklear. Note that you can only push up to NK_INPUT_MAX bytes into - * struct `nk_input` between `nk_input_begin` and `nk_input_end`. +/* nk_input_scroll - Copies the last mouse scroll value to nuklear. Is generally + * a scroll value. So does not have to come from mouse and could also originate + * from touch for example. * Parameters: * @ctx must point to an previously initialized `nk_context` struct - * @c must be a single ASCII character preferable one that can be printed */ + * @val vector with both X- as well as Y-scroll value */ NK_API void nk_input_scroll(struct nk_context*, struct nk_vec2 val); /* nk_input_char - Copies a single ASCII character into an internal text buffer * This is basically a helper function to quickly push ASCII characters into @@ -746,7 +745,7 @@ NK_API void nk_input_char(struct nk_context*, char); * struct `nk_input` between `nk_input_begin` and `nk_input_end`. * Parameters: * @ctx must point to an previously initialized `nk_context` struct - * @glyph UTF-32 uncode codepoint */ + * @glyph UTF-32 unicode codepoint */ NK_API void nk_input_glyph(struct nk_context*, const nk_glyph); /* nk_input_unicode - Converts a unicode rune into UTF-8 and copies the result * into an internal text buffer. @@ -754,7 +753,7 @@ NK_API void nk_input_glyph(struct nk_context*, const nk_glyph); * struct `nk_input` between `nk_input_begin` and `nk_input_end`. * Parameters: * @ctx must point to an previously initialized `nk_context` struct - * @glyph UTF-32 uncode codepoint */ + * @glyph UTF-32 unicode codepoint */ NK_API void nk_input_unicode(struct nk_context*, nk_rune); /* nk_input_end - End the input mirroring process by resetting mouse grabbing * state to ensure the mouse cursor is not grabbed indefinitely. @@ -872,7 +871,7 @@ NK_API void nk_input_end(struct nk_context*); * nk_free(&ctx); * * The second probably more applicable trick is to only draw if anything changed. - * It is not really useful for applications with continous draw loop but + * It is not really useful for applications with continuous draw loop but * quite useful for desktop applications. To actually get nuklear to only * draw on changes you first have to define `NK_ZERO_COMMAND_MEMORY` and * allocate a memory buffer that will store each unique drawing output. @@ -920,7 +919,7 @@ NK_API void nk_input_end(struct nk_context*); * hardware directly. Therefore it is possible to just define * `NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output. * To access the vertex output you first have to convert all draw commands into - * vertexes by calling `nk_convert` which takes in your prefered vertex format. + * vertexes by calling `nk_convert` which takes in your preferred vertex format. * After successfully converting all draw commands just iterate over and execute all * vertex draw commands: * @@ -959,9 +958,9 @@ NK_API void nk_input_end(struct nk_context*); * ------------------- * nk__begin - Returns the first draw command in the context draw command list to be drawn * nk__next - Increments the draw command iterator to the next command inside the context draw command list - * nk_foreach - Iteratates over each draw command inside the context draw command list + * nk_foreach - Iterates over each draw command inside the context draw command list * - * nk_convert - Converts from the abstract draw commands list into a hardware accessable vertex format + * nk_convert - Converts from the abstract draw commands list into a hardware accessible vertex format * nk__draw_begin - Returns the first vertex command in the context vertex draw list to be executed * nk__draw_next - Increments the vertex command iterator to the next command inside the context vertex command list * nk__draw_end - Returns the end of the vertex draw list @@ -989,7 +988,7 @@ struct nk_convert_config { struct nk_draw_null_texture null; /* handle to texture with a white pixel for shape drawing */ const struct nk_draw_vertex_layout_element *vertex_layout; /* describes the vertex output format and packing */ nk_size vertex_size; /* sizeof one vertex for vertex packing */ - nk_size vertex_alignment; /* vertex alignment: Can be optained by NK_ALIGNOF */ + nk_size vertex_alignment; /* vertex alignment: Can be obtained by NK_ALIGNOF */ }; /* nk__begin - Returns a draw command list iterator to iterate all draw * commands accumulated over one frame. @@ -1012,14 +1011,14 @@ NK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_com #define nk_foreach(c, ctx) for((c) = nk__begin(ctx); (c) != 0; (c) = nk__next(ctx,c)) #ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT /* nk_convert - converts all internal draw command into vertex draw commands and fills - * three buffers with vertexes, vertex draw commands and vertex indicies. The vertex format - * as well as some other configuration values have to be configurated by filling out a + * three buffers with vertexes, vertex draw commands and vertex indices. The vertex format + * as well as some other configuration values have to be configured by filling out a * `nk_convert_config` struct. * Parameters: * @ctx must point to an previously initialized `nk_context` struct at the end of a frame * @cmds must point to a previously initialized buffer to hold converted vertex draw commands - * @vertices must point to a previously initialized buffer to hold all produced verticies - * @elements must point to a previously initialized buffer to hold all procudes vertex indicies + * @vertices must point to a previously initialized buffer to hold all produced vertices + * @elements must point to a previously initialized buffer to hold all produced vertex indices * @config must point to a filled out `nk_config` struct to configure the conversion process * Returns: * returns NK_CONVERT_SUCCESS on success and a enum nk_convert_result error values if not */ @@ -1038,7 +1037,7 @@ NK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, co * Return values: * vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer */ NK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*); -/* nk__draw_next - Increments the the vertex draw command buffer iterator +/* nk__draw_next - Increments the vertex draw command buffer iterator * Parameters: * @cmd must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command * @buf must point to an previously by `nk_convert` filled out vertex draw command buffer @@ -1070,7 +1069,7 @@ NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command* * order. The topmost window thereby is the currently active window. * * To change window position inside the stack occurs either automatically by - * user input by being clicked on or programatically by calling `nk_window_focus`. + * user input by being clicked on or programmatically by calling `nk_window_focus`. * Windows by default are visible unless explicitly being defined with flag * `NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag * `NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling @@ -1082,9 +1081,9 @@ NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command* * functions to start window declarations and `nk_end` at the end. Furthermore it * is recommended to check the return value of `nk_begin_xxx` and only process * widgets inside the window if the value is not 0. Either way you have to call - * `nk_end` at the end of window declarations. Furthmore do not attempt to + * `nk_end` at the end of window declarations. Furthermore, do not attempt to * nest `nk_begin_xxx` calls which will hopefully result in an assert or if not - * in a segmation fault. + * in a segmentation fault. * * if (nk_begin_xxx(...) { * [... widgets ...] @@ -1094,7 +1093,7 @@ NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command* * In the grand concept window and widget declarations need to occur after input * handling and before drawing to screen. Not doing so can result in higher * latency or at worst invalid behavior. Furthermore make sure that `nk_clear` - * is called at the end of the frame. While nuklears default platform backends + * is called at the end of the frame. While nuklear's default platform backends * already call `nk_clear` for you if you write your own backend not calling * `nk_clear` can cause asserts or even worse undefined behavior. * @@ -1135,7 +1134,7 @@ NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command* * Reference * ------------------- * nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed - * nk_begin_titled - extended window start with seperated title and identifier to allow multiple windows with same name but not title + * nk_begin_titled - extended window start with separated title and identifier to allow multiple windows with same name but not title * nk_end - needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup * * nk_window_find - finds and returns the window with give name @@ -1144,7 +1143,7 @@ NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command* * nk_window_get_size - returns the size with width and height of the currently processed window * nk_window_get_width - returns the width of the currently processed window * nk_window_get_height - returns the height of the currently processed window - * nk_window_get_panel - returns the underlying panel which contains all processing state of the currnet window + * nk_window_get_panel - returns the underlying panel which contains all processing state of the current window * nk_window_get_content_region - returns the position and size of the currently visible and non-clipped space inside the currently processed window * nk_window_get_content_region_min - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window * nk_window_get_content_region_max - returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window @@ -1157,7 +1156,7 @@ NK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command* * nk_window_is_hidden - returns if the currently processed window was hidden * nk_window_is_active - same as nk_window_has_focus for some reason * nk_window_is_hovered - returns if the currently processed window is currently being hovered by mouse - * nk_window_is_any_hovered - return if any wndow currently hovered + * nk_window_is_any_hovered - return if any window currently hovered * nk_item_is_any_active - returns if any window or widgets is currently hovered or active * * nk_window_set_bounds - updates position and size of the currently processed window @@ -1187,16 +1186,16 @@ enum nk_panel_flags { /* nk_begin - starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed * Parameters: * @ctx must point to an previously initialized `nk_context` struct - * @title window title and identifier. Needs to be persitent over frames to identify the window + * @title window title and identifier. Needs to be persistent over frames to identify the window * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors * Return values: * returns 1 if the window can be filled up with widgets from this point until `nk_end or 0 otherwise for example if minimized `*/ NK_API int nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags); -/* nk_begin_titled - extended window start with seperated title and identifier to allow multiple windows with same name but not title +/* nk_begin_titled - extended window start with separated title and identifier to allow multiple windows with same name but not title * Parameters: * @ctx must point to an previously initialized `nk_context` struct - * @name window identifier. Needs to be persitent over frames to identify the window + * @name window identifier. Needs to be persistent over frames to identify the window * @title window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set * @bounds initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame * @flags window flags defined in `enum nk_panel_flags` with a number of different window behaviors @@ -1213,7 +1212,7 @@ NK_API void nk_end(struct nk_context *ctx); * @ctx must point to an previously initialized `nk_context` struct * @name window identifier * Return values: - * returns a `nk_window` struct pointing to the idified window or 0 if no window with given name was found */ + * returns a `nk_window` struct pointing to the identified window or 0 if no window with given name was found */ NK_API struct nk_window *nk_window_find(struct nk_context *ctx, const char *name); /* nk_window_get_bounds - returns a rectangle with screen position and size of the currently processed window. * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` @@ -1250,7 +1249,7 @@ NK_API float nk_window_get_width(const struct nk_context*); * Return values: * returns the window height */ NK_API float nk_window_get_height(const struct nk_context*); -/* nk_window_get_panel - returns the underlying panel which contains all processing state of the currnet window. +/* nk_window_get_panel - returns the underlying panel which contains all processing state of the current window. * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` * Parameters: * @ctx must point to an previously initialized `nk_context` struct @@ -1352,20 +1351,23 @@ NK_API int nk_item_is_any_active(struct nk_context*); * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` * Parameters: * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to modify both position and size * @bounds points to a `nk_rect` struct with the new position and size of currently active window */ -NK_API void nk_window_set_bounds(struct nk_context*, struct nk_rect bounds); +NK_API void nk_window_set_bounds(struct nk_context*, const char *name, struct nk_rect bounds); /* nk_window_set_position - updates position of the currently processed window * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` * Parameters: * @ctx must point to an previously initialized `nk_context` struct + * @name of the window to modify position of * @pos points to a `nk_vec2` struct with the new position of currently active window */ -NK_API void nk_window_set_position(struct nk_context*, struct nk_vec2 pos); +NK_API void nk_window_set_position(struct nk_context*, const char *name, struct nk_vec2 pos); /* nk_window_set_size - updates size of the currently processed window * IMPORTANT: only call this function between calls `nk_begin_xxx` and `nk_end` * Parameters: * @ctx must point to an previously initialized `nk_context` struct - * @bounds points to a `nk_vec2` struct with the new size of currently active window */ -NK_API void nk_window_set_size(struct nk_context*, struct nk_vec2); + * @name of the window to modify size of + * @size points to a `nk_vec2` struct with the new size of currently active window */ +NK_API void nk_window_set_size(struct nk_context*, const char *name, struct nk_vec2); /* nk_window_set_focus - sets the window with given name as active * Parameters: * @ctx must point to an previously initialized `nk_context` struct @@ -1386,7 +1388,7 @@ NK_API void nk_window_collapse(struct nk_context*, const char *name, enum nk_col * @ctx must point to an previously initialized `nk_context` struct * @name of the window to be either collapse or maximize * @state the window should be put into - * @condition that has to be true to actually commit the collsage state change */ + * @condition that has to be true to actually commit the collapse state change */ NK_API void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond); /* nk_window_show - updates visibility state of a window with given name * Parameters: @@ -1410,14 +1412,14 @@ NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show * While in this particular implementation there are five different APIs for layouting * each with different trade offs between control and ease of use. * - * All layouting methodes in this library are based around the concept of a row. + * All layouting methods in this library are based around the concept of a row. * A row has a height the window content grows by and a number of columns and each * layouting method specifies how each widget is placed inside the row. * After a row has been allocated by calling a layouting functions and then * filled with widgets will advance an internal pointer over the allocated row. * - * To acually define a layout you just call the appropriate layouting function - * and each subsequnetial widget call will place the widget as specified. Important + * To actually define a layout you just call the appropriate layouting function + * and each subsequent widget call will place the widget as specified. Important * here is that if you define more widgets then columns defined inside the layout * functions it will allocate the next row without you having to make another layouting * call. @@ -1576,8 +1578,8 @@ NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show * one is the static widget size specifier with fixed widget pixel width. They do * not grow if the row grows and will always stay the same. The second size * specifier is nk_layout_row_template_push_variable which defines a - * minumum widget size but it also can grow if more space is available not taken - * by other widgets. Finally there are dynamic widgets which are completly flexible + * minimum widget size but it also can grow if more space is available not taken + * by other widgets. Finally there are dynamic widgets which are completely flexible * and unlike variable widgets can even shrink to zero if not enough space * is provided. * @@ -1604,9 +1606,9 @@ NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show * Finally the most flexible API directly allows you to place widgets inside the * window. The space layout API is an immediate mode API which does not support * row auto repeat and directly sets position and size of a widget. Position - * and size hereby can be either specified as ratio of alloated space or + * and size hereby can be either specified as ratio of allocated space or * allocated space local position and pixel size. Since this API is quite - * powerfull there are a number of utility functions to get the available space + * powerful there are a number of utility functions to get the available space * and convert between local allocated space and screen space. * * if (nk_begin_xxx(...) { @@ -1635,7 +1637,7 @@ NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show * nk_layout_widget_bounds - calculates current width a static layout row can fit inside a window * nk_layout_ratio_from_pixel - utility functions to calculate window ratio from pixel size * - * nk_layout_row_dynamic - current layout is divided into n same sized gowing columns + * nk_layout_row_dynamic - current layout is divided into n same sized growing columns * nk_layout_row_static - current layout is divided into n same fixed sized columns * nk_layout_row_begin - starts a new row with given height and number of columns * nk_layout_row_push - pushes another column with given size or window ratio @@ -1649,17 +1651,17 @@ NK_API void nk_window_show_if(struct nk_context*, const char *name, enum nk_show * nk_layout_row_template_end - marks the end of the row template * * nk_layout_space_begin - begins a new layouting space that allows to specify each widgets position and size - * nk_layout_space_push - pushes position and size of the next widget in own coordiante space either as pixel or ratio + * nk_layout_space_push - pushes position and size of the next widget in own coordinate space either as pixel or ratio * nk_layout_space_end - marks the end of the layouting space * * nk_layout_space_bounds - callable after nk_layout_space_begin and returns total space allocated - * nk_layout_space_to_screen - convertes vector from nk_layout_space coordiant space into screen space - * nk_layout_space_to_local - convertes vector from screem space into nk_layout_space coordinates - * nk_layout_space_rect_to_screen - convertes rectangle from nk_layout_space coordiant space into screen space - * nk_layout_space_rect_to_local - convertes rectangle from screem space into nk_layout_space coordinates + * nk_layout_space_to_screen - converts vector from nk_layout_space coordinate space into screen space + * nk_layout_space_to_local - converts vector from screen space into nk_layout_space coordinates + * nk_layout_space_rect_to_screen - converts rectangle from nk_layout_space coordinate space into screen space + * nk_layout_space_rect_to_local - converts rectangle from screen space into nk_layout_space coordinates */ /* nk_layout_set_min_row_height - sets the currently used minimum row height. - * IMPORTANT: The passed height needs to include both your prefered row height + * IMPORTANT: The passed height needs to include both your preferred row height * as well as padding. No internal padding is added. * Parameters: * @ctx must point to an previously initialized `nk_context` struct after call `nk_begin_xxx` @@ -1736,7 +1738,7 @@ NK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_w /* nk_layout_row_template_push_static - adds a static column that does not grow and will always have the same size * Parameters: * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_row_template_begin` - * @width holds the absolulte pixel width value the next column must be */ + * @width holds the absolute pixel width value the next column must be */ NK_API void nk_layout_row_template_push_static(struct nk_context*, float width); /* nk_layout_row_template_end - marks the end of the row template * Parameters: @@ -1749,7 +1751,7 @@ NK_API void nk_layout_row_template_end(struct nk_context*); * @row_height holds height of each widget in row or zero for auto layouting * @widget_count number of widgets inside row */ NK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count); -/* nk_layout_space_push - pushes position and size of the next widget in own coordiante space either as pixel or ratio +/* nk_layout_space_push - pushes position and size of the next widget in own coordinate space either as pixel or ratio * Parameters: * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` * @bounds position and size in laoyut space local coordinates */ @@ -1762,22 +1764,22 @@ NK_API void nk_layout_space_end(struct nk_context*); * Parameters: * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` */ NK_API struct nk_rect nk_layout_space_bounds(struct nk_context*); -/* nk_layout_space_to_screen - convertes vector from nk_layout_space coordiant space into screen space +/* nk_layout_space_to_screen - converts vector from nk_layout_space coordinate space into screen space * Parameters: * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` * @vec position to convert from layout space into screen coordinate space */ NK_API struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2); -/* nk_layout_space_to_screen - convertes vector from layout space into screen space +/* nk_layout_space_to_screen - converts vector from layout space into screen space * Parameters: * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` * @vec position to convert from screen space into layout coordinate space */ NK_API struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2); -/* nk_layout_space_rect_to_screen - convertes rectangle from screen space into layout space +/* nk_layout_space_rect_to_screen - converts rectangle from screen space into layout space * Parameters: * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` * @bounds rectangle to convert from layout space into screen space */ NK_API struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect); -/* nk_layout_space_rect_to_local - convertes rectangle from layout space into screen space +/* nk_layout_space_rect_to_local - converts rectangle from layout space into screen space * Parameters: * @ctx must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin` * @bounds rectangle to convert from screen space into layout space */ @@ -2104,6 +2106,9 @@ NK_API void nk_contextual_end(struct nk_context*); * * ============================================================================= */ NK_API void nk_tooltip(struct nk_context*, const char*); +#ifdef NK_INCLUDE_STANDARD_VARARGS +NK_API void nk_tooltipf(struct nk_context*, const char*, ...); +#endif NK_API int nk_tooltip_begin(struct nk_context*, float width); NK_API void nk_tooltip_end(struct nk_context*); /* ============================================================================= @@ -2321,7 +2326,7 @@ NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune different ways to use the font atlas. The first two will use your font handling scheme and only requires essential data to run nuklear. The next slightly more advanced features is font handling with vertex buffer output. - Finally the most complex API wise is using nuklears font baking API. + Finally the most complex API wise is using nuklear's font baking API. 1.) Using your own implementation without vertex buffer output -------------------------------------------------------------- @@ -2394,7 +2399,7 @@ NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune ------------------------------------ The final approach if you do not have a font handling functionality or don't want to use it in this library is by using the optional font baker. - The font baker API's can be used to create a font plus font atlas texture + The font baker APIs can be used to create a font plus font atlas texture and can be used with or without the vertex buffer output. It still uses the `nk_user_font` struct and the two different approaches @@ -2409,7 +2414,7 @@ NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune memory is temporary and therefore can be freed directly after the baking process is over or permanent you can call `nk_font_atlas_init`. - After successfull intializing the font baker you can add Truetype(.ttf) fonts from + After successfully initializing the font baker you can add Truetype(.ttf) fonts from different sources like memory or from file by calling one of the `nk_font_atlas_add_xxx`. functions. Adding font will permanently store each font, font config and ttf memory block(!) inside the font atlas and allows to reuse the font atlas. If you don't want to reuse @@ -2417,7 +2422,7 @@ NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune `nk_font_atlas_cleanup` after the baking process is over (after calling nk_font_atlas_end). As soon as you added all fonts you wanted you can now start the baking process - for every selected glyphes to image by calling `nk_font_atlas_bake`. + for every selected glyph to image by calling `nk_font_atlas_bake`. The baking process returns image memory, width and height which can be used to either create your own image object or upload it to any graphics library. No matter which case you finally have to call `nk_font_atlas_end` which @@ -2451,7 +2456,7 @@ NK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune I would suggest reading some of my examples `example/` to get a grip on how to use the font atlas. There are a number of details I left out. For example how to merge fonts, configure a font with `nk_font_config` to use other languages, - use another texture coodinate format and a lot more: + use another texture coordinate format and a lot more: struct nk_font_config cfg = nk_font_config(font_pixel_height); cfg.merge_mode = nk_false or nk_true; @@ -2466,7 +2471,7 @@ typedef void(*nk_query_font_glyph_f)(nk_handle handle, float font_height, struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint); -#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT +#if defined(NK_INCLUDE_VERTEX_BUFFER_OUTPUT) || defined(NK_INCLUDE_SOFTWARE_FONT) struct nk_user_font_glyph { struct nk_vec2 uv[2]; /* texture coordinates */ @@ -2500,6 +2505,7 @@ enum nk_font_coord_type { NK_COORD_PIXEL /* texture coordinates inside font glyphs are in absolute pixel */ }; +struct nk_font; struct nk_baked_font { float height; /* height of the font */ @@ -2545,6 +2551,8 @@ struct nk_font_config { /* font to setup in the baking process: NOTE: not needed for font atlas */ nk_rune fallback_glyph; /* fallback glyph to use if a given rune is not found */ + struct nk_font_config *n; + struct nk_font_config *p; }; struct nk_font_glyph { @@ -2786,7 +2794,7 @@ NK_API int nk_str_len_char(struct nk_str*); * First of is the most basic way of just providing a simple char array with * string length. This method is probably the easiest way of handling simple * user text input. Main upside is complete control over memory while the biggest - * downside in comparsion with the other two approaches is missing undo/redo. + * downside in comparison with the other two approaches is missing undo/redo. * * For UIs that require undo/redo the second way was created. It is based on * a fixed size nk_text_edit struct, which has an internal undo/redo stack. @@ -2933,8 +2941,8 @@ NK_API void nk_textedit_redo(struct nk_text_edit*); but also returns the state of the widget space. If your widget is not seen and does not have to be updated it is '0' and you can just return. If it only has to be drawn the state will be `NK_WIDGET_ROM` otherwise you can do both - update and draw your widget. The reason for seperating is to only draw and - update what is actually neccessary which is crucial for performance. + update and draw your widget. The reason for separating is to only draw and + update what is actually necessary which is crucial for performance. */ enum nk_command_type { NK_COMMAND_NOP, @@ -4241,7 +4249,7 @@ template struct nk_alignof{struct Big {T x; char c;}; enum { #define NK_ALIGNOF(t) ((char*)(&((struct {char c; t _h;}*)0)->_h) - (char*)0) #endif -#endif /* NK_H_ */ +#endif /* NK_NUKLEAR_H_ */ /* * ============================================================== * @@ -4371,7 +4379,7 @@ NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255}; ---- For square root nuklear uses the famous fast inverse square root: https://en.wikipedia.org/wiki/Fast_inverse_square_root with - slightly tweaked magic constant. While on todays hardware it is + slightly tweaked magic constant. While on today's hardware it is probably not faster it is still fast and accurate enough for nuklear's use cases. IMPORTANT: this requires float format IEEE 754 @@ -4382,7 +4390,7 @@ NK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255}; approximate exactly that range is that nuklear only needs sine and cosine to generate circles which only requires that exact range. In addition I used Remez instead of Taylor for additional precision: - www.lolengine.net/blog/2011/12/21/better-function-approximatations. + www.lolengine.net/blog/2011/12/21/better-function-approximations. The tool I used to generate constants for both sine and cosine (it can actually approximate a lot more functions) can be @@ -4889,7 +4897,7 @@ nk_strmatch_fuzzy_text(const char *str, int str_len, const char *pattern, int *out_score) { /* Returns true if each character in pattern is found sequentially within str - * if found then outScore is also set. Score value has no intrinsic meaning. + * if found then out_score is also set. Score value has no intrinsic meaning. * Range varies with pattern. Can only compare scores with same search pattern. */ /* ------- scores --------- */ @@ -5067,7 +5075,7 @@ nk_iceilf(float x) { if (x >= 0) { int i = (int)x; - return i; + return (x > i) ? i+1: i; } else { int t = (int)x; float r = x - (float)t; @@ -5638,7 +5646,7 @@ nk_file_load(const char* path, nk_size* siz, struct nk_allocator *alloc) fclose(fd); return 0; } - *siz = (nk_size)fread(buf, *siz, 1, fd); + *siz = (nk_size)fread(buf, 1,*siz, fd); fclose(fd); return buf; } @@ -7963,10 +7971,16 @@ nk_draw_list_push_image(struct nk_draw_list *list, nk_handle texture) nk_draw_list_push_command(list, nk_null_rect, texture); } else { struct nk_draw_command *prev = nk_draw_list_command_last(list); - if (prev->elem_count == 0) + if (prev->elem_count == 0) { prev->texture = texture; - else if (prev->texture.id != texture.id) - nk_draw_list_push_command(list, prev->clip_rect, texture); + #ifdef NK_INCLUDE_COMMAND_USERDATA + prev->userdata = list->userdata; + #endif + } else if (prev->texture.id != texture.id + #ifdef NK_INCLUDE_COMMAND_USERDATA + || prev->userdata.id != list->userdata.id + #endif + ) nk_draw_list_push_command(list, prev->clip_rect, texture); } } @@ -8586,12 +8600,42 @@ nk_draw_list_path_arc_to(struct nk_draw_list *list, struct nk_vec2 center, NK_ASSERT(list); if (!list) return; if (radius == 0.0f) return; - for (i = 0; i <= segments; ++i) { - const float a = a_min + ((float)i / ((float)segments) * (a_max - a_min)); - const float x = center.x + (float)NK_COS(a) * radius; - const float y = center.y + (float)NK_SIN(a) * radius; + + /* This algorithm for arc drawing relies on these two trigonometric identities[1]: + sin(a + b) = sin(a) * cos(b) + cos(a) * sin(b) + cos(a + b) = cos(a) * cos(b) - sin(a) * sin(b) + + Two coordinates (x, y) of a point on a circle centered on + the origin can be written in polar form as: + x = r * cos(a) + y = r * sin(a) + where r is the radius of the circle, + a is the angle between (x, y) and the origin. + + This allows us to rotate the coordinates around the + origin by an angle b using the following transformation: + x' = r * cos(a + b) = x * cos(b) - y * sin(b) + y' = r * sin(a + b) = y * cos(b) + x * sin(b) + + [1] https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Angle_sum_and_difference_identities + */ + {const float d_angle = (a_max - a_min) / (float)segments; + const float sin_d = (float)NK_SIN(d_angle); + const float cos_d = (float)NK_COS(d_angle); + + float cx = (float)NK_COS(a_min) * radius; + float cy = (float)NK_SIN(a_min) * radius; + for(i = 0; i <= segments; ++i) { + float new_cx, new_cy; + const float x = center.x + cx; + const float y = center.y + cy; nk_draw_list_path_line_to(list, nk_vec2(x, y)); - } + + new_cx = cx * cos_d - cy * sin_d; + new_cy = cy * cos_d + cx * sin_d; + cx = new_cx; + cy = new_cy; + }} } NK_API void @@ -11270,7 +11314,7 @@ nk_font_baker_memory(nk_size *temp, int *glyph_count, { int range_count = 0; int total_range_count = 0; - struct nk_font_config *iter; + struct nk_font_config *iter, *i; NK_ASSERT(config_list); NK_ASSERT(glyph_count); @@ -11279,16 +11323,15 @@ nk_font_baker_memory(nk_size *temp, int *glyph_count, *glyph_count = 0; return; } - *glyph_count = 0; - if (!config_list->range) - config_list->range = nk_font_default_glyph_ranges(); for (iter = config_list; iter; iter = iter->next) { - range_count = nk_range_count(iter->range); - total_range_count += range_count; - *glyph_count += nk_range_glyph_count(iter->range, range_count); + i = iter; + do {if (!i->range) iter->range = nk_font_default_glyph_ranges(); + range_count = nk_range_count(i->range); + total_range_count += range_count; + *glyph_count += nk_range_glyph_count(i->range, range_count); + } while ((i = i->n) != iter); } - *temp = (nk_size)*glyph_count * sizeof(struct nk_rp_rect); *temp += (nk_size)total_range_count * sizeof(struct nk_tt_pack_range); *temp += (nk_size)*glyph_count * sizeof(struct nk_tt_packedchar); @@ -11320,7 +11363,7 @@ nk_font_bake_pack(struct nk_font_baker *baker, struct nk_allocator *alloc) { NK_STORAGE const nk_size max_height = 1024 * 32; - const struct nk_font_config *config_iter; + const struct nk_font_config *config_iter, *it; int total_glyph_count = 0; int total_range_count = 0; int range_count = 0; @@ -11335,18 +11378,19 @@ nk_font_bake_pack(struct nk_font_baker *baker, if (!image_memory || !width || !height || !config_list || !count) return nk_false; for (config_iter = config_list; config_iter; config_iter = config_iter->next) { - range_count = nk_range_count(config_iter->range); - total_range_count += range_count; - total_glyph_count += nk_range_glyph_count(config_iter->range, range_count); + it = config_iter; + do {range_count = nk_range_count(it->range); + total_range_count += range_count; + total_glyph_count += nk_range_glyph_count(it->range, range_count); + } while ((it = it->n) != config_iter); } - /* setup font baker from temporary memory */ for (config_iter = config_list; config_iter; config_iter = config_iter->next) { - const struct nk_font_config *cfg = config_iter; - if (!nk_tt_InitFont(&baker->build[i++].info, (const unsigned char*)cfg->ttf_blob, 0)) + it = config_iter; + do {if (!nk_tt_InitFont(&baker->build[i++].info, (const unsigned char*)it->ttf_blob, 0)) return nk_false; + } while ((it = it->n) != config_iter); } - *height = 0; *width = (total_glyph_count > 1000) ? 1024 : 512; nk_tt_PackBegin(&baker->spc, 0, (int)*width, (int)max_height, 0, 1, alloc); @@ -11375,47 +11419,48 @@ nk_font_bake_pack(struct nk_font_baker *baker, /* first font pass: pack all glyphs */ for (input_i = 0, config_iter = config_list; input_i < count && config_iter; - input_i++, config_iter = config_iter->next) - { - int n = 0; - int glyph_count; - const nk_rune *in_range; - const struct nk_font_config *cfg = config_iter; - struct nk_font_bake_data *tmp = &baker->build[input_i]; + config_iter = config_iter->next) { + it = config_iter; + do {int n = 0; + int glyph_count; + const nk_rune *in_range; + const struct nk_font_config *cfg = it; + struct nk_font_bake_data *tmp = &baker->build[input_i++]; - /* count glyphs + ranges in current font */ - glyph_count = 0; range_count = 0; - for (in_range = cfg->range; in_range[0] && in_range[1]; in_range += 2) { - glyph_count += (int)(in_range[1] - in_range[0]) + 1; - range_count++; - } + /* count glyphs + ranges in current font */ + glyph_count = 0; range_count = 0; + for (in_range = cfg->range; in_range[0] && in_range[1]; in_range += 2) { + glyph_count += (int)(in_range[1] - in_range[0]) + 1; + range_count++; + } - /* setup ranges */ - tmp->ranges = baker->ranges + range_n; - tmp->range_count = (nk_rune)range_count; - range_n += range_count; - for (i = 0; i < range_count; ++i) { - in_range = &cfg->range[i * 2]; - tmp->ranges[i].font_size = cfg->size; - tmp->ranges[i].first_unicode_codepoint_in_range = (int)in_range[0]; - tmp->ranges[i].num_chars = (int)(in_range[1]- in_range[0]) + 1; - tmp->ranges[i].chardata_for_range = baker->packed_chars + char_n; - char_n += tmp->ranges[i].num_chars; - } + /* setup ranges */ + tmp->ranges = baker->ranges + range_n; + tmp->range_count = (nk_rune)range_count; + range_n += range_count; + for (i = 0; i < range_count; ++i) { + in_range = &cfg->range[i * 2]; + tmp->ranges[i].font_size = cfg->size; + tmp->ranges[i].first_unicode_codepoint_in_range = (int)in_range[0]; + tmp->ranges[i].num_chars = (int)(in_range[1]- in_range[0]) + 1; + tmp->ranges[i].chardata_for_range = baker->packed_chars + char_n; + char_n += tmp->ranges[i].num_chars; + } - /* pack */ - tmp->rects = baker->rects + rect_n; - rect_n += glyph_count; - nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); - n = nk_tt_PackFontRangesGatherRects(&baker->spc, &tmp->info, - tmp->ranges, (int)tmp->range_count, tmp->rects); - nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, tmp->rects, (int)n); + /* pack */ + tmp->rects = baker->rects + rect_n; + rect_n += glyph_count; + nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); + n = nk_tt_PackFontRangesGatherRects(&baker->spc, &tmp->info, + tmp->ranges, (int)tmp->range_count, tmp->rects); + nk_rp_pack_rects((struct nk_rp_context*)baker->spc.pack_info, tmp->rects, (int)n); - /* texture height */ - for (i = 0; i < n; ++i) { - if (tmp->rects[i].was_packed) - *height = NK_MAX(*height, tmp->rects[i].y + tmp->rects[i].h); - } + /* texture height */ + for (i = 0; i < n; ++i) { + if (tmp->rects[i].was_packed) + *height = NK_MAX(*height, tmp->rects[i].y + tmp->rects[i].h); + } + } while ((it = it->n) != config_iter); } NK_ASSERT(rect_n == total_glyph_count); NK_ASSERT(char_n == total_glyph_count); @@ -11434,6 +11479,7 @@ nk_font_bake(struct nk_font_baker *baker, void *image_memory, int width, int hei int input_i = 0; nk_rune glyph_n = 0; const struct nk_font_config *config_iter; + const struct nk_font_config *it; NK_ASSERT(image_memory); NK_ASSERT(width); @@ -11451,88 +11497,88 @@ nk_font_bake(struct nk_font_baker *baker, void *image_memory, int width, int hei baker->spc.pixels = (unsigned char*)image_memory; baker->spc.height = (int)height; for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter; - ++input_i, config_iter = config_iter->next) - { - const struct nk_font_config *cfg = config_iter; - struct nk_font_bake_data *tmp = &baker->build[input_i]; - nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); - nk_tt_PackFontRangesRenderIntoRects(&baker->spc, &tmp->info, tmp->ranges, - (int)tmp->range_count, tmp->rects, &baker->alloc); - } - nk_tt_PackEnd(&baker->spc, &baker->alloc); + config_iter = config_iter->next) { + it = config_iter; + do {const struct nk_font_config *cfg = it; + struct nk_font_bake_data *tmp = &baker->build[input_i++]; + nk_tt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v); + nk_tt_PackFontRangesRenderIntoRects(&baker->spc, &tmp->info, tmp->ranges, + (int)tmp->range_count, tmp->rects, &baker->alloc); + } while ((it = it->n) != config_iter); + } nk_tt_PackEnd(&baker->spc, &baker->alloc); /* third pass: setup font and glyphs */ for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter; - ++input_i, config_iter = config_iter->next) - { - nk_size i = 0; - int char_idx = 0; - nk_rune glyph_count = 0; - const struct nk_font_config *cfg = config_iter; - struct nk_font_bake_data *tmp = &baker->build[input_i]; - struct nk_baked_font *dst_font = cfg->font; + config_iter = config_iter->next) { + it = config_iter; + do {nk_size i = 0; + int char_idx = 0; + nk_rune glyph_count = 0; + const struct nk_font_config *cfg = it; + struct nk_font_bake_data *tmp = &baker->build[input_i++]; + struct nk_baked_font *dst_font = cfg->font; - float font_scale = nk_tt_ScaleForPixelHeight(&tmp->info, cfg->size); - int unscaled_ascent, unscaled_descent, unscaled_line_gap; - nk_tt_GetFontVMetrics(&tmp->info, &unscaled_ascent, &unscaled_descent, - &unscaled_line_gap); + float font_scale = nk_tt_ScaleForPixelHeight(&tmp->info, cfg->size); + int unscaled_ascent, unscaled_descent, unscaled_line_gap; + nk_tt_GetFontVMetrics(&tmp->info, &unscaled_ascent, &unscaled_descent, + &unscaled_line_gap); - /* fill baked font */ - if (!cfg->merge_mode) { - dst_font->ranges = cfg->range; - dst_font->height = cfg->size; - dst_font->ascent = ((float)unscaled_ascent * font_scale); - dst_font->descent = ((float)unscaled_descent * font_scale); - dst_font->glyph_offset = glyph_n; - } - - /* fill own baked font glyph array */ - for (i = 0; i < tmp->range_count; ++i) - { - struct nk_tt_pack_range *range = &tmp->ranges[i]; - for (char_idx = 0; char_idx < range->num_chars; char_idx++) - { - nk_rune codepoint = 0; - float dummy_x = 0, dummy_y = 0; - struct nk_tt_aligned_quad q; - struct nk_font_glyph *glyph; - - /* query glyph bounds from stb_truetype */ - const struct nk_tt_packedchar *pc = &range->chardata_for_range[char_idx]; - if (!pc->x0 && !pc->x1 && !pc->y0 && !pc->y1) continue; - codepoint = (nk_rune)(range->first_unicode_codepoint_in_range + char_idx); - nk_tt_GetPackedQuad(range->chardata_for_range, (int)width, - (int)height, char_idx, &dummy_x, &dummy_y, &q, 0); - - /* fill own glyph type with data */ - glyph = &glyphs[dst_font->glyph_offset + (unsigned int)glyph_count]; - glyph->codepoint = codepoint; - glyph->x0 = q.x0; glyph->y0 = q.y0; - glyph->x1 = q.x1; glyph->y1 = q.y1; - glyph->y0 += (dst_font->ascent + 0.5f); - glyph->y1 += (dst_font->ascent + 0.5f); - glyph->w = glyph->x1 - glyph->x0 + 0.5f; - glyph->h = glyph->y1 - glyph->y0; - - if (cfg->coord_type == NK_COORD_PIXEL) { - glyph->u0 = q.s0 * (float)width; - glyph->v0 = q.t0 * (float)height; - glyph->u1 = q.s1 * (float)width; - glyph->v1 = q.t1 * (float)height; - } else { - glyph->u0 = q.s0; - glyph->v0 = q.t0; - glyph->u1 = q.s1; - glyph->v1 = q.t1; - } - glyph->xadvance = (pc->xadvance + cfg->spacing.x); - if (cfg->pixel_snap) - glyph->xadvance = (float)(int)(glyph->xadvance + 0.5f); - glyph_count++; + /* fill baked font */ + if (!cfg->merge_mode) { + dst_font->ranges = cfg->range; + dst_font->height = cfg->size; + dst_font->ascent = ((float)unscaled_ascent * font_scale); + dst_font->descent = ((float)unscaled_descent * font_scale); + dst_font->glyph_offset = glyph_n; } - } - dst_font->glyph_count = glyph_count; - glyph_n += dst_font->glyph_count; + + /* fill own baked font glyph array */ + for (i = 0; i < tmp->range_count; ++i) { + struct nk_tt_pack_range *range = &tmp->ranges[i]; + for (char_idx = 0; char_idx < range->num_chars; char_idx++) + { + nk_rune codepoint = 0; + float dummy_x = 0, dummy_y = 0; + struct nk_tt_aligned_quad q; + struct nk_font_glyph *glyph; + + /* query glyph bounds from stb_truetype */ + const struct nk_tt_packedchar *pc = &range->chardata_for_range[char_idx]; + if (!pc->x0 && !pc->x1 && !pc->y0 && !pc->y1) continue; + codepoint = (nk_rune)(range->first_unicode_codepoint_in_range + char_idx); + nk_tt_GetPackedQuad(range->chardata_for_range, (int)width, + (int)height, char_idx, &dummy_x, &dummy_y, &q, 0); + + /* fill own glyph type with data */ + glyph = &glyphs[dst_font->glyph_offset + dst_font->glyph_count + (unsigned int)glyph_count]; + glyph->codepoint = codepoint; + glyph->x0 = q.x0; glyph->y0 = q.y0; + glyph->x1 = q.x1; glyph->y1 = q.y1; + glyph->y0 += (dst_font->ascent + 0.5f); + glyph->y1 += (dst_font->ascent + 0.5f); + glyph->w = glyph->x1 - glyph->x0 + 0.5f; + glyph->h = glyph->y1 - glyph->y0; + + if (cfg->coord_type == NK_COORD_PIXEL) { + glyph->u0 = q.s0 * (float)width; + glyph->v0 = q.t0 * (float)height; + glyph->u1 = q.s1 * (float)width; + glyph->v1 = q.t1 * (float)height; + } else { + glyph->u0 = q.s0; + glyph->v0 = q.t0; + glyph->u1 = q.s1; + glyph->v1 = q.t1; + } + glyph->xadvance = (pc->xadvance + cfg->spacing.x); + if (cfg->pixel_snap) + glyph->xadvance = (float)(int)(glyph->xadvance + 0.5f); + glyph_count++; + } + } + dst_font->glyph_count += glyph_count; + glyph_n += glyph_count; + } while ((it = it->n) != config_iter); } } @@ -11659,6 +11705,7 @@ nk_font_find_glyph(struct nk_font *font, nk_rune unicode) int count; int total_glyphs = 0; const struct nk_font_glyph *glyph = 0; + const struct nk_font_config *iter = 0; NK_ASSERT(font); NK_ASSERT(font->glyphs); @@ -11666,15 +11713,17 @@ nk_font_find_glyph(struct nk_font *font, nk_rune unicode) if (!font || !font->glyphs) return 0; glyph = font->fallback; - count = nk_range_count(font->info.ranges); - for (i = 0; i < count; ++i) { - nk_rune f = font->info.ranges[(i*2)+0]; - nk_rune t = font->info.ranges[(i*2)+1]; - int diff = (int)((t - f) + 1); - if (unicode >= f && unicode <= t) - return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))]; - total_glyphs += diff; - } + iter = font->config; + do {count = nk_range_count(iter->range); + for (i = 0; i < count; ++i) { + nk_rune f = iter->range[(i*2)+0]; + nk_rune t = iter->range[(i*2)+1]; + int diff = (int)((t - f) + 1); + if (unicode >= f && unicode <= t) + return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))]; + total_glyphs += diff; + } + } while ((iter = iter->n) != font->config); return glyph; } @@ -12026,6 +12075,7 @@ nk_font_config(float pixel_height) cfg.merge_mode = 0; cfg.fallback_glyph = '?'; cfg.font = 0; + cfg.n = 0; return cfg; } @@ -12109,43 +12159,57 @@ nk_font_atlas_add(struct nk_font_atlas *atlas, const struct nk_font_config *conf !atlas->temporary.alloc || !atlas->temporary.free) return 0; - /* allocate and insert font config into list */ + /* allocate font config */ cfg = (struct nk_font_config*) atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font_config)); NK_MEMCPY(cfg, config, sizeof(*config)); - if (!atlas->config) { - atlas->config = cfg; - cfg->next = 0; - } else { - cfg->next = atlas->config; - atlas->config = cfg; - } + cfg->n = cfg; + cfg->p = cfg; - /* allocate new font */ if (!config->merge_mode) { + /* insert font config into list */ + if (!atlas->config) { + atlas->config = cfg; + cfg->next = 0; + } else { + struct nk_font_config *i = atlas->config; + while (i->next) i = i->next; + i->next = cfg; + cfg->next = 0; + } + /* allocate new font */ font = (struct nk_font*) atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font)); NK_ASSERT(font); + nk_zero(font, sizeof(*font)); if (!font) return 0; font->config = cfg; - } else { - NK_ASSERT(atlas->font_num); - font = atlas->fonts; - font->config = cfg; - } - /* insert font into list */ - if (!config->merge_mode) { + /* insert font into list */ if (!atlas->fonts) { atlas->fonts = font; font->next = 0; } else { - font->next = atlas->fonts; - atlas->fonts = font; + struct nk_font *i = atlas->fonts; + while (i->next) i = i->next; + i->next = font; + font->next = 0; } cfg->font = &font->info; - } + } else { + /* extend previously added font */ + struct nk_font *f = 0; + struct nk_font_config *c = 0; + NK_ASSERT(atlas->font_num); + f = atlas->fonts; + c = f->config; + cfg->font = &f->info; + cfg->n = c; + cfg->p = c->p; + c->p->n = cfg; + c->p = cfg; + } /* create own copy of .TTF font blob */ if (!config->ttf_data_owned_by_atlas) { cfg->ttf_blob = atlas->permanent.alloc(atlas->permanent.userdata,0, cfg->ttf_size); @@ -12464,16 +12528,18 @@ nk_font_atlas_cleanup(struct nk_font_atlas *atlas) NK_ASSERT(atlas->temporary.free); NK_ASSERT(atlas->permanent.alloc); NK_ASSERT(atlas->permanent.free); - if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return; if (atlas->config) { - struct nk_font_config *iter, *next; - for (iter = atlas->config; iter; iter = next) { - next = iter->next; + struct nk_font_config *iter; + for (iter = atlas->config; iter; iter = iter->next) { + struct nk_font_config *i; + for (i = iter->n; i != iter; i = i->n) { + atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob); + i->ttf_blob = 0; + } atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob); - atlas->permanent.free(atlas->permanent.userdata, iter); + iter->ttf_blob = 0; } - atlas->config = 0; } } @@ -12487,7 +12553,23 @@ nk_font_atlas_clear(struct nk_font_atlas *atlas) NK_ASSERT(atlas->permanent.free); if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return; - nk_font_atlas_cleanup(atlas); + if (atlas->config) { + struct nk_font_config *iter, *next; + for (iter = atlas->config; iter; iter = next) { + struct nk_font_config *i, *n; + for (i = iter->n; i != iter; i = n) { + n = i->n; + if (i->ttf_blob) + atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob); + atlas->permanent.free(atlas->permanent.userdata, i); + } + next = iter->next; + if (i->ttf_blob) + atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob); + atlas->permanent.free(atlas->permanent.userdata, iter); + } + atlas->config = 0; + } if (atlas->fonts) { struct nk_font *iter, *next; for (iter = atlas->fonts; iter; iter = next) { @@ -14913,7 +14995,7 @@ nk_draw_progress(struct nk_command_buffer *out, nk_flags state, } else nk_draw_image(out, *bounds, &background->data.image, nk_white); /* draw cursor */ - if (background->type == NK_STYLE_ITEM_COLOR) { + if (cursor->type == NK_STYLE_ITEM_COLOR) { nk_fill_rect(out, *scursor, style->rounding, cursor->data.color); nk_stroke_rect(out, *scursor, style->rounding, style->border, style->border_color); } else nk_draw_image(out, *scursor, &cursor->data.image, nk_white); @@ -15344,7 +15426,7 @@ nk_edit_draw_text(struct nk_command_buffer *out, while ((text_len < byte_len) && glyph_len) { if (unicode == '\n') { - /* new line sepeator so draw previous line */ + /* new line separator so draw previous line */ struct nk_rect label; label.y = pos_y + line_offset; label.h = row_height; @@ -16084,11 +16166,11 @@ nk_do_property(nk_flags *ws, num_len = nk_strlen(string); break; case NK_PROPERTY_FLOAT: - nk_dtoa(string, (double)variant->value.f); + NK_DTOA(string, (double)variant->value.f); num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); break; case NK_PROPERTY_DOUBLE: - nk_dtoa(string, variant->value.d); + NK_DTOA(string, variant->value.d); num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); break; } @@ -17335,18 +17417,22 @@ nk_clear(struct nk_context *ctx) /* garbage collector */ iter = ctx->begin; while (iter) { - /* make sure minimized windows do not get removed */ + /* make sure valid minimized windows do not get removed */ if ((iter->flags & NK_WINDOW_MINIMIZED) && - !(iter->flags & NK_WINDOW_CLOSED)) { + !(iter->flags & NK_WINDOW_CLOSED) && + iter->seq == ctx->seq) { iter = iter->next; continue; } /* remove hotness from hidden or closed windows*/ if (((iter->flags & NK_WINDOW_HIDDEN) || (iter->flags & NK_WINDOW_CLOSED)) && - iter == ctx->active) - ctx->active = iter->next; - + iter == ctx->active) { + ctx->active = iter->prev; + ctx->end = iter->prev; + if (ctx->active) + ctx->active->flags &= ~(unsigned)NK_WINDOW_ROM; + } /* free unused popup windows */ if (iter->popup.win && iter->popup.win->seq != ctx->seq) { nk_free_window(ctx, iter->popup.win); @@ -17362,8 +17448,7 @@ nk_clear(struct nk_context *ctx) nk_free_table(ctx, it); if (it == iter->tables) iter->tables = n; - } - it = n; + } it = n; }} /* window itself is not used anymore so free */ if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) { @@ -17462,7 +17547,7 @@ nk_finish(struct nk_context *ctx, struct nk_window *win) NK_INTERN void nk_build(struct nk_context *ctx) { - struct nk_window *iter = 0; + struct nk_window *it = 0; struct nk_command *cmd = 0; nk_byte *buffer = 0; @@ -17484,38 +17569,38 @@ nk_build(struct nk_context *ctx) nk_finish_buffer(ctx, &ctx->overlay); } /* build one big draw command list out of all window buffers */ - iter = ctx->begin; + it = ctx->begin; buffer = (nk_byte*)ctx->memory.memory.ptr; - while (iter != 0) { - struct nk_window *next = iter->next; - if (iter->buffer.last == iter->buffer.begin || (iter->flags & NK_WINDOW_HIDDEN)|| - iter->seq != ctx->seq) + while (it != 0) { + struct nk_window *next = it->next; + if (it->buffer.last == it->buffer.begin || (it->flags & NK_WINDOW_HIDDEN)|| + it->seq != ctx->seq) goto cont; - cmd = nk_ptr_add(struct nk_command, buffer, iter->buffer.last); + cmd = nk_ptr_add(struct nk_command, buffer, it->buffer.last); while (next && ((next->buffer.last == next->buffer.begin) || (next->flags & NK_WINDOW_HIDDEN))) next = next->next; /* skip empty command buffers */ if (next) cmd->next = next->buffer.begin; - cont: iter = next; + cont: it = next; } /* append all popup draw commands into lists */ - iter = ctx->begin; - while (iter != 0) { - struct nk_window *next = iter->next; + it = ctx->begin; + while (it != 0) { + struct nk_window *next = it->next; struct nk_popup_buffer *buf; - if (!iter->popup.buf.active) + if (!it->popup.buf.active) goto skip; - buf = &iter->popup.buf; + buf = &it->popup.buf; cmd->next = buf->begin; cmd = nk_ptr_add(struct nk_command, buffer, buf->last); buf->active = nk_false; - skip: iter = next; + skip: it = next; } - /* append overlay commands */ if (cmd) { + /* append overlay commands */ if (ctx->overlay.end != ctx->overlay.begin) cmd->next = ctx->overlay.begin; else cmd->next = ctx->memory.allocated; @@ -17537,7 +17622,8 @@ nk__begin(struct nk_context *ctx) ctx->build = nk_true; } iter = ctx->begin; - while (iter && ((iter->buffer.begin == iter->buffer.end) || (iter->flags & NK_WINDOW_HIDDEN))) + while (iter && ((iter->buffer.begin == iter->buffer.end) || + (iter->flags & NK_WINDOW_HIDDEN) || iter->seq != ctx->seq)) iter = iter->next; if (!iter) return 0; return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin); @@ -18440,7 +18526,7 @@ nk_insert_window(struct nk_context *ctx, struct nk_window *win, ctx->active = ctx->end; ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM; } else { - ctx->end->flags |= NK_WINDOW_ROM; + /*ctx->end->flags |= NK_WINDOW_ROM;*/ ctx->begin->prev = win; win->next = ctx->begin; win->prev = 0; @@ -18546,27 +18632,28 @@ nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, * provided demo backends). */ NK_ASSERT(win->seq != ctx->seq); win->seq = ctx->seq; - if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN)) + if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN)) { ctx->active = win; + ctx->end = win; + } } if (win->flags & NK_WINDOW_HIDDEN) { ctx->current = win; win->layout = 0; return 0; - } + } else nk_start(ctx, win); /* window overlapping */ if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT)) { int inpanel, ishovered; - const struct nk_window *iter = win; + struct nk_window *iter = win; float h = ctx->style.font->height + 2.0f * style->window.header.padding.y + (2.0f * style->window.header.label_padding.y); struct nk_rect win_bounds = (!(win->flags & NK_WINDOW_MINIMIZED))? win->bounds: nk_rect(win->bounds.x, win->bounds.y, win->bounds.w, h); /* activate window if hovered and no other window is overlapping this window */ - nk_start(ctx, win); inpanel = nk_input_has_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_LEFT, win_bounds, nk_true); inpanel = inpanel && ctx->input.mouse.buttons[NK_BUTTON_LEFT].clicked; ishovered = nk_input_is_mouse_hovering_rect(&ctx->input, win_bounds); @@ -18577,7 +18664,7 @@ nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h); if (NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h, iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) && - (!(iter->flags & NK_WINDOW_HIDDEN) || !(iter->flags & NK_WINDOW_BACKGROUND))) + (!(iter->flags & NK_WINDOW_HIDDEN))) break; if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) && @@ -18590,7 +18677,7 @@ nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, } /* activate window if clicked */ - if (iter && inpanel && (win != ctx->end) && !(iter->flags & NK_WINDOW_BACKGROUND)) { + if (iter && inpanel && (win != ctx->end)) { iter = win->next; while (iter) { /* try to find a panel with higher priority in the same position */ @@ -18608,21 +18695,31 @@ nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, iter = iter->next; } } - - if (!iter && ctx->end != win) { - if (!(win->flags & NK_WINDOW_BACKGROUND)) { + if (iter && !(win->flags & NK_WINDOW_ROM) && (win->flags & NK_WINDOW_BACKGROUND)) { + win->flags |= (nk_flags)NK_WINDOW_ROM; + iter->flags &= ~(nk_flags)NK_WINDOW_ROM; + ctx->active = iter; + if (!(iter->flags & NK_WINDOW_BACKGROUND)) { /* current window is active in that position so transfer to top * at the highest priority in stack */ - nk_remove_window(ctx, win); - nk_insert_window(ctx, win, NK_INSERT_BACK); + nk_remove_window(ctx, iter); + nk_insert_window(ctx, iter, NK_INSERT_BACK); } - win->flags &= ~(nk_flags)NK_WINDOW_ROM; - ctx->active = win; + } else { + if (!iter && ctx->end != win) { + if (!(win->flags & NK_WINDOW_BACKGROUND)) { + /* current window is active in that position so transfer to top + * at the highest priority in stack */ + nk_remove_window(ctx, win); + nk_insert_window(ctx, win, NK_INSERT_BACK); + } + win->flags &= ~(nk_flags)NK_WINDOW_ROM; + ctx->active = win; + } + if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND)) + win->flags |= NK_WINDOW_ROM; } - if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND)) - win->flags |= NK_WINDOW_ROM; } - win->layout = (struct nk_panel*)nk_create_panel(ctx); ctx->current = win; ret = nk_panel_begin(ctx, title, NK_PANEL_WINDOW); @@ -18770,6 +18867,8 @@ nk_window_is_hovered(struct nk_context *ctx) NK_ASSERT(ctx); NK_ASSERT(ctx->current); if (!ctx || !ctx->current) return 0; + if(ctx->current->flags & NK_WINDOW_HIDDEN) + return 0; return nk_input_is_mouse_hovering_rect(&ctx->input, ctx->current->bounds); } @@ -18782,17 +18881,20 @@ nk_window_is_any_hovered(struct nk_context *ctx) iter = ctx->begin; while (iter) { /* check if window is being hovered */ - if (iter->flags & NK_WINDOW_MINIMIZED) { - struct nk_rect header = iter->bounds; - header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y; - if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) + if(!(iter->flags & NK_WINDOW_HIDDEN)) { + /* check if window popup is being hovered */ + if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds)) return 1; - } else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) { - return 1; + + if (iter->flags & NK_WINDOW_MINIMIZED) { + struct nk_rect header = iter->bounds; + header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y; + if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) + return 1; + } else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) { + return 1; + } } - /* check if window popup is being hovered */ - if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds)) - return 1; iter = iter->next; } return 0; @@ -18895,29 +18997,36 @@ nk_window_close(struct nk_context *ctx, const char *name) } NK_API void -nk_window_set_bounds(struct nk_context *ctx, struct nk_rect bounds) +nk_window_set_bounds(struct nk_context *ctx, + const char *name, struct nk_rect bounds) { - NK_ASSERT(ctx); NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - ctx->current->bounds = bounds; + struct nk_window *win; + NK_ASSERT(ctx); + if (!ctx) return; + win = nk_window_find(ctx, name); + if (!win) return; + NK_ASSERT(ctx->current != win && "You cannot update a currently in procecss window"); + win->bounds = bounds; } NK_API void -nk_window_set_position(struct nk_context *ctx, struct nk_vec2 pos) +nk_window_set_position(struct nk_context *ctx, + const char *name, struct nk_vec2 pos) { - NK_ASSERT(ctx); NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - ctx->current->bounds.x = pos.x; - ctx->current->bounds.y = pos.y; + struct nk_window *win = nk_window_find(ctx, name); + if (!win) return; + win->bounds.x = pos.x; + win->bounds.y = pos.y; } NK_API void -nk_window_set_size(struct nk_context *ctx, struct nk_vec2 size) +nk_window_set_size(struct nk_context *ctx, + const char *name, struct nk_vec2 size) { - NK_ASSERT(ctx); NK_ASSERT(ctx->current); - if (!ctx || !ctx->current) return; - ctx->current->bounds.w = size.x; - ctx->current->bounds.h = size.y; + struct nk_window *win = nk_window_find(ctx, name); + if (!win) return; + win->bounds.w = size.x; + win->bounds.h = size.y; } NK_API void @@ -19845,6 +19954,9 @@ nk_layout_peek(struct nk_rect *bounds, struct nk_context *ctx) layout->row.index = 0; } nk_layout_widget_space(bounds, ctx, win, nk_false); + if (!layout->row.index) { + bounds->x -= layout->row.item_offset; + } layout->at_y = y; layout->row.index = index; } @@ -21204,8 +21316,8 @@ nk_edit_string(struct nk_context *ctx, nk_flags flags, win->edit.sel_start = edit->select_start; win->edit.sel_end = edit->select_end; win->edit.mode = edit->mode; - win->edit.scrollbar.x = (nk_ushort)edit->scrollbar.x; - win->edit.scrollbar.y = (nk_ushort)edit->scrollbar.y; + win->edit.scrollbar.x = (nk_uint)edit->scrollbar.x; + win->edit.scrollbar.y = (nk_uint)edit->scrollbar.y; } return state; } @@ -21250,7 +21362,9 @@ nk_edit_buffer(struct nk_context *ctx, nk_flags flags, } if (flags & NK_EDIT_CLIPBOARD) edit->clip = ctx->clip; - } + edit->active = (unsigned char)win->edit.active; + } else edit->active = nk_false; + edit->mode = win->edit.mode; filter = (!filter) ? nk_filter_default: filter; prev_state = (unsigned char)edit->active; @@ -22361,10 +22475,10 @@ nk_tooltip_begin(struct nk_context *ctx, float width) if (win->popup.win && (win->popup.type & NK_PANEL_SET_NONBLOCK)) return 0; - bounds.w = width; - bounds.h = nk_null_rect.h; - bounds.x = (in->mouse.pos.x + 1) - win->layout->clip.x; - bounds.y = (in->mouse.pos.y + 1) - win->layout->clip.y; + bounds.w = (float) nk_iceilf(width); + bounds.h = (float) nk_iceilf(nk_null_rect.h); + bounds.x = nk_ifloorf(in->mouse.pos.x + 1) - win->layout->clip.x; + bounds.y = nk_ifloorf(in->mouse.pos.y + 1) - win->layout->clip.y; ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC, "__##Tooltip##__", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds); @@ -22420,6 +22534,19 @@ nk_tooltip(struct nk_context *ctx, const char *text) nk_tooltip_end(ctx); } } +#ifdef NK_INCLUDE_STANDARD_VARARGS +NK_API void +nk_tooltipf(struct nk_context *ctx, const char *fmt, ...) +{ + char buf[256]; + va_list args; + va_start(args, fmt); + nk_strfmt(buf, NK_LEN(buf), fmt, args); + va_end(args); + nk_tooltip(ctx, buf); +} +#endif + /* ------------------------------------------------------------- * * CONTEXTUAL @@ -23587,4 +23714,4 @@ NK_API void nk_menu_end(struct nk_context *ctx) {nk_contextual_end(ctx);} -#endif +#endif /* NK_IMPLEMENTATION */ diff --git a/deps/nuklear_glfw_gl2.h b/deps/nuklear_glfw_gl2.h index 965af5fe1..61acc29c6 100644 --- a/deps/nuklear_glfw_gl2.h +++ b/deps/nuklear_glfw_gl2.h @@ -75,6 +75,8 @@ static struct nk_glfw { int text_len; struct nk_vec2 scroll; double last_button_click; + int is_double_click_down; + struct nk_vec2 double_click_pos; } glfw; NK_INTERN void @@ -219,10 +221,12 @@ nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int m glfwGetCursorPos(window, &x, &y); if (action == GLFW_PRESS) { double dt = glfwGetTime() - glfw.last_button_click; - if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) - nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_true); + if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) { + glfw.is_double_click_down = nk_true; + glfw.double_click_pos = nk_vec2((float)x, (float)y); + } glfw.last_button_click = glfwGetTime(); - } else nk_input_button(&glfw.ctx, NK_BUTTON_DOUBLE, (int)x, (int)y, nk_false); + } else glfw.is_double_click_down = nk_false; } NK_INTERN void @@ -261,6 +265,10 @@ nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state) glfw.ctx.clip.paste = nk_glfw3_clipbard_paste; glfw.ctx.clip.userdata = nk_handle_ptr(0); nk_buffer_init_default(&glfw.ogl.cmds); + + glfw.is_double_click_down = nk_false; + glfw.double_click_pos = nk_vec2(0, 0); + return &glfw.ctx; } @@ -344,7 +352,7 @@ nk_glfw3_new_frame(void) glfwGetCursorPos(win, &x, &y); nk_input_motion(ctx, (int)x, (int)y); if (ctx->input.mouse.grabbed) { - glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y); + glfwSetCursorPos(glfw.win, (double)ctx->input.mouse.prev.x, (double)ctx->input.mouse.prev.y); ctx->input.mouse.pos.x = ctx->input.mouse.prev.x; ctx->input.mouse.pos.y = ctx->input.mouse.prev.y; } @@ -352,6 +360,7 @@ nk_glfw3_new_frame(void) nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS); nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS); nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS); + nk_input_button(ctx, NK_BUTTON_DOUBLE, (int)glfw.double_click_pos.x, (int)glfw.double_click_pos.y, glfw.is_double_click_down); nk_input_scroll(ctx, glfw.scroll); nk_input_end(&glfw.ctx); glfw.text_len = 0; diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 20d85ae9c..6bb849f13 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -27,7 +27,7 @@ foreach(arg ${glfw_DOCS_SOURCES}) endforeach() configure_file(Doxyfile.in Doxyfile @ONLY) - + add_custom_target(docs ALL "${DOXYGEN_EXECUTABLE}" WORKING_DIRECTORY "${GLFW_BINARY_DIR}/docs" COMMENT "Generating HTML documentation" VERBATIM) diff --git a/docs/DoxygenLayout.xml b/docs/DoxygenLayout.xml index 7917f91ed..a7e175306 100644 --- a/docs/DoxygenLayout.xml +++ b/docs/DoxygenLayout.xml @@ -11,7 +11,7 @@ - + @@ -19,7 +19,7 @@ - + diff --git a/docs/compat.dox b/docs/compat.dox index 380244662..50b82c5db 100644 --- a/docs/compat.dox +++ b/docs/compat.dox @@ -78,7 +78,7 @@ fallback path is used. GLFW uses the XInput2 extension to provide raw, non-accelerated mouse motion when the cursor is disabled. If the running X server does not support this -extension, regular accelerated mouse motion will be used. +extension, regular accelerated mouse motion will be used. GLFW uses both the XRender extension and the compositing manager to support transparent window framebuffers. If the running X server does not support this diff --git a/docs/context.dox b/docs/context.dox index e94448dcd..5e1eb25c1 100644 --- a/docs/context.dox +++ b/docs/context.dox @@ -161,7 +161,7 @@ An extension loader library is the easiest and best way to access both OpenGL an OpenGL ES extensions and modern versions of the core OpenGL or OpenGL ES APIs. They will take care of all the details of declaring and loading everything you need. One such library is [glad](https://github.com/Dav1dde/glad) and there are -several others. +several others. The following example will use glad but all extension loader libraries work similarly. diff --git a/docs/input.dox b/docs/input.dox index 89ff98320..1d8439d55 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -1,7 +1,7 @@ /*! @page input_guide Input guide - + @tableofcontents This guide introduces the input related functions of GLFW. For details on @@ -170,6 +170,19 @@ When sticky keys mode is enabled, the pollable state of a key will remain it has been polled, if a key release event had been processed in the meantime, the state will reset to `GLFW_RELEASE`, otherwise it will remain `GLFW_PRESS`. +@anchor GLFW_LOCK_KEY_MODS +If you wish to know what the state of the Caps Lock and Num Lock keys was when +input events were generated, set the `GLFW_LOCK_KEY_MODS` input mode. + +@code +glfwSetInputMode(window, GLFW_LOCK_KEY_MODS, 1); +@endcode + +When this input mode is enabled, any callback that receives +[modifier bits](@ref mods) will have the @ref GLFW_MOD_CAPS_LOCK bit set if Caps +Lock was on when the event occurred and the @ref GLFW_MOD_NUM_LOCK bit set if +Num Lock was on. + The `GLFW_KEY_LAST` constant holds the highest value of any [named key](@ref keys). @@ -186,8 +199,7 @@ encode the code points into UTF-8 or any other encoding you prefer. Because an `unsigned int` is 32 bits long on all platforms supported by GLFW, you can treat the code point argument as native endian UTF-32. -There are two callbacks for receiving Unicode code points. If you wish to -offer regular text input, set a character callback. +If you wish to offer regular text input, set a character callback. @code glfwSetCharCallback(window, character_callback); @@ -203,23 +215,6 @@ void character_callback(GLFWwindow* window, unsigned int codepoint) } @endcode -If you also wish to receive those Unicode code points generated with modifier -key combinations that a plain text field would ignore, or want to know exactly -what modifier keys were used, set a character with modifiers callback. - -@code -glfwSetCharModsCallback(window, charmods_callback); -@endcode - -The callback function receives Unicode code points and -[modifier bits](@ref mods). - -@code -void charmods_callback(GLFWwindow* window, unsigned int codepoint, int mods) -{ -} -@endcode - @subsection input_key_name Key names @@ -424,6 +419,16 @@ void cursor_enter_callback(GLFWwindow* window, int entered) } @endcode +You can query whether the cursor is currently inside the client area of the +window with the [GLFW_HOVERED](@ref GLFW_HOVERED_attrib) window attribute. + +@code +if (glfwGetWindowAttrib(window, GLFW_HOVERED)) +{ + highlight_interface(); +} +@endcode + @subsection input_mouse_button Mouse button input @@ -516,6 +521,9 @@ present with @ref glfwJoystickPresent. int present = glfwJoystickPresent(GLFW_JOYSTICK_1); @endcode +Each joystick has zero or more axes, zero or more buttons, zero or more hats, +a human-readable name, a user pointer and an SDL compatible GUID. + When GLFW is initialized, detected joysticks are added to to the beginning of the array. Once a joystick is detected, it keeps its assigned ID until it is disconnected or the library is terminated, so as joysticks are connected and @@ -607,7 +615,7 @@ See the reference documentation for @ref glfwGetJoystickButtons for details. The human-readable, UTF-8 encoded name of a joystick is returned by @ref glfwGetJoystickName. See the reference documentation for the lifetime of the -returned string. +returned string. @code const char* name = glfwGetJoystickName(GLFW_JOYSTICK_4); @@ -618,6 +626,17 @@ and make may have the same name. Only the [joystick token](@ref joysticks) is guaranteed to be unique, and only until that joystick is disconnected. +@subsection joystick_userptr Joystick user pointer + +Each joystick has a user pointer that can be set with @ref +glfwSetJoystickUserPointer and queried with @ref glfwGetJoystickUserPointer. +This can be used for any purpose you need and will not be modified by GLFW. The +value will be kept until the joystick is disconnected or until the library is +terminated. + +The initial value of the pointer is `NULL`. + + @subsection joystick_event Joystick configuration changes If you wish to be notified when a joystick is connected or disconnected, set @@ -650,6 +669,10 @@ functions. Joystick disconnection may also be detected and the callback called by joystick functions. The function will then return whatever it returns for a disconnected joystick. +Only @ref glfwGetJoystickName and @ref glfwGetJoystickUserPointer will return +useful values for a disconnected joystick and only before the monitor callback +returns. + @subsection gamepad Gamepad input diff --git a/docs/internal.dox b/docs/internal.dox index 72a095403..9118492f1 100644 --- a/docs/internal.dox +++ b/docs/internal.dox @@ -111,6 +111,6 @@ which is generated from the `glfw_config.h.in` file by CMake. Configuration macros the same style as tokens in the public interface, except with a leading underscore. -Examples: `_GLFW_USE_HYBRID_HPG` +Examples: `_GLFW_USE_HYBRID_HPG` */ diff --git a/docs/intro.dox b/docs/intro.dox index 46a445aa2..e8adf5357 100644 --- a/docs/intro.dox +++ b/docs/intro.dox @@ -1,7 +1,7 @@ -/*! +/*! @page intro_guide Introduction to the API - + @tableofcontents This guide introduces the basic concepts of GLFW and describes initialization, @@ -33,7 +33,6 @@ successfully initialized, and only from the main thread. - @ref glfwGetError - @ref glfwSetErrorCallback - @ref glfwInitHint - - @ref glfwInitHintString - @ref glfwInit - @ref glfwTerminate @@ -67,8 +66,7 @@ settings and these might not be restored without termination. @subsection init_hints Initialization hints Initialization hints are set before @ref glfwInit and affect how the library -behaves until termination. Integer type hints are set with @ref glfwInitHint -and string type hints with @ref glfwInitHintString. +behaves until termination. Hints are set with @ref glfwInitHint. @code glfwInitHint(GLFW_JOYSTICK_HAT_BUTTONS, GLFW_FALSE); @@ -104,15 +102,6 @@ a nib or manually, when the first window is created, which is when AppKit is initialized. Set this with @ref glfwInitHint. -@subsubsection init_hints_x11 X11 specific init hints - -@anchor GLFW_X11_WM_CLASS_NAME -@anchor GLFW_X11_WM_CLASS_CLASS -__GLFW_X11_WM_CLASS_NAME__ and __GLFW_X11_WM_CLASS_CLASS__ specifies the desired -ASCII encoded name and class parts of the ICCCM `WM_CLASS` hint for all windows. -Set this with @ref glfwInitHintString. - - @subsubsection init_hints_values Supported and default values Initialization hint | Default value | Supported values @@ -120,8 +109,6 @@ Initialization hint | Default value | Supported values @ref GLFW_JOYSTICK_HAT_BUTTONS | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` @ref GLFW_COCOA_CHDIR_RESOURCES | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` @ref GLFW_COCOA_MENUBAR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` -@ref GLFW_X11_WM_CLASS_NAME | `""` | An ASCII encoded `WM_CLASS` name -@ref GLFW_X11_WM_CLASS_CLASS | `""` | An ASCII encoded `WM_CLASS` class @subsection intro_init_terminate Terminating GLFW @@ -140,7 +127,7 @@ any other resources allocated by GLFW. Once the library is terminated, it is as if it had never been initialized and 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 -immediately. +immediately. @section error_handling Error handling @@ -307,7 +294,7 @@ calls main), but some may be called from any thread once the library has been initialized. Before initialization the whole library is thread-unsafe. The reference documentation for every GLFW function states whether it is limited -to the main thread. +to the main thread. Initialization, termination, event processing and the creation and destruction of windows, cursors and OpenGL and OpenGL ES contexts are all diff --git a/docs/monitor.dox b/docs/monitor.dox index 620646d56..08c119336 100644 --- a/docs/monitor.dox +++ b/docs/monitor.dox @@ -86,14 +86,16 @@ void monitor_callback(GLFWmonitor* monitor, int event) @endcode If a monitor is disconnected, all windows that are full screen on it will be -switched to windowed mode. +switched to windowed mode before the callback is called. Only @ref +glfwGetMonitorName and @ref glfwGetMonitorUserPointer will return useful values +for a disconnected monitor and only before the monitor callback returns. @section monitor_properties Monitor properties Each monitor has a current video mode, a list of supported video modes, -a virtual position, a human-readable name, an estimated physical size and -a gamma ramp. +a virtual position, a human-readable name, a user pointer, an estimated physical +size and a gamma ramp. @subsection monitor_modes Video modes @@ -157,7 +159,7 @@ any UI elements. The content scale may depend on both the monitor resolution and pixel density and on user settings. It may be very different from the raw DPI calculated from -the physical size and current resolution. +the physical size and current resolution. @subsection monitor_pos Virtual position @@ -187,6 +189,17 @@ and make may have the same name. Only the monitor handle is guaranteed to be unique, and only until that monitor is disconnected. +@subsection monitor_userptr User pointer + +Each monitor has a user pointer that can be set with @ref +glfwSetMonitorUserPointer and queried with @ref glfwGetMonitorUserPointer. This +can be used for any purpose you need and will not be modified by GLFW. The +value will be kept until the monitor is disconnected or until the library is +terminated. + +The initial value of the pointer is `NULL`. + + @subsection monitor_gamma Gamma ramp The gamma ramp of a monitor can be set with @ref glfwSetGammaRamp, which accepts diff --git a/docs/moving.dox b/docs/moving.dox index 0f33a7e54..08ef7f24c 100644 --- a/docs/moving.dox +++ b/docs/moving.dox @@ -40,7 +40,7 @@ time away from the focus of GLFW (i.e. context, input and window). There are better threading libraries available and native threading support is available in both [C++11](http://en.cppreference.com/w/cpp/thread) and [C11](http://en.cppreference.com/w/c/thread), both of which are gaining -traction. +traction. If you wish to use the C++11 or C11 facilities but your compiler doesn't yet support them, see the @@ -73,7 +73,7 @@ To become of sufficiently high quality to warrant keeping them in GLFW 3, they would need not only to support other formats, but also modern extensions to OpenGL texturing. This would either add a number of external dependencies (libjpeg, libpng, etc.), or force GLFW to ship with inline versions -of these libraries. +of these libraries. As there already are libraries doing this, it is unnecessary both to duplicate the work and to tie the duplicate to GLFW. The resulting library would also be @@ -92,7 +92,7 @@ has been removed. GLFW is written in C, not Pascal. Removing this macro means there's one less thing for application programmers to remember, i.e. the requirement to mark all callback functions with `GLFWCALL`. It also simplifies the creation of DLLs and DLL link libraries, as there's no need to explicitly -disable `@n` entry point suffixes. +disable `@n` entry point suffixes. @par Old syntax @code diff --git a/docs/news.dox b/docs/news.dox index adbb7724f..392180555 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -64,14 +64,16 @@ GLFW now supports querying the window and monitor content scale, i.e. the ratio between the current DPI and the platform's default DPI, with @ref glfwGetWindowContentScale and @ref glfwGetMonitorContentScale. +Changes of the content scale of a window can be received with the window content +scale callback, set with @ref glfwSetWindowCloseCallback. + @see @ref window_scale @subsection news_33_inithint Support for initialization hints -GLFW now supports setting library initialization hints with @ref glfwInitHint -or @ref glfwInitHintString. These must be set before initialization to take -effect. +GLFW now supports setting library initialization hints with @ref glfwInitHint. +These must be set before initialization to take effect. @see @ref init_hints @@ -140,6 +142,13 @@ creation API, intended for automated testing. This backend does not provide input. +@subsection news_33_userptr Monitor and joystick user pointers + +GLFW now supports setting and querying user pointers for connected monitors and +joysticks with @ref glfwSetMonitorUserPointer, @ref glfwGetMonitorUserPointer, +@ref glfwSetJoystickUserPointer and @ref glfwGetJoystickUserPointer. + + @subsection news_33_primary X11 primary selection access GLFW now supports querying and setting the X11 primary selection via the native diff --git a/docs/quick.dox b/docs/quick.dox index ff2c6f06f..d8c338220 100644 --- a/docs/quick.dox +++ b/docs/quick.dox @@ -174,7 +174,7 @@ If you are using an [extension loader library](@ref context_glext_auto) to access modern OpenGL then this is when to initialize it, as the loader needs a current context to load from. This example uses [glad](https://github.com/Dav1dde/glad), but the same rule applies to all such -libraries. +libraries. @code gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); @@ -309,7 +309,7 @@ done each frame after buffer swapping. There are two methods for processing pending events; polling and waiting. This example will use event polling, which processes only those events that have -already been received and then returns immediately. +already been received and then returns immediately. @code glfwPollEvents(); diff --git a/docs/vulkan.dox b/docs/vulkan.dox index 7de9cd646..8c198bef2 100644 --- a/docs/vulkan.dox +++ b/docs/vulkan.dox @@ -1,7 +1,7 @@ /*! @page vulkan_guide Vulkan guide - + @tableofcontents This guide is intended to fill the gaps between the [Vulkan @@ -180,7 +180,7 @@ ici.ppEnabledExtensionNames = extensions; Additional extensions may be required by future versions of GLFW. You should check whether any extensions you wish to enable are already in the returned array, as it is an error to specify an extension more than once in the -`VkInstanceCreateInfo` struct. +`VkInstanceCreateInfo` struct. @section vulkan_present Querying for Vulkan presentation support @@ -197,7 +197,7 @@ if (glfwGetPhysicalDevicePresentationSupport(instance, physical_device, queue_fa } @endcode -The `VK_KHR_surface` extension additionally provides the +The `VK_KHR_surface` extension additionally provides the `vkGetPhysicalDeviceSurfaceSupportKHR` function, which performs the same test on an existing Vulkan surface. diff --git a/docs/window.dox b/docs/window.dox index db29d6115..9e97ce3bc 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -1,7 +1,7 @@ /*! @page window_guide Window guide - + @tableofcontents This guide introduces the window related functions of GLFW. For details on @@ -48,7 +48,7 @@ the event. To create a full screen window, you need to specify which monitor the window should use. In most cases, the user's primary monitor is a good choice. -For more information about retrieving monitors, see @ref monitor_monitors. +For more information about retrieving monitors, see @ref monitor_monitors. @code GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", glfwGetPrimaryMonitor(), NULL); @@ -146,16 +146,18 @@ is restored, but the gamma ramp is left untouched. There are a number of hints that can be set before the creation of a window and context. Some affect the window itself, others affect the framebuffer or context. These hints are set to their default values each time the library is -initialized with @ref glfwInit, can be set individually with @ref glfwWindowHint -and reset all at once to their defaults with @ref glfwDefaultWindowHints. +initialized with @ref glfwInit. Integer value hints can be set individually +with @ref glfwWindowHint and string value hints with @ref glfwWindowHintString. +You can reset all at once to their defaults with @ref glfwDefaultWindowHints. Some hints are platform specific. These are always valid to set on any platform but they will only affect their specific platform. Other platforms will ignore them. Setting these hints requires no platform specific headers or calls. -Note that hints need to be set _before_ the creation of the window and context -you wish to have the specified attributes. +@note Window hints need to be set before the creation of the window and context +you wish to have the specified attributes. They function as additional +arguments to @ref glfwCreateWindow. @subsubsection window_hints_hard Hard and soft constraints @@ -441,10 +443,10 @@ __GLFW_COCOA_RETINA_FRAMEBUFFER__ specifies whether to use full resolution framebuffers on Retina displays. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. This is ignored on other platforms. -@anchor GLFW_COCOA_FRAME_AUTOSAVE_hint -__GLFW_COCOA_FRAME_AUTOSAVE__ specifies whether to activate frame autosaving -using the window title specified at window creation. Possible values are -`GLFW_TRUE` and `GLFW_FALSE`. This is ignored on other platforms. +@anchor GLFW_COCOA_FRAME_NAME_hint +__GLFW_COCOA_FRAME_NAME__ specifies the UTF-8 encoded name to use for autosaving +the window frame, or if empty disables frame autosaving for the window. This is +ignored on other platforms. This is set with @ref glfwWindowHintString. @anchor GLFW_COCOA_GRAPHICS_SWITCHING_hint __GLFW_COCOA_GRAPHICS_SWITCHING__ specifies whether to in Automatic Graphics @@ -465,6 +467,15 @@ should also declare this in its `Info.plist` by setting the `NSSupportsAutomaticGraphicsSwitching` key to `true`. +@subsubsection window_hints_x11 X11 specific window hints + +@anchor GLFW_X11_CLASS_NAME +@anchor GLFW_X11_INSTANCE_NAME +__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. +These are set with @ref glfwWindowHintString. + + @subsubsection window_hints_values Supported and default values Window hint | Default value | Supported values @@ -504,8 +515,10 @@ GLFW_OPENGL_FORWARD_COMPAT | `GLFW_FALSE` | `GLFW_TRUE` or `GL GLFW_OPENGL_DEBUG_CONTEXT | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_OPENGL_PROFILE | `GLFW_OPENGL_ANY_PROFILE` | `GLFW_OPENGL_ANY_PROFILE`, `GLFW_OPENGL_COMPAT_PROFILE` or `GLFW_OPENGL_CORE_PROFILE` GLFW_COCOA_RETINA_FRAMEBUFFER | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` -GLFW_COCOA_FRAME_AUTOSAVE | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` +GLFW_COCOA_FRAME_NAME | `""` | A UTF-8 encoded frame autosave name GLFW_COCOA_GRAPHICS_SWITCHING | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` +GLFW_X11_CLASS_NAME | `""` | An ASCII encoded `WM_CLASS` class name +GLFW_X11_INSTANCE_NAME | `""` | An ASCII encoded `WM_CLASS` instance name @section window_events Window event processing @@ -518,7 +531,7 @@ See @ref events. @subsection window_userptr User pointer Each window has a user pointer that can be set with @ref -glfwSetWindowUserPointer and fetched with @ref glfwGetWindowUserPointer. This +glfwSetWindowUserPointer and queried with @ref glfwGetWindowUserPointer. This can be used for any purpose you need and will not be modified by GLFW throughout the life-time of the window. @@ -682,6 +695,23 @@ On systems where each monitors can have its own content scale, the window content scale will depend on which monitor the system considers the window to be on. +If you wish to be notified when the content scale of a window changes, whether +because of a system setting change or because it was moved to a monitor with +a different scale, set a content scale callback. + +@code +glfwSetWindowContentScaleCallback(window, window_content_scale_callback); +@endcode + +The callback function receives the new content scale of the window. + +@code +void window_content_scale_callback(GLFWwindow* window, float xscale, float yscale) +{ + set_interface_scale(xscale, yscale); +} +@endcode + @subsection window_sizelimits Window size limits @@ -1190,6 +1220,11 @@ See @ref window_iconify for details. __GLFW_MAXIMIZED__ indicates whether the specified window is maximized. See @ref window_maximize for details. +@anchor GLFW_HOVERED_attrib +__GLFW_HOVERED__ indicates whether the cursor is currently directly over the +client area of the window, with no other windows between. See @ref cursor_enter +for details. + @anchor GLFW_VISIBLE_attrib __GLFW_VISIBLE__ indicates whether the specified window is visible. See @ref window_hide for details. diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 82af857d7..d7521458e 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -493,17 +493,37 @@ extern "C" { * @{ */ /*! @brief If this bit is set one or more Shift keys were held down. + * + * If this bit is set one or more Shift keys were held down. */ #define GLFW_MOD_SHIFT 0x0001 /*! @brief If this bit is set one or more Control keys were held down. + * + * If this bit is set one or more Control keys were held down. */ #define GLFW_MOD_CONTROL 0x0002 /*! @brief If this bit is set one or more Alt keys were held down. + * + * If this bit is set one or more Alt keys were held down. */ #define GLFW_MOD_ALT 0x0004 /*! @brief If this bit is set one or more Super keys were held down. + * + * If this bit is set one or more Super keys were held down. */ #define GLFW_MOD_SUPER 0x0008 +/*! @brief If this bit is set the Caps Lock key is enabled. + * + * If this bit is set the Caps Lock key is enabled and the @ref + * GLFW_LOCK_KEY_MODS input mode is set. + */ +#define GLFW_MOD_CAPS_LOCK 0x0010 +/*! @brief If this bit is set the Num Lock key is enabled. + * + * If this bit is set the Num Lock key is enabled and the @ref + * GLFW_LOCK_KEY_MODS input mode is set. + */ +#define GLFW_MOD_NUM_LOCK 0x0020 /*! @} */ @@ -794,6 +814,7 @@ extern "C" { * [window attribute](@ref GLFW_TRANSPARENT_FRAMEBUFFER_attrib). */ #define GLFW_TRANSPARENT_FRAMEBUFFER 0x0002000A +#define GLFW_HOVERED 0x0002000B /*! @brief Framebuffer bit depth hint. * @@ -944,8 +965,11 @@ extern "C" { #define GLFW_CONTEXT_CREATION_API 0x0002200B #define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001 -#define GLFW_COCOA_FRAME_AUTOSAVE 0x00023002 +#define GLFW_COCOA_FRAME_NAME 0x00023002 #define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003 + +#define GLFW_X11_CLASS_NAME 0x00024001 +#define GLFW_X11_INSTANCE_NAME 0x00024002 /*! @} */ #define GLFW_NO_API 0 @@ -963,6 +987,7 @@ extern "C" { #define GLFW_CURSOR 0x00033001 #define GLFW_STICKY_KEYS 0x00033002 #define GLFW_STICKY_MOUSE_BUTTONS 0x00033003 +#define GLFW_LOCK_KEY_MODS 0x00033004 #define GLFW_CURSOR_NORMAL 0x00034001 #define GLFW_CURSOR_HIDDEN 0x00034002 @@ -1025,9 +1050,6 @@ extern "C" { #define GLFW_COCOA_CHDIR_RESOURCES 0x00051001 #define GLFW_COCOA_MENUBAR 0x00051002 - -#define GLFW_X11_WM_CLASS_NAME 0x00052001 -#define GLFW_X11_WM_CLASS_CLASS 0x00052002 /*! @} */ #define GLFW_DONT_CARE -1 @@ -1046,7 +1068,7 @@ extern "C" { * @sa @ref glfwGetProcAddress * * @since Added in version 3.0. - + * * @ingroup context */ typedef void (*GLFWglproc)(void); @@ -1257,6 +1279,24 @@ typedef void (* GLFWwindowmaximizefun)(GLFWwindow*,int); */ typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int); +/*! @brief The function signature for window content scale callbacks. + * + * This is the function signature for window content scale callback + * functions. + * + * @param[in] window The window whose content scale changed. + * @param[in] xscale The new x-axis content scale of the window. + * @param[in] yscale The new y-axis content scale of the window. + * + * @sa @ref window_scale + * @sa @ref glfwSetWindowContentScaleCallback + * + * @since Added in version 3.3. + * + * @ingroup window + */ +typedef void (* GLFWwindowcontentscalefun)(GLFWwindow*,float,float); + /*! @brief The function signature for mouse button callbacks. * * This is the function signature for mouse button callback functions. @@ -1642,8 +1682,7 @@ GLFWAPI void glfwTerminate(void); /*! @brief Sets the specified init hint to the desired value. * - * This function sets hints for the next initialization of GLFW. Only integer - * type hints can be set with this function. + * This function sets hints for the next initialization of GLFW. * * The values you set hints to are never reset by GLFW, but they only take * effect during initialization. Once GLFW has been initialized, any values @@ -1652,7 +1691,7 @@ GLFWAPI void glfwTerminate(void); * * Some hints are platform specific. These may be set on any platform but they * will only affect their specific platform. Other platforms will ignore them. - * Setting these hints requires no platform specific headers or functions. + * Setting these hints requires no platform specific headers or functions. * * @param[in] hint The [init hint](@ref init_hints) to set. * @param[in] value The new value of the init hint. @@ -1666,7 +1705,6 @@ GLFWAPI void glfwTerminate(void); * * @sa init_hints * @sa glfwInit - * @sa glfwInitHintString * * @since Added in version 3.3. * @@ -1674,40 +1712,6 @@ GLFWAPI void glfwTerminate(void); */ GLFWAPI void glfwInitHint(int hint, int value); -/*! @brief Sets the specified init hint to the desired value. - * - * This function sets hints for the next initialization of GLFW. Only string - * type hints can be set with this function. - * - * The values you set hints to are never reset by GLFW, but they only take - * effect during initialization. Once GLFW has been initialized, any values - * you set will be ignored until the library is terminated and initialized - * again. - * - * Some hints are platform specific. These may be set on any platform but they - * will only affect their specific platform. Other platforms will ignore them. - * Setting these hints requires no platform specific headers or functions. - * - * @param[in] hint The [init hint](@ref init_hints) to set. - * @param[in] value The new value of the init hint. - * - * @errors Possible errors include @ref GLFW_INVALID_ENUM and @ref - * GLFW_INVALID_VALUE. - * - * @remarks This function may be called before @ref glfwInit. - * - * @thread_safety This function must only be called from the main thread. - * - * @sa init_hints - * @sa glfwInit - * @sa glfwInitHint - * - * @since Added in version 3.3. - * - * @ingroup init - */ -GLFWAPI void glfwInitHintString(int hint, const char* value); - /*! @brief Retrieves the version of the GLFW library. * * This function retrieves the major, minor and revision numbers of the GLFW @@ -2004,6 +2008,56 @@ GLFWAPI void glfwGetMonitorContentScale(GLFWmonitor* monitor, float* xscale, flo */ GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); +/*! @brief Sets the user pointer of the specified monitor. + * + * This function sets the user-defined pointer of the specified monitor. The + * current value is retained until the monitor is disconnected. The initial + * value is `NULL`. + * + * This function may be called from the monitor callback, even for a monitor + * that is being disconnected. + * + * @param[in] monitor The monitor whose pointer to set. + * @param[in] pointer The new value. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref monitor_userptr + * @sa @ref glfwGetMonitorUserPointer + * + * @since Added in version 3.3. + * + * @ingroup monitor + */ +GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* monitor, void* pointer); + +/*! @brief Returns the user pointer of the specified monitor. + * + * This function returns the current value of the user-defined pointer of the + * specified monitor. The initial value is `NULL`. + * + * This function may be called from the monitor callback, even for a monitor + * that is being disconnected. + * + * @param[in] monitor The monitor whose pointer to return. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref monitor_userptr + * @sa @ref glfwSetMonitorUserPointer + * + * @since Added in version 3.3. + * + * @ingroup monitor + */ +GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* monitor); + /*! @brief Sets the monitor configuration callback. * * This function sets the monitor configuration callback, or removes the @@ -2203,6 +2257,7 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); * * @sa @ref window_hints * @sa @ref glfwWindowHint + * @sa @ref glfwWindowHintString * * @since Added in version 3.0. * @@ -2213,14 +2268,20 @@ GLFWAPI void glfwDefaultWindowHints(void); /*! @brief Sets the specified window hint to the desired value. * * This function sets hints for the next call to @ref glfwCreateWindow. The - * hints, once set, retain their values until changed by a call to @ref - * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is - * terminated. + * hints, once set, retain their values until changed by a call to this + * function or @ref glfwDefaultWindowHints, or until the library is terminated. + * + * Only integer value hints can be set with this function. String value hints + * are set with @ref glfwWindowHintString. * * This function does not check whether the specified hint values are valid. * If you set hints to invalid values this will instead be reported by the next * call to @ref glfwCreateWindow. * + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. + * * @param[in] hint The [window hint](@ref window_hints) to set. * @param[in] value The new value of the window hint. * @@ -2230,6 +2291,7 @@ GLFWAPI void glfwDefaultWindowHints(void); * @thread_safety This function must only be called from the main thread. * * @sa @ref window_hints + * @sa @ref glfwWindowHintString * @sa @ref glfwDefaultWindowHints * * @since Added in version 3.0. Replaces `glfwOpenWindowHint`. @@ -2238,6 +2300,44 @@ GLFWAPI void glfwDefaultWindowHints(void); */ GLFWAPI void glfwWindowHint(int hint, int value); +/*! @brief Sets the specified window hint to the desired value. + * + * This function sets hints for the next call to @ref glfwCreateWindow. The + * hints, once set, retain their values until changed by a call to this + * function or @ref glfwDefaultWindowHints, or until the library is terminated. + * + * Only string type hints can be set with this function. Integer value hints + * are set with @ref glfwWindowHint. + * + * This function does not check whether the specified hint values are valid. + * If you set hints to invalid values this will instead be reported by the next + * call to @ref glfwCreateWindow. + * + * Some hints are platform specific. These may be set on any platform but they + * will only affect their specific platform. Other platforms will ignore them. + * Setting these hints requires no platform specific headers or functions. + * + * @param[in] hint The [window hint](@ref window_hints) to set. + * @param[in] value The new value of the window hint. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_INVALID_ENUM. + * + * @pointer_lifetime The specified string is copied before this function + * returns. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_hints + * @sa @ref glfwWindowHint + * @sa @ref glfwDefaultWindowHints + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwWindowHintString(int hint, const char* value); + /*! @brief Creates a window and its associated context. * * This function creates a window and its associated OpenGL or OpenGL ES @@ -2348,9 +2448,8 @@ GLFWAPI void glfwWindowHint(int hint, int value); * `CMake/MacOSXBundleInfo.plist.in` in the source tree. * * @remark @macos When activating frame autosaving with - * [GLFW_COCOA_FRAME_AUTOSAVE](@ref GLFW_COCOA_FRAME_AUTOSAVE_hint), the - * specified window size may be overriden by a previously saved size and - * position. + * [GLFW_COCOA_FRAME_NAME](@ref GLFW_COCOA_FRAME_NAME_hint), the specified + * window size and position may be overriden by previously saved values. * * @remark @x11 Some window managers will not respect the placement of * initially hidden windows. @@ -2360,10 +2459,12 @@ GLFWAPI void glfwWindowHint(int hint, int value); * query the final size, position or other attributes directly after window * creation. * - * @remark @x11 The name and class of the `WM_CLASS` window property will by - * default be set to the window title passed to this function. Set the @ref - * GLFW_X11_WM_CLASS_NAME and @ref GLFW_X11_WM_CLASS_CLASS init hints before - * initialization to override this. + * @remark @x11 The class part of the `WM_CLASS` window property will by + * default be set to the window title passed to this function. The instance + * part will use the contents of the `RESOURCE_NAME` environment variable, if + * present and not empty, or fall back to the window title. Set the @ref + * GLFW_X11_CLASS_NAME and @ref GLFW_X11_INSTANCE_NAME window hints to override + * this. * * @remark @wayland The window frame is currently unimplemented, as if * [GLFW_DECORATED](@ref GLFW_DECORATED_hint) was always set to `GLFW_FALSE`. @@ -2850,6 +2951,7 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int * @thread_safety This function must only be called from the main thread. * * @sa @ref window_scale + * @sa @ref glfwSetWindowContentScaleCallback * @sa @ref glfwGetMonitorContentScale * * @since Added in version 3.3. @@ -3224,7 +3326,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); * The supported attributes are [GLFW_DECORATED](@ref GLFW_DECORATED_attrib), * [GLFW_RESIZABLE](@ref GLFW_RESIZABLE_attrib), * [GLFW_FLOATING](@ref GLFW_FLOATING_attrib) and - * [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib). + * [GLFW_AUTO_ICONIFY](@ref GLFW_AUTO_ICONIFY_attrib). * * Some of these attributes are ignored for full screen windows. The new * value will take effect if the window is later made windowed. @@ -3512,6 +3614,30 @@ GLFWAPI GLFWwindowmaximizefun glfwSetWindowMaximizeCallback(GLFWwindow* window, */ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window, GLFWframebuffersizefun cbfun); +/*! @brief Sets the window content scale callback for the specified window. + * + * This function sets the window content scale callback of the specified window, + * which is called when the content scale of the specified window changes. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_scale + * @sa @ref glfwGetWindowContentScale + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* window, GLFWwindowcontentscalefun cbfun); + /*! @brief Processes all pending events. * * This function processes only those events that are already in the event @@ -3676,12 +3802,12 @@ GLFWAPI void glfwPostEmptyEvent(void); /*! @brief Returns the value of an input option for the specified window. * * This function returns the value of an input option for the specified window. - * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or - * @ref GLFW_STICKY_MOUSE_BUTTONS. + * The mode must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, + * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS. * * @param[in] window The window to query. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, + * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref * GLFW_INVALID_ENUM. @@ -3699,8 +3825,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); /*! @brief Sets an input option for the specified window. * * This function sets an input mode option for the specified window. The mode - * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS or - * @ref GLFW_STICKY_MOUSE_BUTTONS. + * must be one of @ref GLFW_CURSOR, @ref GLFW_STICKY_KEYS, + * @ref GLFW_STICKY_MOUSE_BUTTONS or @ref GLFW_LOCK_KEY_MODS. * * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor * modes: @@ -3726,9 +3852,15 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); * you are only interested in whether mouse buttons have been pressed but not * when or in which order. * + * If the mode is `GLFW_LOCK_KEY_MODS`, the value must be either `GLFW_TRUE` to + * enable lock key modifier bits, or `GLFW_FALSE` to disable them. If enabled, + * callbacks that receive modifier bits will also have the @ref + * GLFW_MOD_CAPS_LOCK bit set when the event was generated with Caps Lock on, + * and the @ref GLFW_MOD_NUM_LOCK bit when Num Lock was on. + * * @param[in] window The window whose input mode to set. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or - * `GLFW_STICKY_MOUSE_BUTTONS`. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS`, + * `GLFW_STICKY_MOUSE_BUTTONS` or `GLFW_LOCK_KEY_MODS`. * @param[in] value The new value of the specified input mode. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref @@ -4514,10 +4646,10 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count); * it with the corresponding direction. * * @code - * if (hats[2] & GLFW_HAT_RIGHT) - * { - * // State of hat 2 could be right-up, right or right-down - * } + * if (hats[2] & GLFW_HAT_RIGHT) + * { + * // State of hat 2 could be right-up, right or right-down + * } * @endcode * * If the specified joystick is not present this function will return `NULL` @@ -4621,6 +4753,56 @@ GLFWAPI const char* glfwGetJoystickName(int jid); */ GLFWAPI const char* glfwGetJoystickGUID(int jid); +/*! @brief Sets the user pointer of the specified joystick. + * + * This function sets the user-defined pointer of the specified joystick. The + * current value is retained until the joystick is disconnected. The initial + * value is `NULL`. + * + * This function may be called from the joystick callback, even for a joystick + * that is being disconnected. + * + * @param[in] joystick The joystick whose pointer to set. + * @param[in] pointer The new value. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref joystick_userptr + * @sa @ref glfwGetJoystickUserPointer + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer); + +/*! @brief Returns the user pointer of the specified joystick. + * + * This function returns the current value of the user-defined pointer of the + * specified joystick. The initial value is `NULL`. + * + * This function may be called from the joystick callback, even for a joystick + * that is being disconnected. + * + * @param[in] joystick The joystick whose pointer to return. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @sa @ref joystick_userptr + * @sa @ref glfwSetJoystickUserPointer + * + * @since Added in version 3.3. + * + * @ingroup input + */ +GLFWAPI void* glfwGetJoystickUserPointer(int jid); + /*! @brief Returns whether the specified joystick has a gamepad mapping. * * This function returns whether the specified joystick is both present and has @@ -4897,7 +5079,7 @@ GLFWAPI void glfwSetTime(double time); * 1 / frequency seconds. To get the frequency, call @ref * glfwGetTimerFrequency. * - * @return The value of the timer, or zero if an + * @return The value of the timer, or zero if an * [error](@ref error_handling) occurred. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 01c01053a..3d4e18fde 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -49,7 +49,7 @@ elseif (_GLFW_WAYLAND) BASENAME pointer-constraints-unstable-v1) ecm_add_wayland_client_protocol(glfw_SOURCES PROTOCOL - ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml + "${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml" BASENAME idle-inhibit-unstable-v1) elseif (_GLFW_MIR) set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index d5cc2379a..de4bae04c 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -88,9 +88,10 @@ typedef struct _GLFWwindowNS GLFWbool maximized; - // Cached window and framebuffer sizes used to filter out duplicate events + // Cached window properties to filter out duplicate events int width, height; int fbWidth, fbHeight; + float xscale, yscale; // The total sum of the distances the cursor has been warped // since the last cursor motion event was processed diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 68246342a..10d4a0c13 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -43,6 +43,7 @@ #define NSEventModifierFlagControl NSControlKeyMask #define NSEventModifierFlagOption NSAlternateKeyMask #define NSEventModifierFlagShift NSShiftKeyMask + #define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask #define NSEventModifierFlagDeviceIndependentFlagsMask NSDeviceIndependentModifierFlagsMask #define NSEventMaskAny NSAnyEventMask #define NSEventTypeApplicationDefined NSApplicationDefined @@ -177,6 +178,8 @@ static int translateFlags(NSUInteger flags) mods |= GLFW_MOD_ALT; if (flags & NSEventModifierFlagCommand) mods |= GLFW_MOD_SUPER; + if (flags & NSEventModifierFlagCapsLock) + mods |= GLFW_MOD_CAPS_LOCK; return mods; } @@ -571,6 +574,16 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; window->ns.fbHeight = fbRect.size.height; _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); } + + const float xscale = fbRect.size.width / contentRect.size.width; + const float yscale = fbRect.size.height / contentRect.size.height; + + if (xscale != window->ns.xscale || yscale != window->ns.yscale) + { + window->ns.xscale = xscale; + window->ns.yscale = yscale; + _glfwInputWindowContentScale(window, xscale, yscale); + } } - (void)drawRect:(NSRect)rect @@ -1093,8 +1106,8 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, [window->ns.object zoom:nil]; } - if (wndconfig->ns.frame) - [window->ns.object setFrameAutosaveName:[NSString stringWithUTF8String:wndconfig->title]]; + if (strlen(wndconfig->ns.frameName)) + [window->ns.object setFrameAutosaveName:[NSString stringWithUTF8String:wndconfig->ns.frameName]]; window->ns.view = [[GLFWContentView alloc] initWithGlfwWindow:window]; @@ -1475,6 +1488,20 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return [window->ns.object isZoomed]; } +int _glfwPlatformWindowHovered(_GLFWwindow* window) +{ + const NSPoint point = [NSEvent mouseLocation]; + + if ([NSWindow windowNumberAtPoint:point belowWindowWithWindowNumber:0] != + [window->ns.object windowNumber]) + { + return GLFW_FALSE; + } + + return NSPointInRect(point, + [window->ns.object convertRectToScreen:[window->ns.view bounds]]); +} + int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { return ![window->ns.object isOpaque] && ![window->ns.view isOpaque]; diff --git a/src/context.c b/src/context.c index 3842f0a37..212b34f9d 100644 --- a/src/context.c +++ b/src/context.c @@ -321,10 +321,11 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, return closest; } -GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) +GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig) { int i; - _GLFWwindow* window; + _GLFWwindow* previous; const char* version; const char* prefixes[] = { @@ -334,11 +335,12 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) NULL }; - window = _glfwPlatformGetTls(&_glfw.contextSlot); - window->context.source = ctxconfig->source; window->context.client = GLFW_OPENGL_API; + previous = _glfwPlatformGetTls(&_glfw.contextSlot);; + glfwMakeContextCurrent((GLFWwindow*) window); + window->context.GetIntegerv = (PFNGLGETINTEGERVPROC) window->context.getProcAddress("glGetIntegerv"); window->context.GetString = (PFNGLGETSTRINGPROC) @@ -346,6 +348,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) if (!window->context.GetIntegerv || !window->context.GetString) { _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); + glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_FALSE; } @@ -363,6 +366,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) "OpenGL ES version string retrieval is broken"); } + glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_FALSE; } @@ -394,6 +398,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) "No version found in OpenGL ES version string"); } + glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_FALSE; } @@ -423,6 +428,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) window->context.major, window->context.minor); } + glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_FALSE; } @@ -438,6 +444,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) { _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); + glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_FALSE; } } @@ -544,6 +551,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) window->context.swapBuffers(window); } + glfwMakeContextCurrent((GLFWwindow*) previous); return GLFW_TRUE; } diff --git a/src/init.c b/src/init.c index ae82831bf..99080b113 100644 --- a/src/init.c +++ b/src/init.c @@ -53,10 +53,6 @@ static _GLFWinitconfig _glfwInitHints = { GLFW_TRUE, // macOS menu bar GLFW_TRUE // macOS bundle chdir - }, - { - "", // X11 WM_CLASS name - "" // X11 WM_CLASS class } }; @@ -260,27 +256,7 @@ GLFWAPI void glfwInitHint(int hint, int value) } _glfwInputError(GLFW_INVALID_ENUM, - "Invalid integer type init hint 0x%08X", hint); -} - -GLFWAPI void glfwInitHintString(int hint, const char* value) -{ - assert(value != NULL); - - switch (hint) - { - case GLFW_X11_WM_CLASS_NAME: - strncpy(_glfwInitHints.x11.className, value, - sizeof(_glfwInitHints.x11.className) - 1); - return; - case GLFW_X11_WM_CLASS_CLASS: - strncpy(_glfwInitHints.x11.classClass, value, - sizeof(_glfwInitHints.x11.classClass) - 1); - return; - } - - _glfwInputError(GLFW_INVALID_ENUM, - "Invalid string type init hint 0x%08X", hint); + "Invalid init hint 0x%08X", hint); } GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev) diff --git a/src/input.c b/src/input.c index 40a5e1175..870f979f4 100644 --- a/src/input.c +++ b/src/input.c @@ -57,6 +57,58 @@ static _GLFWmapping* findMapping(const char* guid) return NULL; } +// Checks whether a gamepad mapping element is present in the hardware +// +static GLFWbool isValidElementForJoystick(const _GLFWmapelement* e, + const _GLFWjoystick* js) +{ + if (e->type == _GLFW_JOYSTICK_HATBIT && (e->value >> 4) >= js->hatCount) + return GLFW_FALSE; + else if (e->type == _GLFW_JOYSTICK_BUTTON && e->value >= js->buttonCount) + return GLFW_FALSE; + else if (e->type == _GLFW_JOYSTICK_AXIS && e->value >= js->axisCount) + return GLFW_FALSE; + + return GLFW_TRUE; +} + +// Finds a mapping based on joystick GUID and verifies element indices +// +static _GLFWmapping* findValidMapping(const _GLFWjoystick* js) +{ + _GLFWmapping* mapping = findMapping(js->guid); + if (mapping) + { + int i; + + for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) + { + if (!isValidElementForJoystick(mapping->buttons + i, js)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid button in gamepad mapping %s (%s)", + mapping->guid, + mapping->name); + return NULL; + } + } + + for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) + { + if (!isValidElementForJoystick(mapping->axes + i, js)) + { + _glfwInputError(GLFW_INVALID_VALUE, + "Invalid axis in gamepad mapping %s (%s)", + mapping->guid, + mapping->name); + return NULL; + } + } + } + + return mapping; +} + // Parses an SDL_GameControllerDB line and adds it to the mapping list // static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) @@ -193,6 +245,9 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m action = GLFW_REPEAT; } + if (!window->lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + if (window->callbacks.key) window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods); } @@ -202,6 +257,9 @@ void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWb if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) return; + if (!window->lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + if (window->callbacks.charmods) window->callbacks.charmods((GLFWwindow*) window, codepoint, mods); @@ -223,6 +281,9 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) return; + if (!window->lockKeyMods) + mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + if (action == GLFW_RELEASE && window->stickyMouseButtons) window->mouseButtons[button] = _GLFW_STICK; else @@ -328,9 +389,9 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name, js->axisCount = axisCount; js->buttonCount = buttonCount; js->hatCount = hatCount; - js->mapping = findMapping(guid); strcpy(js->guid, guid); + js->mapping = findValidMapping(js); return js; } @@ -364,6 +425,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) return window->stickyKeys; case GLFW_STICKY_MOUSE_BUTTONS: return window->stickyMouseButtons; + case GLFW_LOCK_KEY_MODS: + return window->lockKeyMods; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); @@ -419,7 +482,7 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) } } - window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE; + window->stickyKeys = value; } else if (mode == GLFW_STICKY_MOUSE_BUTTONS) { @@ -439,8 +502,10 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) } } - window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE; + window->stickyMouseButtons = value; } + else if (mode == GLFW_LOCK_KEY_MODS) + window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; else _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); } @@ -948,6 +1013,38 @@ GLFWAPI const char* glfwGetJoystickGUID(int jid) return js->guid; } +GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer) +{ + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + _GLFW_REQUIRE_INIT(); + + js = _glfw.joysticks + jid; + if (!js->present) + return; + + js->userPointer = pointer; +} + +GLFWAPI void* glfwGetJoystickUserPointer(int jid) +{ + _GLFWjoystick* js; + + assert(jid >= GLFW_JOYSTICK_1); + assert(jid <= GLFW_JOYSTICK_LAST); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + + js = _glfw.joysticks + jid; + if (!js->present) + return NULL; + + return js->userPointer; +} + GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -1007,7 +1104,7 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string) { _GLFWjoystick* js = _glfw.joysticks + jid; if (js->present) - js->mapping = findMapping(js->guid); + js->mapping = findValidMapping(js); } return GLFW_TRUE; @@ -1119,8 +1216,8 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) state->axes[i] = js->axes[js->mapping->axes[i].value]; else if (js->mapping->buttons[i].type == _GLFW_JOYSTICK_HATBIT) { - const unsigned int hat = js->mapping->buttons[i].value >> 4; - const unsigned int bit = js->mapping->buttons[i].value & 0xf; + const unsigned int hat = js->mapping->axes[i].value >> 4; + const unsigned int bit = js->mapping->axes[i].value & 0xf; if (js->hats[hat] & bit) state->axes[i] = 1.f; } diff --git a/src/internal.h b/src/internal.h index 34657e01d..1405f82eb 100644 --- a/src/internal.h +++ b/src/internal.h @@ -281,10 +281,6 @@ struct _GLFWinitconfig GLFWbool menubar; GLFWbool chdir; } ns; - struct { - char className[256]; - char classClass[256]; - } x11; }; /*! @brief Window configuration. @@ -308,8 +304,12 @@ struct _GLFWwndconfig GLFWbool centerCursor; struct { GLFWbool retina; - GLFWbool frame; + char frameName[256]; } ns; + struct { + char className[256]; + char instanceName[256]; + } x11; }; /*! @brief Context configuration. @@ -419,9 +419,13 @@ struct _GLFWwindow GLFWbool stickyKeys; GLFWbool stickyMouseButtons; + double penPressure; int penXposition; int penYposition; + + GLFWbool lockKeyMods; + int cursorMode; char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1]; char keys[GLFW_KEY_LAST + 1]; @@ -439,6 +443,7 @@ struct _GLFWwindow GLFWwindowiconifyfun iconify; GLFWwindowmaximizefun maximize; GLFWframebuffersizefun fbsize; + GLFWwindowcontentscalefun scale; GLFWmousebuttonfun mouseButton; GLFWpenpressurefun penPressure; GLFWcursorposfun cursorPos; @@ -459,6 +464,7 @@ struct _GLFWwindow struct _GLFWmonitor { char* name; + void* userPointer; // Physical dimensions in millimeters. int widthMM, heightMM; @@ -517,6 +523,7 @@ struct _GLFWjoystick unsigned char* hats; int hatCount; char* name; + void* userPointer; char guid[33]; _GLFWmapping* mapping; @@ -690,6 +697,7 @@ int _glfwPlatformWindowFocused(_GLFWwindow* window); int _glfwPlatformWindowIconified(_GLFWwindow* window); int _glfwPlatformWindowVisible(_GLFWwindow* window); int _glfwPlatformWindowMaximized(_GLFWwindow* window); +int _glfwPlatformWindowHovered(_GLFWwindow* window); int _glfwPlatformFramebufferTransparent(_GLFWwindow* window); float _glfwPlatformGetWindowOpacity(_GLFWwindow* window); void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled); @@ -755,6 +763,14 @@ void _glfwInputWindowSize(_GLFWwindow* window, int width, int height); */ void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height); +/*! @brief Notifies shared code that a window content scale has changed. + * @param[in] window The window that received the event. + * @param[in] xscale The new x-axis content scale of the window. + * @param[in] yscale The new y-axis content scale of the window. + * @ingroup event + */ +void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscale); + /*! @brief Notifies shared code that a window has been iconified or restored. * @param[in] window The window that received the event. * @param[in] iconified `GLFW_TRUE` if the window was iconified, or @@ -964,7 +980,8 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, * unusable. * @ingroup utility */ -GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig); +GLFWbool _glfwRefreshContextAttribs(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig); /*! @brief Checks whether the desired context attributes are valid. * @param[in] ctxconfig The context attributes to check. diff --git a/src/mappings.h b/src/mappings.h index dd7476085..9563df835 100644 --- a/src/mappings.h +++ b/src/mappings.h @@ -51,7 +51,7 @@ // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. +// be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. diff --git a/src/mappings.h.in b/src/mappings.h.in index 207d40b9f..eb6c32f7c 100644 --- a/src/mappings.h.in +++ b/src/mappings.h.in @@ -51,7 +51,7 @@ // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would -// be appreciated but is not required. +// be appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. diff --git a/src/mir_window.c b/src/mir_window.c index fd8f2914d..a0d17db2e 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -117,12 +117,16 @@ static int mirModToGLFWMod(uint32_t mods) if (mods & mir_input_event_modifier_alt) publicMods |= GLFW_MOD_ALT; - else if (mods & mir_input_event_modifier_shift) + if (mods & mir_input_event_modifier_shift) publicMods |= GLFW_MOD_SHIFT; - else if (mods & mir_input_event_modifier_ctrl) + if (mods & mir_input_event_modifier_ctrl) publicMods |= GLFW_MOD_CONTROL; - else if (mods & mir_input_event_modifier_meta) + if (mods & mir_input_event_modifier_meta) publicMods |= GLFW_MOD_SUPER; + if (mods & mir_input_event_modifier_caps_lock) + publicMods |= GLFW_MOD_CAPS_LOCK; + if (mods & mir_input_event_modifier_num_lock) + publicMods |= GLFW_MOD_NUM_LOCK; return publicMods; } @@ -623,6 +627,13 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return mir_window_get_state(window->mir.window) == mir_window_state_maximized; } +int _glfwPlatformWindowHovered(_GLFWwindow* window) +{ + _glfwInputError(GLFW_PLATFORM_ERROR, + "Mir: Unsupported function %s", __PRETTY_FUNCTION__); + return GLFW_FALSE; +} + int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/monitor.c b/src/monitor.c index 6f64cca5d..21e52723a 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -351,6 +351,24 @@ GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* handle) return monitor->name; } +GLFWAPI void glfwSetMonitorUserPointer(GLFWmonitor* handle, void* pointer) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + _GLFW_REQUIRE_INIT(); + monitor->userPointer = pointer; +} + +GLFWAPI void* glfwGetMonitorUserPointer(GLFWmonitor* handle) +{ + _GLFWmonitor* monitor = (_GLFWmonitor*) handle; + assert(monitor != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + return monitor->userPointer; +} + GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -406,16 +424,16 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* handle, float gamma) for (i = 0; i < 256; i++) { - double value; + float value; // Calculate intensity - value = i / 255.0; + value = i / 255.f; // Apply gamma curve - value = pow(value, 1.0 / gamma) * 65535.0 + 0.5; + value = powf(value, 1.f / gamma) * 65535.f + 0.5f; // Clamp to value range - if (value > 65535.0) - value = 65535.0; + if (value > 65535.f) + value = 65535.f; values[i] = (unsigned short) value; } diff --git a/src/null_window.c b/src/null_window.c index 6eb4ac6e2..6a54cfe56 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -165,6 +165,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return GLFW_FALSE; } +int _glfwPlatformWindowHovered(_GLFWwindow* window) +{ + return GLFW_FALSE; +} + int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { return GLFW_FALSE; diff --git a/src/wgl_context.c b/src/wgl_context.c index d864a47cc..beccb13ed 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -329,21 +329,52 @@ static void destroyContextWGL(_GLFWwindow* window) } } -// Initialize WGL-specific extensions + +////////////////////////////////////////////////////////////////////////// +////// GLFW internal API ////// +////////////////////////////////////////////////////////////////////////// + +// Initialize WGL // -static void loadWGLExtensions(void) +GLFWbool _glfwInitWGL(void) { PIXELFORMATDESCRIPTOR pfd; - HGLRC rc; - HDC dc = GetDC(_glfw.win32.helperWindowHandle);; + HGLRC prc, rc; + HDC pdc, dc; - _glfw.wgl.extensionsLoaded = GLFW_TRUE; + if (_glfw.wgl.instance) + return GLFW_TRUE; + + _glfw.wgl.instance = LoadLibraryA("opengl32.dll"); + if (!_glfw.wgl.instance) + { + _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, + "WGL: Failed to load opengl32.dll"); + return GLFW_FALSE; + } + + _glfw.wgl.CreateContext = (PFN_wglCreateContext) + GetProcAddress(_glfw.wgl.instance, "wglCreateContext"); + _glfw.wgl.DeleteContext = (PFN_wglDeleteContext) + GetProcAddress(_glfw.wgl.instance, "wglDeleteContext"); + _glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress) + GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress"); + _glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC) + GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC"); + _glfw.wgl.GetCurrentContext = (PFN_wglGetCurrentContext) + GetProcAddress(_glfw.wgl.instance, "wglGetCurrentContext"); + _glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent) + GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent"); + _glfw.wgl.ShareLists = (PFN_wglShareLists) + GetProcAddress(_glfw.wgl.instance, "wglShareLists"); // NOTE: A dummy context has to be created for opengl32.dll to load the // OpenGL ICD, from which we can then query WGL extensions // NOTE: This code will accept the Microsoft GDI ICD; accelerated context // creation failure occurs during manual pixel format enumeration + dc = GetDC(_glfw.win32.helperWindowHandle);; + ZeroMemory(&pfd, sizeof(pfd)); pfd.nSize = sizeof(pfd); pfd.nVersion = 1; @@ -355,7 +386,7 @@ static void loadWGLExtensions(void) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to set pixel format for dummy context"); - return; + return GLFW_FALSE; } rc = wglCreateContext(dc); @@ -363,15 +394,19 @@ static void loadWGLExtensions(void) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to create dummy context"); - return; + return GLFW_FALSE; } + pdc = wglGetCurrentDC(); + prc = wglGetCurrentContext(); + if (!wglMakeCurrent(dc, rc)) { _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, "WGL: Failed to make dummy context current"); + wglMakeCurrent(pdc, prc); wglDeleteContext(rc); - return; + return GLFW_FALSE; } // NOTE: Functions must be loaded first as they're needed to retrieve the @@ -414,43 +449,8 @@ static void loadWGLExtensions(void) _glfw.wgl.ARB_context_flush_control = extensionSupportedWGL("WGL_ARB_context_flush_control"); - wglMakeCurrent(dc, NULL); + wglMakeCurrent(pdc, prc); wglDeleteContext(rc); -} - - -////////////////////////////////////////////////////////////////////////// -////// GLFW internal API ////// -////////////////////////////////////////////////////////////////////////// - -// Initialize WGL -// -GLFWbool _glfwInitWGL(void) -{ - if (_glfw.wgl.instance) - return GLFW_TRUE; - - _glfw.wgl.instance = LoadLibraryA("opengl32.dll"); - if (!_glfw.wgl.instance) - { - _glfwInputErrorWin32(GLFW_PLATFORM_ERROR, - "WGL: Failed to load opengl32.dll"); - return GLFW_FALSE; - } - - _glfw.wgl.CreateContext = (PFN_wglCreateContext) - GetProcAddress(_glfw.wgl.instance, "wglCreateContext"); - _glfw.wgl.DeleteContext = (PFN_wglDeleteContext) - GetProcAddress(_glfw.wgl.instance, "wglDeleteContext"); - _glfw.wgl.GetProcAddress = (PFN_wglGetProcAddress) - GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress"); - _glfw.wgl.GetCurrentDC = (PFN_wglGetCurrentDC) - GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC"); - _glfw.wgl.MakeCurrent = (PFN_wglMakeCurrent) - GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent"); - _glfw.wgl.ShareLists = (PFN_wglShareLists) - GetProcAddress(_glfw.wgl.instance, "wglShareLists"); - return GLFW_TRUE; } @@ -480,9 +480,6 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, PIXELFORMATDESCRIPTOR pfd; HGLRC share = NULL; - if (!_glfw.wgl.extensionsLoaded) - loadWGLExtensions(); - if (ctxconfig->share) share = ctxconfig->share->context.wgl.handle; diff --git a/src/wgl_context.h b/src/wgl_context.h index 9fae91141..c7540386b 100644 --- a/src/wgl_context.h +++ b/src/wgl_context.h @@ -86,6 +86,7 @@ typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC); typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC); typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR); typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void); +typedef HGLRC (WINAPI * PFN_wglGetCurrentContext)(void); typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC); typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC); @@ -94,6 +95,7 @@ typedef BOOL (WINAPI * PFN_wglShareLists)(HGLRC,HGLRC); #define wglDeleteContext _glfw.wgl.DeleteContext #define wglGetProcAddress _glfw.wgl.GetProcAddress #define wglGetCurrentDC _glfw.wgl.GetCurrentDC +#define wglGetCurrentContext _glfw.wgl.GetCurrentContext #define wglMakeCurrent _glfw.wgl.MakeCurrent #define wglShareLists _glfw.wgl.ShareLists @@ -124,11 +126,10 @@ typedef struct _GLFWlibraryWGL PFN_wglDeleteContext DeleteContext; PFN_wglGetProcAddress GetProcAddress; PFN_wglGetCurrentDC GetCurrentDC; + PFN_wglGetCurrentContext GetCurrentContext; PFN_wglMakeCurrent MakeCurrent; PFN_wglShareLists ShareLists; - GLFWbool extensionsLoaded; - PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT; PFNWGLGETPIXELFORMATATTRIBIVARBPROC GetPixelFormatAttribivARB; PFNWGLGETEXTENSIONSSTRINGEXTPROC GetExtensionsStringEXT; diff --git a/src/win32_init.c b/src/win32_init.c index ee7ccfdaa..a913846d4 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -351,9 +351,10 @@ static HWND createHelperWindow(void) dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; dbi.dbcc_classguid = GUID_DEVINTERFACE_HID; - RegisterDeviceNotificationW(window, - (DEV_BROADCAST_HDR*) &dbi, - DEVICE_NOTIFY_WINDOW_HANDLE); + _glfw.win32.deviceNotificationHandle = + RegisterDeviceNotificationW(window, + (DEV_BROADCAST_HDR*) &dbi, + DEVICE_NOTIFY_WINDOW_HANDLE); } while (PeekMessageW(&msg, _glfw.win32.helperWindowHandle, 0, 0, PM_REMOVE)) @@ -543,6 +544,9 @@ int _glfwPlatformInit(void) void _glfwPlatformTerminate(void) { + if (_glfw.win32.deviceNotificationHandle) + UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle); + if (_glfw.win32.helperWindowHandle) DestroyWindow(_glfw.win32.helperWindowHandle); diff --git a/src/win32_platform.h b/src/win32_platform.h index d7464c545..49c68480a 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -188,12 +188,11 @@ WINUSERAPI BOOL WINAPI GetPointerInfo(UINT32,POINTER_INFO*); #endif /*Windows 8 and above*/ #if WINVER < 0x0601 -typedef struct tagCHANGEFILTERSTRUCT +typedef struct { DWORD cbSize; DWORD ExtStatus; - -} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT; +} CHANGEFILTERSTRUCT; #ifndef MSGFLT_ALLOW #define MSGFLT_ALLOW 1 #endif @@ -212,13 +211,13 @@ typedef struct #endif /*Windows Vista*/ #ifndef DPI_ENUMS_DECLARED -typedef enum PROCESS_DPI_AWARENESS +typedef enum { PROCESS_DPI_UNAWARE = 0, PROCESS_SYSTEM_DPI_AWARE = 1, PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS; -typedef enum MONITOR_DPI_TYPE +typedef enum { MDT_EFFECTIVE_DPI = 0, MDT_ANGULAR_DPI = 1, @@ -292,7 +291,7 @@ typedef HRESULT (WINAPI * PFN_DirectInput8Create)(HINSTANCE,DWORD,REFIID,LPVOID* // user32.dll function pointer typedefs typedef BOOL (WINAPI * PFN_SetProcessDPIAware)(void); -typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); +typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,CHANGEFILTERSTRUCT*); #define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_ #define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_ @@ -372,6 +371,7 @@ typedef struct _GLFWwindowWin32 typedef struct _GLFWlibraryWin32 { HWND helperWindowHandle; + HDEVNOTIFY deviceNotificationHandle; DWORD foregroundLockTimeout; int acquiredMonitorCount; char* clipboardString; diff --git a/src/win32_window.c b/src/win32_window.c index 2e3feed56..f0c1ce268 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -386,14 +386,18 @@ static int getKeyMods(void) { int mods = 0; - if (GetKeyState(VK_SHIFT) & (1 << 31)) + if (GetKeyState(VK_SHIFT) & 0x8000) mods |= GLFW_MOD_SHIFT; - if (GetKeyState(VK_CONTROL) & (1 << 31)) + if (GetKeyState(VK_CONTROL) & 0x8000) mods |= GLFW_MOD_CONTROL; - if (GetKeyState(VK_MENU) & (1 << 31)) + if (GetKeyState(VK_MENU) & 0x8000) mods |= GLFW_MOD_ALT; - if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1 << 31)) + if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & 0x8000) mods |= GLFW_MOD_SUPER; + if (GetKeyState(VK_CAPITAL) & 1) + mods |= GLFW_MOD_CAPS_LOCK; + if (GetKeyState(VK_NUMLOCK) & 1) + mods |= GLFW_MOD_NUM_LOCK; return mods; } @@ -404,14 +408,18 @@ static int getAsyncKeyMods(void) { int mods = 0; - if (GetAsyncKeyState(VK_SHIFT) & (1 << 31)) + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) mods |= GLFW_MOD_SHIFT; - if (GetAsyncKeyState(VK_CONTROL) & (1 << 31)) + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) mods |= GLFW_MOD_CONTROL; - if (GetAsyncKeyState(VK_MENU) & (1 << 31)) + if (GetAsyncKeyState(VK_MENU) & 0x8000) mods |= GLFW_MOD_ALT; - if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & (1 << 31)) + if ((GetAsyncKeyState(VK_LWIN) | GetAsyncKeyState(VK_RWIN)) & 0x8000) mods |= GLFW_MOD_SUPER; + if (GetAsyncKeyState(VK_CAPITAL) & 1) + mods |= GLFW_MOD_CAPS_LOCK; + if (GetAsyncKeyState(VK_NUMLOCK) & 1) + mods |= GLFW_MOD_NUM_LOCK; return mods; } @@ -1051,6 +1059,14 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, return 0; } + case WM_DPICHANGED: + { + const float xscale = HIWORD(wParam) / 96.f; + const float yscale = LOWORD(wParam) / 96.f; + _glfwInputWindowContentScale(window, xscale, yscale); + break; + } + case WM_SETCURSOR: { if (LOWORD(lParam) == HTCLIENT) @@ -1506,7 +1522,7 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window) void _glfwPlatformShowWindow(_GLFWwindow* window) { - ShowWindow(window->win32.handle, SW_SHOW); + ShowWindow(window->win32.handle, SW_SHOWNA); } void _glfwPlatformHideWindow(_GLFWwindow* window) @@ -1625,6 +1641,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return IsZoomed(window->win32.handle); } +int _glfwPlatformWindowHovered(_GLFWwindow* window) +{ + return cursorInClientArea(window); +} + int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { return window->win32.transparent && _glfwIsCompositionEnabledWin32(); diff --git a/src/window.c b/src/window.c index 27684f74d..5949c37fd 100644 --- a/src/window.c +++ b/src/window.c @@ -93,6 +93,12 @@ void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height) window->callbacks.fbsize((GLFWwindow*) window, width, height); } +void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscale) +{ + if (window->callbacks.scale) + window->callbacks.scale((GLFWwindow*) window, xscale, yscale); +} + void _glfwInputWindowDamage(_GLFWwindow* window) { if (window->callbacks.refresh) @@ -126,7 +132,6 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, _GLFWctxconfig ctxconfig; _GLFWwndconfig wndconfig; _GLFWwindow* window; - _GLFWwindow* previous; assert(title != NULL); assert(width >= 0); @@ -190,33 +195,20 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->numer = GLFW_DONT_CARE; window->denom = GLFW_DONT_CARE; - // Save the currently current context so it can be restored later - previous = _glfwPlatformGetTls(&_glfw.contextSlot); - if (ctxconfig.client != GLFW_NO_API) - glfwMakeContextCurrent(NULL); - // Open the actual window and create its context if (!_glfwPlatformCreateWindow(window, &wndconfig, &ctxconfig, &fbconfig)) { - glfwMakeContextCurrent((GLFWwindow*) previous); glfwDestroyWindow((GLFWwindow*) window); return NULL; } if (ctxconfig.client != GLFW_NO_API) { - window->context.makeCurrent(window); - - // Retrieve the actual (as opposed to requested) context attributes - if (!_glfwRefreshContextAttribs(&ctxconfig)) + if (!_glfwRefreshContextAttribs(window, &ctxconfig)) { - glfwMakeContextCurrent((GLFWwindow*) previous); glfwDestroyWindow((GLFWwindow*) window); return NULL; } - - // Restore the previously current context (or NULL) - glfwMakeContextCurrent((GLFWwindow*) previous); } if (!window->monitor) @@ -348,9 +340,6 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_COCOA_RETINA_FRAMEBUFFER: _glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE; return; - case GLFW_COCOA_FRAME_AUTOSAVE: - _glfw.hints.window.ns.frame = value ? GLFW_TRUE : GLFW_FALSE; - return; case GLFW_COCOA_GRAPHICS_SWITCHING: _glfw.hints.context.nsgl.offline = value ? GLFW_TRUE : GLFW_FALSE; return; @@ -395,6 +384,31 @@ GLFWAPI void glfwWindowHint(int hint, int value) _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint); } +GLFWAPI void glfwWindowHintString(int hint, const char* value) +{ + assert(value != NULL); + + _GLFW_REQUIRE_INIT(); + + switch (hint) + { + case GLFW_COCOA_FRAME_NAME: + strncpy(_glfw.hints.window.ns.frameName, value, + sizeof(_glfw.hints.window.ns.frameName) - 1); + return; + case GLFW_X11_CLASS_NAME: + strncpy(_glfw.hints.window.x11.className, value, + sizeof(_glfw.hints.window.x11.className) - 1); + return; + case GLFW_X11_INSTANCE_NAME: + strncpy(_glfw.hints.window.x11.instanceName, value, + sizeof(_glfw.hints.window.x11.instanceName) - 1); + return; + } + + _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint); +} + GLFWAPI void glfwDestroyWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; @@ -770,6 +784,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return _glfwPlatformWindowVisible(window); case GLFW_MAXIMIZED: return _glfwPlatformWindowMaximized(window); + case GLFW_HOVERED: + return _glfwPlatformWindowHovered(window); case GLFW_TRANSPARENT_FRAMEBUFFER: return _glfwPlatformFramebufferTransparent(window); case GLFW_RESIZABLE: @@ -1004,6 +1020,17 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* handle return cbfun; } +GLFWAPI GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback(GLFWwindow* handle, + GLFWwindowcontentscalefun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.scale, cbfun); + return cbfun; +} + GLFWAPI void glfwPollEvents(void) { _GLFW_REQUIRE_INIT(); diff --git a/src/wl_init.c b/src/wl_init.c index ec25f206b..c80519021 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -54,6 +54,8 @@ static void pointerHandleEnter(void* data, _glfw.wl.pointerSerial = serial; _glfw.wl.pointerFocus = window; + window->wl.hovered = GLFW_TRUE; + _glfwPlatformSetCursor(window, window->wl.currentCursor); _glfwInputCursorEnter(window, GLFW_TRUE); } @@ -68,6 +70,8 @@ static void pointerHandleLeave(void* data, if (!window) return; + window->wl.hovered = GLFW_FALSE; + _glfw.wl.pointerSerial = serial; _glfw.wl.pointerFocus = NULL; _glfwInputCursorEnter(window, GLFW_FALSE); @@ -137,6 +141,9 @@ static void pointerHandleAxis(void* data, if (!window) return; + assert(axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL || + axis == WL_POINTER_AXIS_VERTICAL_SCROLL); + /* Wayland scroll events are in pointer motion coordinate space (think * two finger scroll). The factor 10 is commonly used to convert to * "scroll step means 1.0. */ @@ -152,9 +159,6 @@ static void pointerHandleAxis(void* data, x = 0.0; y = wl_fixed_to_double(value) * scrollFactor; break; - default: - assert(GLFW_FALSE); - break; } _glfwInputScroll(window, x, y); @@ -264,6 +268,10 @@ static void keyboardHandleKeymap(void* data, 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Shift"); _glfw.wl.xkb.superMask = 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod4"); + _glfw.wl.xkb.capsLockMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Lock"); + _glfw.wl.xkb.numLockMask = + 1 << xkb_keymap_mod_get_index(_glfw.wl.xkb.keymap, "Mod2"); } static void keyboardHandleEnter(void* data, @@ -409,6 +417,10 @@ static void keyboardHandleModifiers(void* data, modifiers |= GLFW_MOD_SHIFT; if (mask & _glfw.wl.xkb.superMask) modifiers |= GLFW_MOD_SUPER; + if (mask & _glfw.wl.xkb.capsLockMask) + modifiers |= GLFW_MOD_CAPS_LOCK; + if (mask & _glfw.wl.xkb.numLockMask) + modifiers |= GLFW_MOD_NUM_LOCK; _glfw.wl.xkb.modifiers = modifiers; } @@ -763,15 +775,22 @@ void _glfwPlatformTerminate(void) _glfwTerminateJoysticksLinux(); #ifdef HAVE_XKBCOMMON_COMPOSE_H - xkb_compose_state_unref(_glfw.wl.xkb.composeState); + if (_glfw.wl.xkb.composeState) + xkb_compose_state_unref(_glfw.wl.xkb.composeState); #endif - xkb_keymap_unref(_glfw.wl.xkb.keymap); - xkb_state_unref(_glfw.wl.xkb.state); - xkb_context_unref(_glfw.wl.xkb.context); + if (_glfw.wl.xkb.keymap) + xkb_keymap_unref(_glfw.wl.xkb.keymap); + if (_glfw.wl.xkb.state) + xkb_state_unref(_glfw.wl.xkb.state); + if (_glfw.wl.xkb.context) + xkb_context_unref(_glfw.wl.xkb.context); - dlclose(_glfw.wl.xkb.handle); - _glfw.wl.xkb.handle = NULL; + if (_glfw.wl.xkb.handle) + { + _glfw_dlclose(_glfw.wl.xkb.handle); + _glfw.wl.xkb.handle = NULL; + } if (_glfw.wl.cursorTheme) wl_cursor_theme_destroy(_glfw.wl.cursorTheme); diff --git a/src/wl_platform.h b/src/wl_platform.h index 516c84be8..534998124 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -117,6 +117,7 @@ typedef struct _GLFWwindowWayland int width, height; GLFWbool visible; GLFWbool maximized; + GLFWbool hovered; GLFWbool transparent; struct wl_surface* surface; struct wl_egl_window* native; @@ -183,6 +184,8 @@ typedef struct _GLFWlibraryWayland xkb_mod_mask_t altMask; xkb_mod_mask_t shiftMask; xkb_mod_mask_t superMask; + xkb_mod_mask_t capsLockMask; + xkb_mod_mask_t numLockMask; unsigned int modifiers; PFN_xkb_context_new context_new; diff --git a/src/wl_window.c b/src/wl_window.c index 9759ba26f..57e6f2ad0 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -125,6 +125,7 @@ static void checkScaleChange(_GLFWwindow* window) wl_surface_set_buffer_scale(window->wl.surface, scale); wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0); _glfwInputFramebufferSize(window, scaledWidth, scaledHeight); + _glfwInputWindowContentScale(window, scale, scale); } } @@ -692,6 +693,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return window->wl.maximized; } +int _glfwPlatformWindowHovered(_GLFWwindow* window) +{ + return window->wl.hovered; +} + int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { return window->wl.transparent; diff --git a/src/x11_window.c b/src/x11_window.c index 32fff63b6..1520b8256 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -212,6 +212,10 @@ static int translateState(int state) mods |= GLFW_MOD_ALT; if (state & Mod4Mask) mods |= GLFW_MOD_SUPER; + if (state & LockMask) + mods |= GLFW_MOD_CAPS_LOCK; + if (state & Mod2Mask) + mods |= GLFW_MOD_NUM_LOCK; return mods; } @@ -707,21 +711,26 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, { XClassHint* hint = XAllocClassHint(); - if (strlen(_glfw.hints.init.x11.className) && - strlen(_glfw.hints.init.x11.classClass)) + if (strlen(wndconfig->x11.instanceName) && + strlen(wndconfig->x11.className)) { - hint->res_name = (char*) _glfw.hints.init.x11.className; - hint->res_class = (char*) _glfw.hints.init.x11.classClass; - } - else if (strlen(wndconfig->title)) - { - hint->res_name = (char*) wndconfig->title; - hint->res_class = (char*) wndconfig->title; + hint->res_name = (char*) wndconfig->x11.instanceName; + hint->res_class = (char*) wndconfig->x11.className; } else { - hint->res_name = (char*) "glfw-application"; - hint->res_class = (char*) "GLFW-Application"; + const char* resourceName = getenv("RESOURCE_NAME"); + if (resourceName && strlen(resourceName)) + hint->res_name = (char*) resourceName; + else if (strlen(wndconfig->title)) + hint->res_name = (char*) wndconfig->title; + else + hint->res_name = (char*) "glfw-application"; + + if (strlen(wndconfig->title)) + hint->res_class = (char*) wndconfig->title; + else + hint->res_class = (char*) "GLFW-Application"; } XSetClassHint(_glfw.x11.display, window->x11.handle, hint); @@ -2444,6 +2453,28 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window) return maximized; } +int _glfwPlatformWindowHovered(_GLFWwindow* window) +{ + Window w = _glfw.x11.root; + while (w) + { + Window root; + int rootX, rootY, childX, childY; + unsigned int mask; + + if (!XQueryPointer(_glfw.x11.display, w, + &root, &w, &rootX, &rootY, &childX, &childY, &mask)) + { + return GLFW_FALSE; + } + + if (w == window->x11.handle) + return GLFW_TRUE; + } + + return GLFW_FALSE; +} + int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) { if (!window->x11.transparent) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 52b08389d..a9900a0d4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -33,7 +33,7 @@ add_executable(icon WIN32 MACOSX_BUNDLE icon.c ${GLAD}) add_executable(inputlag WIN32 MACOSX_BUNDLE inputlag.c ${GETOPT} ${GLAD}) add_executable(joysticks WIN32 MACOSX_BUNDLE joysticks.c ${GLAD}) add_executable(opacity WIN32 MACOSX_BUNDLE opacity.c ${GLAD}) -add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GETOPT} ${GLAD}) +add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GLAD}) add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD} ${GLAD}) add_executable(timeout WIN32 MACOSX_BUNDLE timeout.c ${GLAD}) add_executable(title WIN32 MACOSX_BUNDLE title.c ${GLAD}) diff --git a/tests/events.c b/tests/events.c index 8b162a91a..d12d9a8ae 100644 --- a/tests/events.c +++ b/tests/events.c @@ -244,6 +244,10 @@ static const char* get_mods_name(int mods) strcat(name, " alt"); if (mods & GLFW_MOD_SUPER) strcat(name, " super"); + if (mods & GLFW_MOD_CAPS_LOCK) + strcat(name, " capslock-on"); + if (mods & GLFW_MOD_NUM_LOCK) + strcat(name, " numlock-on"); return name; } @@ -289,6 +293,13 @@ static void framebuffer_size_callback(GLFWwindow* window, int width, int height) glViewport(0, 0, width, height); } +static void window_content_scale_callback(GLFWwindow* window, float xscale, float yscale) +{ + Slot* slot = glfwGetWindowUserPointer(window); + printf("%08x to %i at %0.3f: Window content scale: %0.3f %0.3f\n", + counter++, slot->number, glfwGetTime(), xscale, yscale); +} + static void window_close_callback(GLFWwindow* window) { Slot* slot = glfwGetWindowUserPointer(window); @@ -411,6 +422,15 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, printf("(( closing %s ))\n", slot->closeable ? "enabled" : "disabled"); break; } + + case GLFW_KEY_L: + { + const int state = glfwGetInputMode(window, GLFW_LOCK_KEY_MODS); + glfwSetInputMode(window, GLFW_LOCK_KEY_MODS, !state); + + printf("(( lock key mods %s ))\n", !state ? "enabled" : "disabled"); + break; + } } } @@ -597,6 +617,7 @@ int main(int argc, char** argv) glfwSetWindowPosCallback(slots[i].window, window_pos_callback); glfwSetWindowSizeCallback(slots[i].window, window_size_callback); glfwSetFramebufferSizeCallback(slots[i].window, framebuffer_size_callback); + glfwSetWindowContentScaleCallback(slots[i].window, window_content_scale_callback); glfwSetWindowCloseCallback(slots[i].window, window_close_callback); glfwSetWindowRefreshCallback(slots[i].window, window_refresh_callback); glfwSetWindowFocusCallback(slots[i].window, window_focus_callback); diff --git a/tests/gamma.c b/tests/gamma.c index fbd37622e..6fca690df 100644 --- a/tests/gamma.c +++ b/tests/gamma.c @@ -135,13 +135,13 @@ int main(int argc, char** argv) glfwGetWindowSize(window, &width, &height); area = nk_rect(0.f, 0.f, (float) width, (float) height); + nk_window_set_bounds(nk, "", area); glClear(GL_COLOR_BUFFER_BIT); nk_glfw3_new_frame(); if (nk_begin(nk, "", area, 0)) { const GLFWgammaramp* ramp; - nk_window_set_bounds(nk, area); nk_layout_row_dynamic(nk, 30, 3); if (nk_slider_float(nk, 0.1f, &gamma_value, 5.f, 0.1f)) @@ -155,7 +155,7 @@ int main(int argc, char** argv) nk_layout_row_dynamic(nk, height - 60.f, 3); chart_ramp_array(nk, nk_rgb(255, 0, 0), ramp->size, ramp->red); chart_ramp_array(nk, nk_rgb(0, 255, 0), ramp->size, ramp->green); - chart_ramp_array(nk, nk_rgb(0,0, 255), ramp->size, ramp->blue); + chart_ramp_array(nk, nk_rgb(0, 0, 255), ramp->size, ramp->blue); } nk_end(nk); diff --git a/tests/joysticks.c b/tests/joysticks.c index d2be6475d..1d2993759 100644 --- a/tests/joysticks.c +++ b/tests/joysticks.c @@ -85,6 +85,32 @@ static void joystick_callback(int jid, int event) glfwRequestWindowAttention(window); } +static void drop_callback(GLFWwindow* window, int count, const char** paths) +{ + int i; + + for (i = 0; i < count; i++) + { + long size; + char* text; + FILE* stream = fopen(paths[i], "rb"); + if (!stream) + continue; + + fseek(stream, 0, SEEK_END); + size = ftell(stream); + fseek(stream, 0, SEEK_SET); + + text = malloc(size + 1); + text[size] = '\0'; + if (fread(text, 1, size, stream) == size) + glfwUpdateGamepadMappings(text); + + free(text); + fclose(stream); + } +} + static const char* joystick_label(int jid) { static char label[1024]; @@ -176,6 +202,7 @@ int main(void) } glfwSetJoystickCallback(joystick_callback); + glfwSetDropCallback(window, drop_callback); while (!glfwWindowShouldClose(window)) { diff --git a/tests/tearing.c b/tests/tearing.c index 1d8a00a40..eed4f04d8 100644 --- a/tests/tearing.c +++ b/tests/tearing.c @@ -36,7 +36,6 @@ #include #include "linmath.h" -#include "getopt.h" static const struct { @@ -69,14 +68,6 @@ static int swap_tear; static int swap_interval; static double frame_rate; -static void usage(void) -{ - printf("Usage: tearing [-h] [-f]\n"); - printf("Options:\n"); - printf(" -f create full screen window\n"); - printf(" -h show this help\n"); -} - static void update_window_title(GLFWwindow* window) { char title[256]; @@ -138,64 +129,50 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, 1); break; + + case GLFW_KEY_F11: + case GLFW_KEY_ENTER: + { + static int x, y, width, height; + + if (mods != GLFW_MOD_ALT) + return; + + if (glfwGetWindowMonitor(window)) + glfwSetWindowMonitor(window, NULL, x, y, width, height, 0); + else + { + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + glfwGetWindowPos(window, &x, &y); + glfwGetWindowSize(window, &width, &height); + glfwSetWindowMonitor(window, monitor, + 0, 0, mode->width, mode->height, + mode->refreshRate); + } + + break; + } } } int main(int argc, char** argv) { - int ch, width, height; unsigned long frame_count = 0; double last_time, current_time; - int fullscreen = GLFW_FALSE; - GLFWmonitor* monitor = NULL; GLFWwindow* window; GLuint vertex_buffer, vertex_shader, fragment_shader, program; GLint mvp_location, vpos_location; - while ((ch = getopt(argc, argv, "fh")) != -1) - { - switch (ch) - { - case 'h': - usage(); - exit(EXIT_SUCCESS); - - case 'f': - fullscreen = GLFW_TRUE; - break; - } - } - glfwSetErrorCallback(error_callback); if (!glfwInit()) exit(EXIT_FAILURE); - if (fullscreen) - { - const GLFWvidmode* mode; - - monitor = glfwGetPrimaryMonitor(); - mode = glfwGetVideoMode(monitor); - - glfwWindowHint(GLFW_RED_BITS, mode->redBits); - glfwWindowHint(GLFW_GREEN_BITS, mode->greenBits); - glfwWindowHint(GLFW_BLUE_BITS, mode->blueBits); - glfwWindowHint(GLFW_REFRESH_RATE, mode->refreshRate); - - width = mode->width; - height = mode->height; - } - else - { - width = 640; - height = 480; - } - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); - window = glfwCreateWindow(width, height, "", monitor, NULL); + window = glfwCreateWindow(640, 480, "Tearing detector", NULL, NULL); if (!window) { glfwTerminate(); diff --git a/tests/vulkan.c b/tests/vulkan.c index d0d4b3e3a..13a7ec2b3 100644 --- a/tests/vulkan.c +++ b/tests/vulkan.c @@ -738,7 +738,7 @@ static void demo_prepare_buffers(struct demo *demo) { } else if (swapchainExtent.width > surfCapabilities.maxImageExtent.width) { swapchainExtent.width = surfCapabilities.maxImageExtent.width; } - + if (swapchainExtent.height < surfCapabilities.minImageExtent.height) { swapchainExtent.height = surfCapabilities.minImageExtent.height; } else if (swapchainExtent.height > surfCapabilities.maxImageExtent.height) {