Updated glfw

simple_math_single_header
Martin Felis 2018-02-16 21:22:08 +01:00
parent 48c8cde66b
commit cf59f6b6ae
35 changed files with 984 additions and 656 deletions

View File

@ -1,35 +1,118 @@
# Contribution Guide # Contribution Guide
This file is a work in progress and you can report errors or submit patches for ## Contents
it the same as any other file.
- [Asking a question](#asking-a-question)
- [Reporting a bug](#reporting-a-bug)
- [Reporting a compile or link bug](#reporting-a-compile-or-link-bug)
- [Reporting a segfault or other crash bug](#reporting-a-segfault-or-other-crash-bug)
- [Reporting a context creation bug](#reporting-a-context-creation-bug)
- [Reporting a monitor or video mode bug](#reporting-a-monitor-or-video-mode-bug)
- [Reporting an input or event bug](#reporting-an-input-or-event-bug)
- [Reporting some other library bug](#reporting-some-other-library-bug)
- [Reporting a documentation bug](#reporting-a-documentation-bug)
- [Reporting a website bug](#reporting-a-website-bug)
- [Requesting a feature](#requesting-a-feature)
- [Contributing a bug fix](#contributing-a-bug-fix)
- [Contributing a feature](#contributing-a-feature)
## Asking a question
Questions about how to use GLFW should be asked either in the [support
section](http://discourse.glfw.org/c/support) of the forum, under the [Stack
Overflow tag](https://stackoverflow.com/questions/tagged/glfw) or [Game
Development tag](https://gamedev.stackexchange.com/questions/tagged/glfw) on
Stack Exchange or in the IRC channel `#glfw` on
[Freenode](http://freenode.net/).
Questions about the design or implementation of GLFW or about future plans
should be asked in the [dev section](http://discourse.glfw.org/c/dev) of the
forum or in the IRC channel. Please don't open a GitHub issue to discuss design
questions without first checking with a maintainer.
## Reporting a bug ## Reporting a bug
If GLFW is behaving unexpectedly, make sure you have set an error callback. If GLFW is behaving unexpectedly at run-time, start by setting an [error
GLFW will often tell you the cause of an issue via this callback. callback](http://www.glfw.org/docs/latest/intro_guide.html#error_handling).
GLFW will often tell you the cause of an error via this callback. If it
doesn't, that might be a separate bug.
If GLFW is crashing or triggering asserts, make sure that all your object If GLFW is crashing or triggering asserts, make sure that all your object
handles and other pointers are valid. handles and other pointers are valid.
Always include the __operating system name and version__ (i.e. `Windows For bugs where it makes sense, a [Short, Self Contained, Correct (Compilable),
7 64-bit` or `Ubuntu 15.10`). If you are using an official release of GLFW, Example](http://www.sscce.org/) is absolutely invaluable. Just put it inline in
include the __GLFW release version__ (i.e. `3.1.2`), otherwise include the the body text. Note that if the bug is reproducible with one of the test
__GLFW commit ID__ (i.e. `3795d78b14ef06008889cc422a1fb8d642597751`) from Git. programs that come with GLFW, just mention that instead.
If possible, please also include the __GLFW version string__ (`3.2.0 X11 EGL
clock_gettime /dev/js XI Xf86vm`), as described __Don't worry about adding too much information__. Unimportant information can
[here](http://www.glfw.org/docs/latest/intro.html#intro_version_string). be abbreviated or removed later, but missing information can stall bug fixing,
especially when your schedule doesn't align with that of the maintainer.
There are issue labels for both platforms and GPU manufacturers, so there is no
need to mention these in the subject line. If you do, it will be removed when
the issue is labeled.
If your bug is already reported, please add any new information you have, or if
it already has everything, give it a :+1:.
### Reporting a compile or link bug ### Reporting a compile or link bug
__Note:__ GLFW needs many system APIs to do its job. See the [Building __Note:__ GLFW needs many system APIs to do its job, which on some platforms
applications](http://www.glfw.org/docs/latest/build.html) guide for more means linking to many system libraries. If you are using GLFW as a static
information. library, that means your application needs to link to these in addition to GLFW.
In addition to the information above, always include the complete build log from __Note:__ Check the [Compiling
your compiler and linker. Issue posts are editable so it can always be GLFW](http://www.glfw.org/docs/latest/compile.html) guide and or [Building
shortened later. applications](http://www.glfw.org/docs/latest/build.html) guide for before
opening an issue of this kind. Most issues are caused by a missing package or
linker flag.
Always include the __operating system name and version__ (e.g. `Windows
7 64-bit` or `Ubuntu 15.10`) and the __compiler name and version__ (e.g. `Visual
C++ 2015 Update 2`). If you are using an official release of GLFW,
include the __GLFW release version__ (e.g. `3.1.2`), otherwise include the
__GLFW commit ID__ (e.g. `3795d78b14ef06008889cc422a1fb8d642597751`) from Git.
Please also include the __complete build log__ from your compiler and linker,
even if it's long. It can always be shortened later, if necessary.
#### Quick template
```
OS and version:
Compiler version:
Release or commit:
Build log:
```
### Reporting a segfault or other crash bug
Always include the __operating system name and version__ (e.g. `Windows
7 64-bit` or `Ubuntu 15.10`). If you are using an official release of GLFW,
include the __GLFW release version__ (e.g. `3.1.2`), otherwise include the
__GLFW commit ID__ (e.g. `3795d78b14ef06008889cc422a1fb8d642597751`) from Git.
Please also include any __error messages__ provided to your application via the
[error
callback](http://www.glfw.org/docs/latest/intro_guide.html#error_handling) and
the __full call stack__ of the crash, or if the crash does not occur in debug
mode, mention that instead.
#### Quick template
```
OS and version:
Release or commit:
Error messages:
Call stack:
```
### Reporting a context creation bug ### Reporting a context creation bug
@ -38,23 +121,42 @@ __Note:__ Windows ships with graphics drivers that do not support OpenGL. If
GLFW says that your machine lacks support for OpenGL, it very likely does. GLFW says that your machine lacks support for OpenGL, it very likely does.
Install drivers from the computer manufacturer or graphics card manufacturer Install drivers from the computer manufacturer or graphics card manufacturer
([Nvidia](http://www.geforce.com/drivers), ([Nvidia](http://www.geforce.com/drivers),
[AMD](http://support.amd.com/en-us/download), [AMD](http://support.amd.com/en-us/download),
[Intel](https://www-ssl.intel.com/content/www/us/en/support/detect.html)) to [Intel](https://www-ssl.intel.com/content/www/us/en/support/detect.html)) to
fix this. fix this.
__Note:__ AMD only supports OpenGL ES on Windows via EGL. EGL support is not __Note:__ AMD only supports OpenGL ES on Windows via EGL. See the
enabled in GLFW by default. You need to [enable EGL when [GLFW\_CONTEXT\_CREATION\_API](http://www.glfw.org/docs/latest/window_guide.html#window_hints_ctx)
compiling](http://www.glfw.org/docs/latest/compile.html) GLFW to use this. hint for how to select EGL.
The `glfwinfo` tool is included in the GLFW source tree as `tests/glfwinfo.c` Please verify that context creation also fails with the `glfwinfo` tool before
and is built along with the library. It lets you request any kind of context reporting it as a bug. This tool is included in the GLFW source tree as
and framebuffer format supported by the GLFW API without having to recompile. `tests/glfwinfo.c` and is built along with the library. It has switches for all
If context creation fails in your application, please verify that it also fails GLFW context and framebuffer hints. Run `glfwinfo -h` for a complete list.
with this tool before reporting it as a bug.
In addition to the information above (OS and GLFW version), always include the Always include the __operating system name and version__ (e.g. `Windows
__GPU model and driver version__ (i.e. `GeForce GTX660 with 352.79`) when 7 64-bit` or `Ubuntu 15.10`). If you are using an official release of GLFW,
reporting this kind of bug. include the __GLFW release version__ (e.g. `3.1.2`), otherwise include the
__GLFW commit ID__ (e.g. `3795d78b14ef06008889cc422a1fb8d642597751`) from Git.
Please also include the __GLFW version string__ (`3.2.0 X11 EGL clock_gettime
/dev/js XI Xf86vm`), as described
[here](http://www.glfw.org/docs/latest/intro.html#intro_version_string), the
__GPU model and driver version__ (e.g. `GeForce GTX660 with 352.79`), and the
__output of `glfwinfo`__ (with switches matching any hints you set in your
code) when reporting this kind of bug. If this tool doesn't run on the machine,
mention that instead.
#### Quick template
```
OS and version:
GPU and driver:
Release or commit:
Version string:
glfwinfo output:
```
### Reporting a monitor or video mode bug ### Reporting a monitor or video mode bug
@ -63,23 +165,44 @@ __Note:__ On headless systems on some platforms, no monitors are reported. This
causes glfwGetPrimaryMonitor to return `NULL`, which not all applications are causes glfwGetPrimaryMonitor to return `NULL`, which not all applications are
prepared for. prepared for.
__Note:__ Some third-party tools report more video modes than those approved of __Note:__ Some third-party tools report more video modes than are approved of
by the OS. For safety and compatbility, GLFW only reports video modes the OS by the OS. For safety and compatibility, GLFW only reports video modes the OS
wants programs to use. This is not a bug. wants programs to use. This is not a bug.
The `monitors` tool is included in the GLFW source tree as `tests/monitors.c` The `monitors` tool is included in the GLFW source tree as `tests/monitors.c`
and is built along with the library. lists all information about connected and is built along with the library. It lists all information GLFW provides
monitors made available by GLFW. about monitors it detects.
In addition to the information above (OS and GLFW version), please also include Always include the __operating system name and version__ (e.g. `Windows
the output of the `monitors` tool when reporting this kind of bug. If it 7 64-bit` or `Ubuntu 15.10`). If you are using an official release of GLFW,
doesn't work at all, please mention this. include the __GLFW release version__ (e.g. `3.1.2`), otherwise include the
__GLFW commit ID__ (e.g. `3795d78b14ef06008889cc422a1fb8d642597751`) from Git.
Please also include any __error messages__ provided to your application via the
[error
callback](http://www.glfw.org/docs/latest/intro_guide.html#error_handling) and
the __output of `monitors`__ when reporting this kind of bug. If this tool
doesn't run on the machine, mention this instead.
### Reporting a window event bug #### Quick template
__Note:__ While GLFW tries to provide the exact same behavior between platforms, ```
the exact ordering of related window events will sometimes differ. OS and version:
Release or commit:
Error messages:
monitors output:
```
### Reporting an input or event bug
__Note:__ The exact ordering of related window events will sometimes differ.
__Note:__ Window moving and resizing (by the user) will block the main thread on some
platforms. This is not a bug. Set a [refresh
callback](http://www.glfw.org/docs/latest/window.html#window_refresh) if you
want to keep the window contents updated during a move or size operation.
The `events` tool is included in the GLFW source tree as `tests/events.c` and is The `events` tool is included in the GLFW source tree as `tests/events.c` and is
built along with the library. It prints all information provided to every built along with the library. It prints all information provided to every
@ -87,20 +210,137 @@ callback supported by GLFW as events occur. Each event is listed with the time
and a unique number to make discussions about event logs easier. The tool has and a unique number to make discussions about event logs easier. The tool has
command-line options for creating multiple windows and full screen windows. command-line options for creating multiple windows and full screen windows.
Always include the __operating system name and version__ (e.g. `Windows
7 64-bit` or `Ubuntu 15.10`). If you are using an official release of GLFW,
include the __GLFW release version__ (e.g. `3.1.2`), otherwise include the
__GLFW commit ID__ (e.g. `3795d78b14ef06008889cc422a1fb8d642597751`) from Git.
Please also include any __error messages__ provided to your application via the
[error
callback](http://www.glfw.org/docs/latest/intro_guide.html#error_handling) and
if relevant, the __output of `events`__ when reporting this kind of bug. If
this tool doesn't run on the machine, mention this instead.
#### Quick template
```
OS and version:
Release or commit:
Error messages:
events output:
```
### Reporting some other library bug
Always include the __operating system name and version__ (e.g. `Windows
7 64-bit` or `Ubuntu 15.10`). If you are using an official release of GLFW,
include the __GLFW release version__ (e.g. `3.1.2`), otherwise include the
__GLFW commit ID__ (e.g. `3795d78b14ef06008889cc422a1fb8d642597751`) from Git.
Please also include any __error messages__ provided to your application via the
[error
callback](http://www.glfw.org/docs/latest/intro_guide.html#error_handling), if
relevant.
#### Quick template
```
OS and version:
Release or commit:
Error messages:
```
### Reporting a documentation bug ### Reporting a documentation bug
If you found the error in the generated documentation then it's fine to just If you found a bug in the documentation, including this file, then it's fine to
link to that webpage. You don't need to figure out which documentation source just link to that web page or mention that source file. You don't need to match
file the text comes from. the source to the output or vice versa.
### Reporting a website bug
If the bug is in the documentation (anything under `/docs/`) then please see the
section above. Bugs in the rest of the site are reported to to the [website
source repository](https://github.com/glfw/website/issues).
## Requesting a feature
Please explain why you need the feature and how you intend to use it. If you
have a specific API design in mind, please add that as well. If you have or are
planning to write code for the feature, see the section below.
If there already is a request for the feature you need, add your specific use
case unless it is already mentioned. If it is, give it a :+1:.
## Contributing a bug fix ## Contributing a bug fix
There should be text here, but there isn't. __Note:__ You must have all necessary [intellectual
property rights](https://en.wikipedia.org/wiki/Intellectual_property) to any
code you contribute. If you did not write the code yourself, you must explain
where it came from and under what license you received it. Even code using the
same license as GLFW may not be copied without attribution.
__There is no preferred patch size__. A one character fix is just as welcome as
a thousand line one, if that is the appropriate size for the fix.
In addition to the code, a complete bug fix includes:
- Change log entry in `README.md`, describing the incorrect behavior
- Credits entries for all authors of the bug fix
Bug fixes will not be rejected because they don't include all the above parts,
but please keep in mind that maintainer time is finite and that there are many
other bugs and features to work on.
If the patch fixes a bug introduced after the last release, it should not get
a change log entry.
## Contributing a feature ## Contributing a feature
This is not (yet) the text you are looking for. __Note:__ You must have all necessary rights to any code you contribute. If you
did not write the code yourself, you must explain where it came from and under
what license. Even code using the same license as GLFW may not be copied
without attribution.
__There is no preferred patch size__. A one character change is just as welcome
as one adding a thousand line one, if that is the appropriate size for the
feature.
In addition to the code, a complete feature includes:
- Change log entry in `README.md`, listing all new symbols
- News page entry, briefly describing the feature
- Guide documentation, with minimal examples, in the relevant guide
- Reference documentation, with all applicable tags
- Cross-references and mentions in appropriate places
- Credits entries for all authors of the feature
If the feature requires platform-specific code, at minimum stubs must be added
for the new platform function to all supported and experimental platforms.
If it adds a new callback, support for it must be added to `tests/event.c`.
If it adds a new monitor property, support for it must be added to
`tests/monitor.c`.
If it adds a new OpenGL, OpenGL ES or Vulkan option or extension, support
for it must be added to `tests/glfwinfo.c` and the behavior of the library when
the extension is missing documented in `docs/compat.dox`.
Features will not be rejected because they don't include all the above parts,
but please keep in mind that maintainer time is finite and that there are many
other features and bugs to work on.
Please also keep in mind that any part of the public API that has been included
in a release cannot be changed until the next _major_ version. Features can be
added and existing parts can sometimes be overloaded (in the general sense of
doing more things, not in the C++ sense), but code written to the API of one
minor release should both compile and run on subsequent minor releases.

View File

@ -1,82 +0,0 @@
# External junk
.DS_Store
_ReSharper*
*.opensdf
*.sdf
*.suo
*.dir
*.vcxproj*
*.sln
Win32
x64
Debug
Release
MinSizeRel
RelWithDebInfo
*.xcodeproj
# CMake files
Makefile
CMakeCache.txt
CMakeFiles
CMakeScripts
cmake_install.cmake
cmake_uninstall.cmake
# Generated files
docs/Doxyfile
docs/html
docs/warnings.txt
docs/doxygen_sqlite3.db
src/glfw_config.h
src/glfw3.pc
src/glfw3Config.cmake
src/glfw3ConfigVersion.cmake
src/wayland-pointer-constraints-unstable-v1-client-protocol.h
src/wayland-pointer-constraints-unstable-v1-protocol.c
src/wayland-relative-pointer-unstable-v1-client-protocol.h
src/wayland-relative-pointer-unstable-v1-protocol.c
# Compiled binaries
src/libglfw.so
src/libglfw.so.3
src/libglfw.so.3.2
src/libglfw.dylib
src/libglfw.dylib
src/libglfw.3.dylib
src/libglfw.3.2.dylib
src/libglfw3.a
src/glfw3.lib
src/glfw3.dll
src/glfw3dll.lib
src/libglfw3dll.a
examples/*.app
examples/*.exe
examples/boing
examples/gears
examples/heightmap
examples/particles
examples/splitview
examples/simple
examples/wave
tests/*.app
tests/*.exe
tests/clipboard
tests/cursor
tests/empty
tests/events
tests/gamma
tests/glfwinfo
tests/iconify
tests/joysticks
tests/monitors
tests/msaa
tests/reopen
tests/sharing
tests/tearing
tests/threads
tests/title
tests/version
tests/vulkan
tests/windows

View File

@ -12,6 +12,9 @@ if (WIN32)
find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS
"$ENV{VULKAN_SDK}/Bin" "$ENV{VULKAN_SDK}/Bin"
"$ENV{VK_SDK_PATH}/Bin") "$ENV{VK_SDK_PATH}/Bin")
find_library(VULKAN_STATIC_LIBRARY NAMES vkstatic.1 HINTS
"$ENV{VULKAN_SDK}/Bin"
"$ENV{VK_SDK_PATH}/Bin")
else() else()
find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS find_library(VULKAN_LIBRARY NAMES vulkan-1 HINTS
"$ENV{VULKAN_SDK}/Bin32" "$ENV{VULKAN_SDK}/Bin32"
@ -27,5 +30,5 @@ endif()
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Vulkan DEFAULT_MSG VULKAN_LIBRARY VULKAN_INCLUDE_DIR) find_package_handle_standard_args(Vulkan DEFAULT_MSG VULKAN_LIBRARY VULKAN_INCLUDE_DIR)
mark_as_advanced(VULKAN_INCLUDE_DIR VULKAN_LIBRARY) mark_as_advanced(VULKAN_INCLUDE_DIR VULKAN_LIBRARY VULKAN_STATIC_LIBRARY)

View File

@ -25,6 +25,7 @@ option(GLFW_BUILD_EXAMPLES "Build the GLFW example programs" ON)
option(GLFW_BUILD_TESTS "Build the GLFW test programs" ON) option(GLFW_BUILD_TESTS "Build the GLFW test programs" ON)
option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON) option(GLFW_BUILD_DOCS "Build the GLFW documentation" ON)
option(GLFW_INSTALL "Generate installation target" ON) option(GLFW_INSTALL "Generate installation target" ON)
option(GLFW_VULKAN_STATIC "Use the Vulkan loader statically linked into application" OFF)
option(GLFW_DOCUMENT_INTERNALS "Include internals in documentation" OFF) option(GLFW_DOCUMENT_INTERNALS "Include internals in documentation" OFF)
if (WIN32) if (WIN32)
@ -57,7 +58,11 @@ else()
set(GLFW_LIB_NAME glfw3) set(GLFW_LIB_NAME glfw3)
endif() endif()
set(CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules") if (GLFW_VULKAN_STATIC)
set(_GLFW_VULKAN_STATIC 1)
endif()
list(APPEND CMAKE_MODULE_PATH "${GLFW_SOURCE_DIR}/CMake/modules")
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
find_package(Vulkan) find_package(Vulkan)
@ -148,6 +153,21 @@ else()
message(FATAL_ERROR "No supported platform was detected") message(FATAL_ERROR "No supported platform was detected")
endif() endif()
#--------------------------------------------------------------------
# Add Vulkan static library if requested
#--------------------------------------------------------------------
if (GLFW_VULKAN_STATIC)
if (VULKAN_FOUND AND VULKAN_STATIC_LIBRARY)
list(APPEND glfw_LIBRARIES ${VULKAN_STATIC_LIBRARY})
else()
if (BUILD_SHARED_LIBS OR GLFW_BUILD_EXAMPLES OR GLFW_BUILD_TESTS)
message(FATAL_ERROR "Vulkan loader static library not found")
else()
message(WARNING "Vulkan loader static library not found")
endif()
endif()
endif()
#-------------------------------------------------------------------- #--------------------------------------------------------------------
# Find and add Unix math and time libraries # Find and add Unix math and time libraries
#-------------------------------------------------------------------- #--------------------------------------------------------------------
@ -253,7 +273,7 @@ endif()
#-------------------------------------------------------------------- #--------------------------------------------------------------------
if (_GLFW_WAYLAND) if (_GLFW_WAYLAND)
find_package(ECM REQUIRED NO_MODULE) find_package(ECM REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
find_package(Wayland REQUIRED) find_package(Wayland REQUIRED)
find_package(WaylandScanner REQUIRED) find_package(WaylandScanner REQUIRED)

View File

@ -2,19 +2,25 @@
[![Build status](https://travis-ci.org/glfw/glfw.svg?branch=master)](https://travis-ci.org/glfw/glfw) [![Build status](https://travis-ci.org/glfw/glfw.svg?branch=master)](https://travis-ci.org/glfw/glfw)
[![Build status](https://ci.appveyor.com/api/projects/status/0kf0ct9831i5l6sp/branch/master?svg=true)](https://ci.appveyor.com/project/elmindreda/glfw) [![Build status](https://ci.appveyor.com/api/projects/status/0kf0ct9831i5l6sp/branch/master?svg=true)](https://ci.appveyor.com/project/elmindreda/glfw)
[![Coverity Scan](https://scan.coverity.com/projects/4884/badge.svg)](https://scan.coverity.com/projects/glfw-glfw)
## Introduction ## Introduction
GLFW is a free, Open Source, multi-platform library for OpenGL, OpenGL ES and GLFW is an Open Source, multi-platform library for OpenGL, OpenGL ES and Vulkan
Vulkan application development. It provides a simple, platform-independent API application development. It provides a simple, platform-independent API for
for creating windows, contexts and surfaces, reading input, handling events, etc. creating windows, contexts and surfaces, reading input, handling events, etc.
The current stable release is version 3.2. See the GLFW is licensed under the [zlib/libpng
[downloads](http://www.glfw.org/download.html) page for details and files, or license](https://opensource.org/licenses/Zlib).
fetch the `latest` branch, which always points to the latest stable release.
Each release starting with 3.0 also has a corresponding annotated tag.
This is version 3.2.1, which is _not yet described_. This is version 3.2.1, which adds support for statically linking the Vulkan
loader and fixes for a number of bugs that together affect all supported
platforms.
See the [downloads](http://www.glfw.org/download.html) page for details and
files, or fetch the `latest` branch, which always points to the latest stable
release. Each release starting with 3.0 also has a corresponding [annotated
tag](https://github.com/glfw/glfw/releases) with source and binary archives.
If you are new to GLFW, you may find the If you are new to GLFW, you may find the
[tutorial](http://www.glfw.org/docs/latest/quick.html) for GLFW [tutorial](http://www.glfw.org/docs/latest/quick.html) for GLFW
@ -25,37 +31,43 @@ the GLFW 3 API.
## Compiling GLFW ## Compiling GLFW
See the [Compiling GLFW](http://www.glfw.org/docs/latest/compile.html) guide in GLFW itself requires only the headers and libraries for your window system. It
the GLFW documentation. does not need the headers for any context creation API (WGL, GLX, EGL, NSGL) or
rendering API (OpenGL, OpenGL ES, Vulkan) to enable support for them.
GLFW supports compilation on Windows with Visual C++ 2010 and later, MinGW and
MinGW-w64, on OS X with Clang and on Linux and other Unix-like systems with GCC
and Clang. It will likely compile in other environments as well, but this is
not regularly tested.
There are also [pre-compiled Windows
binaries](http://www.glfw.org/download.html) available for all compilers
supported on that platform.
See the [compilation guide](http://www.glfw.org/docs/latest/compile.html) in the
documentation for more information.
## Using GLFW ## Using GLFW
See the See the [building application guide](http://www.glfw.org/docs/latest/build.html)
[Building programs that use GLFW](http://www.glfw.org/docs/latest/build.html) guide in the documentation for more information.
guide in the GLFW documentation.
## Reporting bugs ## System requirements
Bugs are reported to our [issue tracker](https://github.com/glfw/glfw/issues). GLFW supports Windows XP and later, OS X 10.7 Lion and later, and Linux and
Please always include the name and version of the OS where the bug occurs and other Unix-like systems with the X Window System. Experimental implementations
the version of GLFW used. If you have cloned it, include the commit ID used. for the Wayland protocol and the Mir display server are available but not yet
officially supported.
If it's a build issue, please also include the build log and the name and See the [compatibility guide](http://www.glfw.org/docs/latest/compat.html)
version of your development environment. in the documentation for more information.
If it's a context creation issue, please also include the make and model of your
graphics card and the version of your driver.
This will help both us and other people experiencing the same bug.
## Dependencies ## Dependencies
GLFW itself needs only the headers and libraries for your window system. It GLFW itself depends only on the headers and libraries for your window system.
does not need the headers for any context creation API (WGL, GLX, EGL, NSGL) or
rendering API (OpenGL, OpenGL ES, Vulkan) to enable support for them.
The examples and test programs depend on a number of tiny libraries. These are The examples and test programs depend on a number of tiny libraries. These are
located in the `deps/` directory. located in the `deps/` directory.
@ -74,30 +86,64 @@ The Vulkan example additionally requires the Vulkan SDK to be installed, or it
will not be included in the build. will not be included in the build.
The documentation is generated with [Doxygen](http://doxygen.org/). If CMake The documentation is generated with [Doxygen](http://doxygen.org/). If CMake
does not find Doxygen, the documentation will not be generated. does not find Doxygen, the documentation will not be generated when you build.
## Reporting bugs
Bugs are reported to our [issue tracker](https://github.com/glfw/glfw/issues).
Please check the [contribution
guide](https://github.com/glfw/glfw/blob/master/.github/CONTRIBUTING.md) for
information on what to include when reporting a bug.
## Changelog ## Changelog
- Bugfix: The range checks for `glfwSetCursorPos` used the wrong minimum - Added on-demand loading of Vulkan and context creation API libraries
- Added `_GLFW_VULKAN_STATIC` build macro to make the library use the Vulkan
loader linked statically into the application (#820)
- Bugfix: Single compilation unit builds failed due to naming conflicts (#783)
- Bugfix: The range checks for `glfwSetCursorPos` used the wrong minimum (#773)
- Bugfix: Defining `GLFW_INCLUDE_VULKAN` when compiling the library did not
fail with the expected error message (#823)
- Bugfix: Inherited value of `CMAKE_MODULE_PATH` was clobbered (#822)
- [Win32] Bugfix: `glfwSetClipboardString` created an unnecessary intermediate
copy of the string
- [Win32] Bugfix: Examples failed to build on Visual C++ 2010 due to C99 in
`linmath.h` (#785)
- [Win32] Bugfix: The first shown window ignored the `GLFW_MAXIMIZED` hint
when the process was provided a `STARTUPINFO` (#780)
- [Cocoa] Bugfix: Event processing would segfault on some machines due to
a previous distributed notification listener not being fully
removed (#817,#826)
- [Cocoa] Bugfix: Some include statements were duplicated (#838)
- [X11] Bugfix: Window size limits were ignored if the minimum or maximum size
was set to `GLFW_DONT_CARE` (#805)
- [X11] Bugfix: Input focus was set before window was visible, causing
`BadMatch` on some non-reparenting WMs (#789,#798)
- [X11] Bugfix: `glfwGetWindowPos` and `glfwSetWindowPos` operated on the
window frame instead of the client area (#800)
- [WGL] Added reporting of errors from `WGL_ARB_create_context` extension
- [GLX] Bugfix: Dynamically loaded entry points were not verified
- [EGL] Added `lib` prefix matching between EGL and OpenGL ES library binaries
- [EGL] Bugfix: Dynamically loaded entry points were not verified
## Contact ## Contact
The official website for GLFW is [glfw.org](http://www.glfw.org/). There you On [glfw.org](http://www.glfw.org/) you can find the latest version of GLFW, as
can find the latest version of GLFW, as well as news, documentation and other well as news, documentation and other information about the project.
information about the project.
If you have questions related to the use of GLFW, we have a If you have questions related to the use of GLFW, we have a
[support forum](http://discourse.glfw.org/), and the IRC [forum](http://discourse.glfw.org/), and the `#glfw` IRC channel on
channel `#glfw` on [Freenode](http://freenode.net/). [Freenode](http://freenode.net/).
If you have a bug to report, a patch to submit or a feature you'd like to If you have a bug to report, a patch to submit or a feature you'd like to
request, please file it in the request, please file it in the
[issue tracker](https://github.com/glfw/glfw/issues) on GitHub. [issue tracker](https://github.com/glfw/glfw/issues) on GitHub.
Finally, if you're interested in helping out with the development of GLFW or Finally, if you're interested in helping out with the development of GLFW or
porting it to your favorite platform, join us on GitHub or IRC. porting it to your favorite platform, join us on the forum, GitHub or IRC.
## Acknowledgements ## Acknowledgements
@ -140,8 +186,10 @@ skills.
- heromyth - heromyth
- Lucas Hinderberger - Lucas Hinderberger
- Paul Holden - Paul Holden
- Warren Hu
- IntellectualKitty - IntellectualKitty
- Aaron Jacobs - Aaron Jacobs
- Erik S. V. Jansson
- Toni Jovanoski - Toni Jovanoski
- Arseny Kapoulkine - Arseny Kapoulkine
- Osman Keskin - Osman Keskin
@ -181,6 +229,7 @@ skills.
- Emmanuel Gil Peyrot - Emmanuel Gil Peyrot
- Cyril Pichard - Cyril Pichard
- Pieroman - Pieroman
- Philip Rideout
- Jorge Rodriguez - Jorge Rodriguez
- Ed Ropple - Ed Ropple
- Aleksey Rybalkin - Aleksey Rybalkin
@ -195,6 +244,7 @@ skills.
- Dmitri Shuralyov - Dmitri Shuralyov
- Daniel Skorupski - Daniel Skorupski
- Bradley Smith - Bradley Smith
- Patrick Snape
- Julian Squires - Julian Squires
- Johannes Stein - Johannes Stein
- Justin Stoecker - Justin Stoecker
@ -202,7 +252,7 @@ skills.
- Nathan Sweet - Nathan Sweet
- TTK-Bandit - TTK-Bandit
- Sergey Tikhomirov - Sergey Tikhomirov
- A. Tombs - Arthur Tombs
- Ioannis Tsakpinis - Ioannis Tsakpinis
- Samuli Tuomola - Samuli Tuomola
- urraka - urraka

View File

@ -3,7 +3,7 @@
#include <math.h> #include <math.h>
#ifdef _MSC_VER #ifdef _MSC_VER
#define inline __inline #define inline __inline
#endif #endif
@ -192,19 +192,20 @@ static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z,
vec3 u = {x, y, z}; vec3 u = {x, y, z};
if(vec3_len(u) > 1e-4) { if(vec3_len(u) > 1e-4) {
mat4x4 T, C, S;
vec3_norm(u, u); vec3_norm(u, u);
mat4x4 T;
mat4x4_from_vec3_mul_outer(T, u, u); mat4x4_from_vec3_mul_outer(T, u, u);
mat4x4 S = { S[1][2] = u[0];
{ 0, u[2], -u[1], 0}, S[2][1] = -u[0];
{-u[2], 0, u[0], 0}, S[2][0] = u[1];
{ u[1], -u[0], 0, 0}, S[0][2] = -u[1];
{ 0, 0, 0, 0} S[0][1] = u[2];
}; S[1][0] = -u[2];
mat4x4_scale(S, S, s); mat4x4_scale(S, S, s);
mat4x4 C;
mat4x4_identity(C); mat4x4_identity(C);
mat4x4_sub(C, C, T); mat4x4_sub(C, C, T);
@ -213,7 +214,7 @@ static inline void mat4x4_rotate(mat4x4 R, mat4x4 M, float x, float y, float z,
mat4x4_add(T, T, C); mat4x4_add(T, T, C);
mat4x4_add(T, T, S); mat4x4_add(T, T, S);
T[3][3] = 1.; T[3][3] = 1.;
mat4x4_mul(R, M, T); mat4x4_mul(R, M, T);
} else { } else {
mat4x4_dup(R, M); mat4x4_dup(R, M);
@ -257,6 +258,7 @@ static inline void mat4x4_rotate_Z(mat4x4 Q, mat4x4 M, float angle)
} }
static inline void mat4x4_invert(mat4x4 T, mat4x4 M) static inline void mat4x4_invert(mat4x4 T, mat4x4 M)
{ {
float idet;
float s[6]; float s[6];
float c[6]; float c[6];
s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1]; s[0] = M[0][0]*M[1][1] - M[1][0]*M[0][1];
@ -272,10 +274,10 @@ static inline void mat4x4_invert(mat4x4 T, mat4x4 M)
c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2]; c[3] = M[2][1]*M[3][2] - M[3][1]*M[2][2];
c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3]; c[4] = M[2][1]*M[3][3] - M[3][1]*M[2][3];
c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3]; c[5] = M[2][2]*M[3][3] - M[3][2]*M[2][3];
/* Assumes it is invertible */ /* Assumes it is invertible */
float idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] ); idet = 1.0f/( s[0]*c[5]-s[1]*c[4]+s[2]*c[3]+s[3]*c[2]-s[4]*c[1]+s[5]*c[0] );
T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet; T[0][0] = ( M[1][1] * c[5] - M[1][2] * c[4] + M[1][3] * c[3]) * idet;
T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet; T[0][1] = (-M[0][1] * c[5] + M[0][2] * c[4] - M[0][3] * c[3]) * idet;
T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet; T[0][2] = ( M[3][1] * s[5] - M[3][2] * s[4] + M[3][3] * s[3]) * idet;
@ -298,12 +300,12 @@ static inline void mat4x4_invert(mat4x4 T, mat4x4 M)
} }
static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M) static inline void mat4x4_orthonormalize(mat4x4 R, mat4x4 M)
{ {
mat4x4_dup(R, M);
float s = 1.; float s = 1.;
vec3 h; vec3 h;
mat4x4_dup(R, M);
vec3_norm(R[2], R[2]); vec3_norm(R[2], R[2]);
s = vec3_mul_inner(R[1], R[2]); s = vec3_mul_inner(R[1], R[2]);
vec3_scale(h, R[2], s); vec3_scale(h, R[2], s);
vec3_sub(R[1], R[1], h); vec3_sub(R[1], R[1], h);
@ -324,7 +326,7 @@ static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t,
{ {
M[0][0] = 2.f*n/(r-l); M[0][0] = 2.f*n/(r-l);
M[0][1] = M[0][2] = M[0][3] = 0.f; M[0][1] = M[0][2] = M[0][3] = 0.f;
M[1][1] = 2.f*n/(t-b); M[1][1] = 2.f*n/(t-b);
M[1][0] = M[1][2] = M[1][3] = 0.f; M[1][0] = M[1][2] = M[1][3] = 0.f;
@ -332,7 +334,7 @@ static inline void mat4x4_frustum(mat4x4 M, float l, float r, float b, float t,
M[2][1] = (t+b)/(t-b); M[2][1] = (t+b)/(t-b);
M[2][2] = -(f+n)/(f-n); M[2][2] = -(f+n)/(f-n);
M[2][3] = -1.f; M[2][3] = -1.f;
M[3][2] = -2.f*(f*n)/(f-n); M[3][2] = -2.f*(f*n)/(f-n);
M[3][0] = M[3][1] = M[3][3] = 0.f; M[3][0] = M[3][1] = M[3][3] = 0.f;
} }
@ -346,7 +348,7 @@ static inline void mat4x4_ortho(mat4x4 M, float l, float r, float b, float t, fl
M[2][2] = -2.f/(f-n); M[2][2] = -2.f/(f-n);
M[2][0] = M[2][1] = M[2][3] = 0.f; M[2][0] = M[2][1] = M[2][3] = 0.f;
M[3][0] = -(r+l)/(r-l); M[3][0] = -(r+l)/(r-l);
M[3][1] = -(t+b)/(t-b); M[3][1] = -(t+b)/(t-b);
M[3][2] = -(f+n)/(f-n); M[3][2] = -(f+n)/(f-n);
@ -387,14 +389,15 @@ static inline void mat4x4_look_at(mat4x4 m, vec3 eye, vec3 center, vec3 up)
/* TODO: The negation of of can be spared by swapping the order of /* TODO: The negation of of can be spared by swapping the order of
* operands in the following cross products in the right way. */ * operands in the following cross products in the right way. */
vec3 f; vec3 f;
vec3_sub(f, center, eye);
vec3_norm(f, f);
vec3 s; vec3 s;
vec3 t;
vec3_sub(f, center, eye);
vec3_norm(f, f);
vec3_mul_cross(s, f, up); vec3_mul_cross(s, f, up);
vec3_norm(s, s); vec3_norm(s, s);
vec3 t;
vec3_mul_cross(t, s, f); vec3_mul_cross(t, s, f);
m[0][0] = s[0]; m[0][0] = s[0];
@ -470,9 +473,9 @@ static inline void quat_conj(quat r, quat q)
r[3] = q[3]; r[3] = q[3];
} }
static inline void quat_rotate(quat r, float angle, vec3 axis) { static inline void quat_rotate(quat r, float angle, vec3 axis) {
int i;
vec3 v; vec3 v;
vec3_scale(v, axis, sinf(angle / 2)); vec3_scale(v, axis, sinf(angle / 2));
int i;
for(i=0; i<3; ++i) for(i=0; i<3; ++i)
r[i] = v[i]; r[i] = v[i];
r[3] = cosf(angle / 2); r[3] = cosf(angle / 2);
@ -507,7 +510,7 @@ static inline void mat4x4_from_quat(mat4x4 M, quat q)
float b2 = b*b; float b2 = b*b;
float c2 = c*c; float c2 = c*c;
float d2 = d*d; float d2 = d*d;
M[0][0] = a2 + b2 - c2 - d2; M[0][0] = a2 + b2 - c2 - d2;
M[0][1] = 2.f*(b*c + a*d); M[0][1] = 2.f*(b*c + a*d);
M[0][2] = 2.f*(b*d - a*c); M[0][2] = 2.f*(b*d - a*c);

View File

@ -115,11 +115,14 @@ extern "C" {
#define GLFW_CALLBACK_DEFINED #define GLFW_CALLBACK_DEFINED
#endif /* CALLBACK */ #endif /* CALLBACK */
/* Most Windows GLU headers need wchar_t. /* Include because most Windows GLU headers need wchar_t and
* The OS X OpenGL header blocks the definition of ptrdiff_t by glext.h. * the OS X OpenGL header blocks the definition of ptrdiff_t by glext.h.
* Include it unconditionally to avoid surprising side-effects. * Include it unconditionally to avoid surprising side-effects.
*/ */
#include <stddef.h> #include <stddef.h>
/* Include because it is needed by Vulkan and related functions.
*/
#include <stdint.h> #include <stdint.h>
/* Include the chosen client API headers. /* Include the chosen client API headers.
@ -1182,6 +1185,7 @@ typedef struct GLFWgammaramp
/*! @brief Image data. /*! @brief Image data.
* *
* @sa @ref cursor_custom * @sa @ref cursor_custom
* @sa @ref window_icon
* *
* @since Added in version 2.1. * @since Added in version 2.1.
* @glfw3 Removed format and bytes-per-pixel members. * @glfw3 Removed format and bytes-per-pixel members.
@ -1739,6 +1743,10 @@ GLFWAPI void glfwWindowHint(int hint, int value);
* screen windows, including the creation of so called _windowed full screen_ * screen windows, including the creation of so called _windowed full screen_
* or _borderless full screen_ windows, see @ref window_windowed_full_screen. * or _borderless full screen_ windows, see @ref window_windowed_full_screen.
* *
* Once you have created the window, you can switch it between windowed and
* full screen mode with @ref glfwSetWindowMonitor. If the window has an
* OpenGL or OpenGL ES context, it will be unaffected.
*
* By default, newly created windows use the placement recommended by the * By default, newly created windows use the placement recommended by the
* window system. To create the window at a specific position, make it * window system. To create the window at a specific position, make it
* initially invisible using the [GLFW_VISIBLE](@ref window_hints_wnd) window * initially invisible using the [GLFW_VISIBLE](@ref window_hints_wnd) window
@ -2390,8 +2398,8 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* window);
* in full screen on. * in full screen on.
* *
* @param[in] window The window to query. * @param[in] window The window to query.
* @return The monitor, or `NULL` if the window is in windowed mode or an error * @return The monitor, or `NULL` if the window is in windowed mode or an
* occurred. * [error](@ref error_handling) occurred.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
* *
@ -2846,7 +2854,7 @@ GLFWAPI void glfwWaitEventsTimeout(double timeout);
/*! @brief Posts an empty event to the event queue. /*! @brief Posts an empty event to the event queue.
* *
* This function posts an empty event from the current thread to the event * This function posts an empty event from the current thread to the event
* queue, causing @ref glfwWaitEvents to return. * queue, causing @ref glfwWaitEvents or @ref glfwWaitEventsTimeout to return.
* *
* If no windows exist, this function returns immediately. For synchronization * If no windows exist, this function returns immediately. For synchronization
* of threads in applications that do not create windows, use your threading * of threads in applications that do not create windows, use your threading
@ -2859,6 +2867,7 @@ GLFWAPI void glfwWaitEventsTimeout(double timeout);
* *
* @sa @ref events * @sa @ref events
* @sa glfwWaitEvents * @sa glfwWaitEvents
* @sa glfwWaitEventsTimeout
* *
* @since Added in version 3.1. * @since Added in version 3.1.
* *
@ -3354,7 +3363,7 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun);
* @param[in] cbfun The new callback, or `NULL` to remove the currently set * @param[in] cbfun The new callback, or `NULL` to remove the currently set
* callback. * callback.
* @return The previously set callback, or `NULL` if no callback was set or an * @return The previously set callback, or `NULL` if no callback was set or an
* error occurred. * [error](@ref error_handling) occurred.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
* *
@ -3533,8 +3542,10 @@ GLFWAPI int glfwJoystickPresent(int joy);
* *
* @param[in] joy The [joystick](@ref joysticks) to query. * @param[in] joy The [joystick](@ref joysticks) to query.
* @param[out] count Where to store the number of axis values in the returned * @param[out] count Where to store the number of axis values in the returned
* array. This is set to zero if an error occurred. * array. This is set to zero if the joystick is not present or an error
* @return An array of axis values, or `NULL` if the joystick is not present. * occurred.
* @return An array of axis values, or `NULL` if the joystick is not present or
* an [error](@ref error_handling) occurred.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
@ -3565,8 +3576,10 @@ GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count);
* *
* @param[in] joy The [joystick](@ref joysticks) to query. * @param[in] joy The [joystick](@ref joysticks) to query.
* @param[out] count Where to store the number of button states in the returned * @param[out] count Where to store the number of button states in the returned
* array. This is set to zero if an error occurred. * array. This is set to zero if the joystick is not present or an error
* @return An array of button states, or `NULL` if the joystick is not present. * occurred.
* @return An array of button states, or `NULL` if the joystick is not present
* or an [error](@ref error_handling) occurred.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.
@ -3599,7 +3612,7 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count);
* *
* @param[in] joy The [joystick](@ref joysticks) to query. * @param[in] joy The [joystick](@ref joysticks) to query.
* @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick
* is not present. * is not present or an [error](@ref error_handling) occurred.
* *
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref * @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR. * GLFW_INVALID_ENUM and @ref GLFW_PLATFORM_ERROR.

View File

@ -325,9 +325,6 @@ int _glfwPlatformInit(void)
if (!_glfwInitThreadLocalStoragePOSIX()) if (!_glfwInitThreadLocalStoragePOSIX())
return GLFW_FALSE; return GLFW_FALSE;
if (!_glfwInitNSGL())
return GLFW_FALSE;
_glfwInitTimerNS(); _glfwInitTimerNS();
_glfwInitJoysticksNS(); _glfwInitJoysticksNS();
@ -362,6 +359,8 @@ void _glfwPlatformTerminate(void)
removeObserver:_glfw.ns.listener removeObserver:_glfw.ns.listener
name:(__bridge NSString*)kTISNotifySelectedKeyboardInputSourceChanged name:(__bridge NSString*)kTISNotifySelectedKeyboardInputSourceChanged
object:nil]; object:nil];
[[NSDistributedNotificationCenter defaultCenter]
removeObserver:_glfw.ns.listener];
[_glfw.ns.listener release]; [_glfw.ns.listener release];
_glfw.ns.listener = nil; _glfw.ns.listener = nil;
} }

View File

@ -27,11 +27,9 @@
#include "internal.h" #include "internal.h"
#include <stdlib.h>
#include <stdlib.h> #include <stdlib.h>
#include <limits.h> #include <limits.h>
#include <IOKit/graphics/IOGraphicsLib.h>
#include <IOKit/graphics/IOGraphicsLib.h> #include <IOKit/graphics/IOGraphicsLib.h>
#include <CoreVideo/CVBase.h> #include <CoreVideo/CVBase.h>
#include <CoreVideo/CVDisplayLink.h> #include <CoreVideo/CVDisplayLink.h>
@ -66,7 +64,7 @@ static char* getDisplayName(CGDirectDisplayID displayID)
size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value),
kCFStringEncodingUTF8); kCFStringEncodingUTF8);
name = calloc(size + 1, sizeof(char)); name = calloc(size + 1, 1);
CFStringGetCString(value, name, size, kCFStringEncodingUTF8); CFStringGetCString(value, name, size, kCFStringEncodingUTF8);
CFRelease(info); CFRelease(info);

View File

@ -944,8 +944,8 @@ static GLFWbool initializeAppKit(void)
// Create the Cocoa window // Create the Cocoa window
// //
static GLFWbool createWindow(_GLFWwindow* window, static GLFWbool createNativeWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig) const _GLFWwndconfig* wndconfig)
{ {
window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window]; window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window];
if (window->ns.delegate == nil) if (window->ns.delegate == nil)
@ -1027,13 +1027,15 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
if (!initializeAppKit()) if (!initializeAppKit())
return GLFW_FALSE; return GLFW_FALSE;
if (!createWindow(window, wndconfig)) if (!createNativeWindow(window, wndconfig))
return GLFW_FALSE; return GLFW_FALSE;
if (ctxconfig->client != GLFW_NO_API) if (ctxconfig->client != GLFW_NO_API)
{ {
if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
{ {
if (!_glfwInitNSGL())
return GLFW_FALSE;
if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig)) if (!_glfwCreateContextNSGL(window, ctxconfig, fbconfig))
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -1067,7 +1069,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
if (window->monitor) if (window->monitor)
releaseMonitor(window); releaseMonitor(window);
if (window->context.client != GLFW_NO_API) if (window->context.destroy)
window->context.destroy(window); window->context.destroy(window);
[window->ns.object setDelegate:nil]; [window->ns.object setDelegate:nil];
@ -1538,7 +1540,7 @@ int _glfwPlatformCreateCursor(_GLFWcursor* cursor,
memcpy([rep bitmapData], image->pixels, image->width * image->height * 4); memcpy([rep bitmapData], image->pixels, image->width * image->height * 4);
native = [[NSImage alloc] initWithSize:NSMakeSize(image->width, image->height)]; native = [[NSImage alloc] initWithSize:NSMakeSize(image->width, image->height)];
[native addRepresentation: rep]; [native addRepresentation:rep];
cursor->ns.object = [[NSCursor alloc] initWithImage:native cursor->ns.object = [[NSCursor alloc] initWithImage:native
hotSpot:NSMakePoint(xhot, yhot)]; hotSpot:NSMakePoint(xhot, yhot)];

View File

@ -34,56 +34,6 @@
#include <stdio.h> #include <stdio.h>
// Parses the client API version string and extracts the version number
//
static GLFWbool parseVersionString(int* api, int* major, int* minor, int* rev)
{
int i;
_GLFWwindow* window;
const char* version;
const char* prefixes[] =
{
"OpenGL ES-CM ",
"OpenGL ES-CL ",
"OpenGL ES ",
NULL
};
*api = GLFW_OPENGL_API;
window = _glfwPlatformGetCurrentContext();
version = (const char*) window->context.GetString(GL_VERSION);
if (!version)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Client API version string retrieval is broken");
return GLFW_FALSE;
}
for (i = 0; prefixes[i]; i++)
{
const size_t length = strlen(prefixes[i]);
if (strncmp(version, prefixes[i], length) == 0)
{
version += length;
*api = GLFW_OPENGL_ES_API;
break;
}
}
if (!sscanf(version, "%d.%d.%d", major, minor, rev))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"No version found in client API version string");
return GLFW_FALSE;
}
return GLFW_TRUE;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW internal API ////// ////// GLFW internal API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -369,27 +319,79 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig) GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
{ {
_GLFWwindow* window = _glfwPlatformGetCurrentContext(); int i;
_GLFWwindow* window;
const char* version;
const char* prefixes[] =
{
"OpenGL ES-CM ",
"OpenGL ES-CL ",
"OpenGL ES ",
NULL
};
window = _glfwPlatformGetCurrentContext();
window->context.source = ctxconfig->source;
window->context.client = GLFW_OPENGL_API;
window->context.GetIntegerv = (PFNGLGETINTEGERVPROC) window->context.GetIntegerv = (PFNGLGETINTEGERVPROC)
glfwGetProcAddress("glGetIntegerv"); window->context.getProcAddress("glGetIntegerv");
window->context.GetString = (PFNGLGETSTRINGPROC) window->context.GetString = (PFNGLGETSTRINGPROC)
glfwGetProcAddress("glGetString"); window->context.getProcAddress("glGetString");
if (!window->context.GetIntegerv || !window->context.GetString) if (!window->context.GetIntegerv || !window->context.GetString)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken"); _glfwInputError(GLFW_PLATFORM_ERROR, "Entry point retrieval is broken");
return GLFW_FALSE; return GLFW_FALSE;
} }
if (!parseVersionString(&window->context.client, version = (const char*) window->context.GetString(GL_VERSION);
&window->context.major, if (!version)
&window->context.minor,
&window->context.revision))
{ {
if (ctxconfig->client == GLFW_OPENGL_API)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OpenGL version string retrieval is broken");
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"OpenGL ES version string retrieval is broken");
}
return GLFW_FALSE; return GLFW_FALSE;
} }
window->context.source = ctxconfig->source; for (i = 0; prefixes[i]; i++)
{
const size_t length = strlen(prefixes[i]);
if (strncmp(version, prefixes[i], length) == 0)
{
version += length;
window->context.client = GLFW_OPENGL_ES_API;
break;
}
}
if (!sscanf(version, "%d.%d.%d",
&window->context.major,
&window->context.minor,
&window->context.revision))
{
if (window->context.client == GLFW_OPENGL_API)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"No version found in OpenGL version string");
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"No version found in OpenGL ES version string");
}
return GLFW_FALSE;
}
if (window->context.major < ctxconfig->major || if (window->context.major < ctxconfig->major ||
(window->context.major == ctxconfig->major && (window->context.major == ctxconfig->major &&
@ -402,10 +404,21 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
// For API consistency, we emulate the behavior of the // For API consistency, we emulate the behavior of the
// {GLX|WGL}_ARB_create_context extension and fail here // {GLX|WGL}_ARB_create_context extension and fail here
_glfwInputError(GLFW_VERSION_UNAVAILABLE, if (window->context.client == GLFW_OPENGL_API)
"Requested client API version %i.%i, got version %i.%i", {
ctxconfig->major, ctxconfig->minor, _glfwInputError(GLFW_VERSION_UNAVAILABLE,
window->context.major, window->context.minor); "Requested OpenGL version %i.%i, got version %i.%i",
ctxconfig->major, ctxconfig->minor,
window->context.major, window->context.minor);
}
else
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"Requested OpenGL ES version %i.%i, got version %i.%i",
ctxconfig->major, ctxconfig->minor,
window->context.major, window->context.minor);
}
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -416,7 +429,7 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
// users as early as possible that their build may be broken // users as early as possible that their build may be broken
window->context.GetStringi = (PFNGLGETSTRINGIPROC) window->context.GetStringi = (PFNGLGETSTRINGIPROC)
glfwGetProcAddress("glGetStringi"); window->context.getProcAddress("glGetStringi");
if (!window->context.GetStringi) if (!window->context.GetStringi)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
@ -521,7 +534,8 @@ GLFWbool _glfwRefreshContextAttribs(const _GLFWctxconfig* ctxconfig)
// Clearing the front buffer to black to avoid garbage pixels left over from // Clearing the front buffer to black to avoid garbage pixels left over from
// previous uses of our bit of VRAM // previous uses of our bit of VRAM
{ {
PFNGLCLEARPROC glClear = (PFNGLCLEARPROC) glfwGetProcAddress("glClear"); PFNGLCLEARPROC glClear = (PFNGLCLEARPROC)
window->context.getProcAddress("glClear");
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
window->context.swapBuffers(window); window->context.swapBuffers(window);
} }

View File

@ -28,6 +28,7 @@
#include "internal.h" #include "internal.h"
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
@ -296,6 +297,9 @@ GLFWbool _glfwInitEGL(void)
NULL NULL
}; };
if (_glfw.egl.handle)
return GLFW_TRUE;
for (i = 0; sonames[i]; i++) for (i = 0; sonames[i]; i++)
{ {
_glfw.egl.handle = _glfw_dlopen(sonames[i]); _glfw.egl.handle = _glfw_dlopen(sonames[i]);
@ -304,7 +308,12 @@ GLFWbool _glfwInitEGL(void)
} }
if (!_glfw.egl.handle) if (!_glfw.egl.handle)
{
_glfwInputError(GLFW_API_UNAVAILABLE, "EGL: Library not found");
return GLFW_FALSE; return GLFW_FALSE;
}
_glfw.egl.prefix = (strncmp(sonames[i], "lib", 3) == 0);
_glfw.egl.GetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) _glfw.egl.GetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC)
_glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib"); _glfw_dlsym(_glfw.egl.handle, "eglGetConfigAttrib");
@ -339,6 +348,30 @@ GLFWbool _glfwInitEGL(void)
_glfw.egl.GetProcAddress = (PFNEGLGETPROCADDRESSPROC) _glfw.egl.GetProcAddress = (PFNEGLGETPROCADDRESSPROC)
_glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress"); _glfw_dlsym(_glfw.egl.handle, "eglGetProcAddress");
if (!_glfw.egl.GetConfigAttrib ||
!_glfw.egl.GetConfigs ||
!_glfw.egl.GetDisplay ||
!_glfw.egl.GetError ||
!_glfw.egl.Initialize ||
!_glfw.egl.Terminate ||
!_glfw.egl.BindAPI ||
!_glfw.egl.CreateContext ||
!_glfw.egl.DestroySurface ||
!_glfw.egl.DestroyContext ||
!_glfw.egl.CreateWindowSurface ||
!_glfw.egl.MakeCurrent ||
!_glfw.egl.SwapBuffers ||
!_glfw.egl.SwapInterval ||
!_glfw.egl.QueryString ||
!_glfw.egl.GetProcAddress)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"EGL: Failed to load required entry points");
_glfwTerminateEGL();
return GLFW_FALSE;
}
_glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY); _glfw.egl.display = eglGetDisplay(_GLFW_EGL_NATIVE_DISPLAY);
if (_glfw.egl.display == EGL_NO_DISPLAY) if (_glfw.egl.display == EGL_NO_DISPLAY)
{ {
@ -600,6 +633,11 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
for (i = 0; sonames[i]; i++) for (i = 0; sonames[i]; i++)
{ {
// HACK: Match presence of lib prefix to increase chance of finding
// a matching pair in the jungle that is Win32 EGL/GLES
if (_glfw.egl.prefix != (strncmp(sonames[i], "lib", 3) == 0))
continue;
window->context.egl.client = _glfw_dlopen(sonames[i]); window->context.egl.client = _glfw_dlopen(sonames[i]);
if (window->context.egl.client) if (window->context.egl.client)
break; break;

View File

@ -171,6 +171,7 @@ typedef struct _GLFWlibraryEGL
{ {
EGLDisplay display; EGLDisplay display;
EGLint major, minor; EGLint major, minor;
GLFWbool prefix;
GLFWbool KHR_create_context; GLFWbool KHR_create_context;
GLFWbool KHR_create_context_no_error; GLFWbool KHR_create_context_no_error;

View File

@ -47,6 +47,8 @@
// Define this to 1 if building as a shared library / dynamic library / DLL // Define this to 1 if building as a shared library / dynamic library / DLL
#cmakedefine _GLFW_BUILD_DLL #cmakedefine _GLFW_BUILD_DLL
// Define this to 1 to use Vulkan loader linked statically into application
#cmakedefine _GLFW_VULKAN_STATIC
// Define this to 1 to force use of high-performance GPU on hybrid systems // Define this to 1 to force use of high-performance GPU on hybrid systems
#cmakedefine _GLFW_USE_HYBRID_HPG #cmakedefine _GLFW_USE_HYBRID_HPG

View File

@ -30,7 +30,6 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <stdio.h>
#ifndef GLXBadProfileARB #ifndef GLXBadProfileARB
#define GLXBadProfileARB 13 #define GLXBadProfileARB 13
@ -180,20 +179,15 @@ static void swapIntervalGLX(int interval)
if (_glfw.glx.EXT_swap_control) if (_glfw.glx.EXT_swap_control)
{ {
fprintf (stderr, "swapping with glXSwapIntervalEXT\n");
_glfw.glx.SwapIntervalEXT(_glfw.x11.display, _glfw.glx.SwapIntervalEXT(_glfw.x11.display,
window->context.glx.window, window->context.glx.window,
interval); interval);
} }
else if (_glfw.glx.MESA_swap_control) else if (_glfw.glx.MESA_swap_control)
{
fprintf (stderr, "swapping with glXSwapIntervalMESA %d %p\n", interval, _glfw.glx.SwapIntervalMESA);
_glfw.glx.SwapIntervalMESA(interval); _glfw.glx.SwapIntervalMESA(interval);
}
else if (_glfw.glx.SGI_swap_control) else if (_glfw.glx.SGI_swap_control)
{ {
fprintf (stderr, "swapping with glXSwapIntervalSGI\n"); if (interval > 0)
if (interval > 0)
_glfw.glx.SwapIntervalSGI(interval); _glfw.glx.SwapIntervalSGI(interval);
} }
} }
@ -259,6 +253,9 @@ GLFWbool _glfwInitGLX(void)
NULL NULL
}; };
if (_glfw.glx.handle)
return GLFW_TRUE;
for (i = 0; sonames[i]; i++) for (i = 0; sonames[i]; i++)
{ {
_glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL); _glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL);
@ -303,6 +300,27 @@ GLFWbool _glfwInitGLX(void)
_glfw.glx.GetVisualFromFBConfig = _glfw.glx.GetVisualFromFBConfig =
dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig"); dlsym(_glfw.glx.handle, "glXGetVisualFromFBConfig");
if (!_glfw.glx.GetFBConfigs ||
!_glfw.glx.GetFBConfigAttrib ||
!_glfw.glx.GetClientString ||
!_glfw.glx.QueryExtension ||
!_glfw.glx.QueryVersion ||
!_glfw.glx.DestroyContext ||
!_glfw.glx.MakeCurrent ||
!_glfw.glx.SwapBuffers ||
!_glfw.glx.QueryExtensionsString ||
!_glfw.glx.CreateNewContext ||
!_glfw.glx.CreateWindow ||
!_glfw.glx.DestroyWindow ||
!_glfw.glx.GetProcAddress ||
!_glfw.glx.GetProcAddressARB ||
!_glfw.glx.GetVisualFromFBConfig)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"GLX: Failed to load required entry points");
return GLFW_FALSE;
}
if (!glXQueryExtension(_glfw.x11.display, if (!glXQueryExtension(_glfw.x11.display,
&_glfw.glx.errorBase, &_glfw.glx.errorBase,
&_glfw.glx.eventBase)) &_glfw.glx.eventBase))
@ -330,8 +348,6 @@ GLFWbool _glfwInitGLX(void)
_glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)
getProcAddressGLX("glXSwapIntervalEXT"); getProcAddressGLX("glXSwapIntervalEXT");
fprintf (stderr, "using glXSwapIntervalEXT\n");
if (_glfw.glx.SwapIntervalEXT) if (_glfw.glx.SwapIntervalEXT)
_glfw.glx.EXT_swap_control = GLFW_TRUE; _glfw.glx.EXT_swap_control = GLFW_TRUE;
} }
@ -341,9 +357,6 @@ GLFWbool _glfwInitGLX(void)
_glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) _glfw.glx.SwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)
getProcAddressGLX("glXSwapIntervalSGI"); getProcAddressGLX("glXSwapIntervalSGI");
fprintf (stderr, "using glXSwapIntervalSGI\n");
if (_glfw.glx.SwapIntervalSGI) if (_glfw.glx.SwapIntervalSGI)
_glfw.glx.SGI_swap_control = GLFW_TRUE; _glfw.glx.SGI_swap_control = GLFW_TRUE;
} }
@ -353,8 +366,6 @@ GLFWbool _glfwInitGLX(void)
_glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) _glfw.glx.SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC)
getProcAddressGLX("glXSwapIntervalMESA"); getProcAddressGLX("glXSwapIntervalMESA");
fprintf (stderr, "using glXSwapIntervalMESA\n");
if (_glfw.glx.SwapIntervalMESA) if (_glfw.glx.SwapIntervalMESA)
_glfw.glx.MESA_swap_control = GLFW_TRUE; _glfw.glx.MESA_swap_control = GLFW_TRUE;
} }

View File

@ -84,7 +84,7 @@ typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable);
typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int); typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int);
typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*); typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*);
typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool); typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool);
typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC) (const GLubyte *procName); typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName);
typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int); typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int);
typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int); typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int);
typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int); typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int);

View File

@ -65,9 +65,9 @@ static const char* getErrorString(int error)
case GLFW_OUT_OF_MEMORY: case GLFW_OUT_OF_MEMORY:
return "Out of memory"; return "Out of memory";
case GLFW_API_UNAVAILABLE: case GLFW_API_UNAVAILABLE:
return "The requested client API is unavailable"; return "The requested API is unavailable";
case GLFW_VERSION_UNAVAILABLE: case GLFW_VERSION_UNAVAILABLE:
return "The requested client API version is unavailable"; return "The requested API version is unavailable";
case GLFW_PLATFORM_ERROR: case GLFW_PLATFORM_ERROR:
return "A platform-specific error occurred"; return "A platform-specific error occurred";
case GLFW_FORMAT_UNAVAILABLE: case GLFW_FORMAT_UNAVAILABLE:
@ -130,8 +130,6 @@ GLFWAPI int glfwInit(void)
return GLFW_FALSE; return GLFW_FALSE;
} }
_glfwInitVulkan();
_glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount); _glfw.monitors = _glfwPlatformGetMonitors(&_glfw.monitorCount);
_glfwInitialized = GLFW_TRUE; _glfwInitialized = GLFW_TRUE;

View File

@ -40,6 +40,7 @@
defined(GLFW_INCLUDE_NONE) || \ defined(GLFW_INCLUDE_NONE) || \
defined(GLFW_INCLUDE_GLEXT) || \ defined(GLFW_INCLUDE_GLEXT) || \
defined(GLFW_INCLUDE_GLU) || \ defined(GLFW_INCLUDE_GLU) || \
defined(GLFW_INCLUDE_VULKAN) || \
defined(GLFW_DLL) defined(GLFW_DLL)
#error "You must not define any header option macros when compiling GLFW" #error "You must not define any header option macros when compiling GLFW"
#endif #endif
@ -149,11 +150,16 @@ typedef struct VkExtensionProperties
} VkExtensionProperties; } VkExtensionProperties;
typedef void (APIENTRY * PFN_vkVoidFunction)(void); typedef void (APIENTRY * PFN_vkVoidFunction)(void);
typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*);
typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*);
#define vkEnumerateInstanceExtensionProperties _glfw.vk.EnumerateInstanceExtensionProperties #if defined(_GLFW_VULKAN_STATIC)
#define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr PFN_vkVoidFunction vkGetInstanceProcAddr(VkInstance,const char*);
VkResult vkEnumerateInstanceExtensionProperties(const char*,uint32_t*,VkExtensionProperties*);
#else
typedef PFN_vkVoidFunction (APIENTRY * PFN_vkGetInstanceProcAddr)(VkInstance,const char*);
typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const char*,uint32_t*,VkExtensionProperties*);
#define vkEnumerateInstanceExtensionProperties _glfw.vk.EnumerateInstanceExtensionProperties
#define vkGetInstanceProcAddr _glfw.vk.GetInstanceProcAddr
#endif
#if defined(_GLFW_COCOA) #if defined(_GLFW_COCOA)
#include "cocoa_platform.h" #include "cocoa_platform.h"
@ -445,8 +451,10 @@ struct _GLFWlibrary
void* handle; void* handle;
char** extensions; char** extensions;
uint32_t extensionCount; uint32_t extensionCount;
#if !defined(_GLFW_VULKAN_STATIC)
PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties;
PFN_vkGetInstanceProcAddr GetInstanceProcAddr; PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
#endif
GLFWbool KHR_surface; GLFWbool KHR_surface;
GLFWbool KHR_win32_surface; GLFWbool KHR_win32_surface;
GLFWbool KHR_xlib_surface; GLFWbool KHR_xlib_surface;
@ -1034,7 +1042,7 @@ GLFWbool _glfwIsPrintable(int key);
/*! @ingroup utility /*! @ingroup utility
*/ */
void _glfwInitVulkan(void); GLFWbool _glfwInitVulkan(void);
/*! @ingroup utility /*! @ingroup utility
*/ */

View File

@ -49,7 +49,7 @@
static GLFWbool openJoystickDevice(const char* path) static GLFWbool openJoystickDevice(const char* path)
{ {
char axisCount, buttonCount; char axisCount, buttonCount;
char name[256]; char name[256] = "";
int joy, fd, version; int joy, fd, version;
_GLFWjoystickLinux* js; _GLFWjoystickLinux* js;
@ -153,7 +153,7 @@ static GLFWbool pollJoystickEvents(_GLFWjoystickLinux* js)
return js->present; return js->present;
} }
// Lexically compare joysticks, used by quicksort // Lexically compare joysticks by name; used by qsort
// //
#if defined(__linux__) #if defined(__linux__)
static int compareJoysticks(const void* fp, const void* sp) static int compareJoysticks(const void* fp, const void* sp)

View File

@ -183,9 +183,6 @@ int _glfwPlatformInit(void)
if (!_glfwInitThreadLocalStoragePOSIX()) if (!_glfwInitThreadLocalStoragePOSIX())
return GLFW_FALSE; return GLFW_FALSE;
if (!_glfwInitEGL())
return GLFW_FALSE;
if (!_glfwInitJoysticksLinux()) if (!_glfwInitJoysticksLinux())
return GLFW_FALSE; return GLFW_FALSE;

View File

@ -379,6 +379,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
if (ctxconfig->client != GLFW_NO_API) if (ctxconfig->client != GLFW_NO_API)
{ {
if (!_glfwInitEGL())
return GLFW_FALSE;
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -394,7 +396,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
window->mir.surface = NULL; window->mir.surface = NULL;
} }
if (window->context.client != GLFW_NO_API) if (window->context.destroy)
window->context.destroy(window); window->context.destroy(window);
} }

View File

@ -92,6 +92,9 @@ static void destroyContextNSGL(_GLFWwindow* window)
// //
GLFWbool _glfwInitNSGL(void) GLFWbool _glfwInitNSGL(void)
{ {
if (_glfw.nsgl.framework)
return GLFW_TRUE;
_glfw.nsgl.framework = _glfw.nsgl.framework =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
if (_glfw.nsgl.framework == NULL) if (_glfw.nsgl.framework == NULL)

View File

@ -36,20 +36,25 @@
////// GLFW internal API ////// ////// GLFW internal API //////
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void _glfwInitVulkan(void) GLFWbool _glfwInitVulkan(void)
{ {
VkResult err; VkResult err;
VkExtensionProperties* ep; VkExtensionProperties* ep;
uint32_t i, count; uint32_t i, count;
#if !defined(_GLFW_VULKAN_STATIC)
#if defined(_GLFW_WIN32) #if defined(_GLFW_WIN32)
const char* name = "vulkan-1.dll"; const char* name = "vulkan-1.dll";
#else #else
const char* name = "libvulkan.so.1"; const char* name = "libvulkan.so.1";
#endif #endif
if (_glfw.vk.available)
return GLFW_TRUE;
_glfw.vk.handle = _glfw_dlopen(name); _glfw.vk.handle = _glfw_dlopen(name);
if (!_glfw.vk.handle) if (!_glfw.vk.handle)
return; return GLFW_FALSE;
_glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr) _glfw.vk.GetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)
_glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr"); _glfw_dlsym(_glfw.vk.handle, "vkGetInstanceProcAddr");
@ -57,7 +62,9 @@ void _glfwInitVulkan(void)
{ {
_glfwInputError(GLFW_API_UNAVAILABLE, _glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Loader does not export vkGetInstanceProcAddr"); "Vulkan: Loader does not export vkGetInstanceProcAddr");
return;
_glfwTerminateVulkan();
return GLFW_FALSE;
} }
_glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties) _glfw.vk.EnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)
@ -66,8 +73,11 @@ void _glfwInitVulkan(void)
{ {
_glfwInputError(GLFW_API_UNAVAILABLE, _glfwInputError(GLFW_API_UNAVAILABLE,
"Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties"); "Vulkan: Failed to retrieve vkEnumerateInstanceExtensionProperties");
return;
_glfwTerminateVulkan();
return GLFW_FALSE;
} }
#endif // _GLFW_VULKAN_STATIC
err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL); err = vkEnumerateInstanceExtensionProperties(NULL, &count, NULL);
if (err) if (err)
@ -75,7 +85,9 @@ void _glfwInitVulkan(void)
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Vulkan: Failed to query instance extension count: %s", "Vulkan: Failed to query instance extension count: %s",
_glfwGetVulkanResultString(err)); _glfwGetVulkanResultString(err));
return;
_glfwTerminateVulkan();
return GLFW_FALSE;
} }
ep = calloc(count, sizeof(VkExtensionProperties)); ep = calloc(count, sizeof(VkExtensionProperties));
@ -88,7 +100,8 @@ void _glfwInitVulkan(void)
_glfwGetVulkanResultString(err)); _glfwGetVulkanResultString(err));
free(ep); free(ep);
return; _glfwTerminateVulkan();
return GLFW_FALSE;
} }
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
@ -111,11 +124,13 @@ void _glfwInitVulkan(void)
_glfw.vk.available = GLFW_TRUE; _glfw.vk.available = GLFW_TRUE;
if (!_glfw.vk.KHR_surface) if (_glfw.vk.KHR_surface)
return; {
_glfw.vk.extensions =
_glfwPlatformGetRequiredInstanceExtensions(&_glfw.vk.extensionCount);
}
_glfw.vk.extensions = return GLFW_TRUE;
_glfwPlatformGetRequiredInstanceExtensions(&_glfw.vk.extensionCount);
} }
void _glfwTerminateVulkan(void) void _glfwTerminateVulkan(void)
@ -193,7 +208,7 @@ const char* _glfwGetVulkanResultString(VkResult result)
GLFWAPI int glfwVulkanSupported(void) GLFWAPI int glfwVulkanSupported(void)
{ {
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
return _glfw.vk.available; return _glfwInitVulkan();
} }
GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count) GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count)
@ -202,9 +217,9 @@ GLFWAPI const char** glfwGetRequiredInstanceExtensions(uint32_t* count)
_GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (!_glfw.vk.available) if (!_glfwInitVulkan())
{ {
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found"); _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
return NULL; return NULL;
} }
@ -219,9 +234,9 @@ GLFWAPI GLFWvkproc glfwGetInstanceProcAddress(VkInstance instance,
_GLFW_REQUIRE_INIT_OR_RETURN(NULL); _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (!_glfw.vk.available) if (!_glfwInitVulkan())
{ {
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found"); _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
return NULL; return NULL;
} }
@ -238,9 +253,9 @@ GLFWAPI int glfwGetPhysicalDevicePresentationSupport(VkInstance instance,
{ {
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
if (!_glfw.vk.available) if (!_glfwInitVulkan())
{ {
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found"); _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -263,15 +278,15 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance,
{ {
_GLFWwindow* window = (_GLFWwindow*) handle; _GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL); assert(window != NULL);
assert(surface != NULL); assert(surface != NULL);
*surface = VK_NULL_HANDLE; *surface = VK_NULL_HANDLE;
_GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED); _GLFW_REQUIRE_INIT_OR_RETURN(VK_ERROR_INITIALIZATION_FAILED);
if (!_glfw.vk.available) if (!_glfwInitVulkan())
{ {
_glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: Loader not found"); _glfwInputError(GLFW_API_UNAVAILABLE, "Vulkan: API not available");
return VK_ERROR_INITIALIZATION_FAILED; return VK_ERROR_INITIALIZATION_FAILED;
} }

View File

@ -55,19 +55,17 @@ static int getPixelFormatAttrib(_GLFWwindow* window, int pixelFormat, int attrib
// Return a list of available and usable framebuffer configs // Return a list of available and usable framebuffer configs
// //
static GLFWbool choosePixelFormat(_GLFWwindow* window, static int choosePixelFormat(_GLFWwindow* window, const _GLFWfbconfig* desired)
const _GLFWfbconfig* desired,
int* result)
{ {
_GLFWfbconfig* usableConfigs; _GLFWfbconfig* usableConfigs;
const _GLFWfbconfig* closest; const _GLFWfbconfig* closest;
int i, nativeCount, usableCount; int i, pixelFormat, nativeCount, usableCount;
if (_glfw.wgl.ARB_pixel_format) if (_glfw.wgl.ARB_pixel_format)
{ {
nativeCount = getPixelFormatAttrib(window, nativeCount = getPixelFormatAttrib(window,
1, 1,
WGL_NUMBER_PIXEL_FORMATS_ARB); WGL_NUMBER_PIXEL_FORMATS_ARB);
} }
else else
{ {
@ -197,7 +195,7 @@ static GLFWbool choosePixelFormat(_GLFWwindow* window,
"WGL: The driver does not appear to support OpenGL"); "WGL: The driver does not appear to support OpenGL");
free(usableConfigs); free(usableConfigs);
return GLFW_FALSE; return 0;
} }
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
@ -207,13 +205,13 @@ static GLFWbool choosePixelFormat(_GLFWwindow* window,
"WGL: Failed to find a suitable pixel format"); "WGL: Failed to find a suitable pixel format");
free(usableConfigs); free(usableConfigs);
return GLFW_FALSE; return 0;
} }
*result = (int) closest->handle; pixelFormat = (int) closest->handle;
free(usableConfigs); free(usableConfigs);
return GLFW_TRUE; return pixelFormat;
} }
// Returns whether desktop compositing is enabled // Returns whether desktop compositing is enabled
@ -288,8 +286,6 @@ static int extensionSupportedWGL(const char* extension)
{ {
const char* extensions; const char* extensions;
_GLFWwindow* window = _glfwPlatformGetCurrentContext();
if (_glfw.wgl.GetExtensionsStringEXT) if (_glfw.wgl.GetExtensionsStringEXT)
{ {
extensions = _glfw.wgl.GetExtensionsStringEXT(); extensions = _glfw.wgl.GetExtensionsStringEXT();
@ -302,7 +298,7 @@ static int extensionSupportedWGL(const char* extension)
if (_glfw.wgl.GetExtensionsStringARB) if (_glfw.wgl.GetExtensionsStringARB)
{ {
extensions = _glfw.wgl.GetExtensionsStringARB(window->context.wgl.dc); extensions = _glfw.wgl.GetExtensionsStringARB(wglGetCurrentDC());
if (extensions) if (extensions)
{ {
if (_glfwStringInExtensionString(extension, extensions)) if (_glfwStringInExtensionString(extension, extensions))
@ -335,29 +331,65 @@ static void destroyContextWGL(_GLFWwindow* window)
// Initialize WGL-specific extensions // Initialize WGL-specific extensions
// //
static void loadExtensions(void) static void loadWGLExtensions(void)
{ {
// Functions for WGL_EXT_extension_string PIXELFORMATDESCRIPTOR pfd;
// NOTE: These are needed by extensionSupported HGLRC rc;
HDC dc = GetDC(_glfw.win32.helperWindowHandle);;
_glfw.wgl.extensionsLoaded = GLFW_TRUE;
// 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
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
if (!SetPixelFormat(dc, ChoosePixelFormat(dc, &pfd), &pfd))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to set pixel format for dummy context");
return;
}
rc = wglCreateContext(dc);
if (!rc)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to create dummy context");
return;
}
if (!wglMakeCurrent(dc, rc))
{
wglDeleteContext(rc);
_glfwInputError(GLFW_PLATFORM_ERROR,
"WGL: Failed to make dummy context current");
return;
}
// NOTE: Functions must be loaded first as they're needed to retrieve the
// extension string that tells us whether the functions are supported
_glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) _glfw.wgl.GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC)
wglGetProcAddress("wglGetExtensionsStringEXT"); wglGetProcAddress("wglGetExtensionsStringEXT");
_glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) _glfw.wgl.GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)
wglGetProcAddress("wglGetExtensionsStringARB"); wglGetProcAddress("wglGetExtensionsStringARB");
// Functions for WGL_ARB_create_context
_glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) _glfw.wgl.CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)
wglGetProcAddress("wglCreateContextAttribsARB"); wglGetProcAddress("wglCreateContextAttribsARB");
// Functions for WGL_EXT_swap_control
_glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) _glfw.wgl.SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)
wglGetProcAddress("wglSwapIntervalEXT"); wglGetProcAddress("wglSwapIntervalEXT");
// Functions for WGL_ARB_pixel_format
_glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) _glfw.wgl.GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)
wglGetProcAddress("wglGetPixelFormatAttribivARB"); wglGetProcAddress("wglGetPixelFormatAttribivARB");
// This needs to include every extension used below except for // NOTE: WGL_ARB_extensions_string and WGL_EXT_extensions_string are not
// WGL_ARB_extensions_string and WGL_EXT_extensions_string // checked below as we are already using them
_glfw.wgl.ARB_multisample = _glfw.wgl.ARB_multisample =
extensionSupportedWGL("WGL_ARB_multisample"); extensionSupportedWGL("WGL_ARB_multisample");
_glfw.wgl.ARB_framebuffer_sRGB = _glfw.wgl.ARB_framebuffer_sRGB =
@ -379,7 +411,8 @@ static void loadExtensions(void)
_glfw.wgl.ARB_context_flush_control = _glfw.wgl.ARB_context_flush_control =
extensionSupportedWGL("WGL_ARB_context_flush_control"); extensionSupportedWGL("WGL_ARB_context_flush_control");
_glfw.wgl.extensionsLoaded = GLFW_TRUE; wglMakeCurrent(dc, NULL);
wglDeleteContext(rc);
} }
@ -391,6 +424,9 @@ static void loadExtensions(void)
// //
GLFWbool _glfwInitWGL(void) GLFWbool _glfwInitWGL(void)
{ {
if (_glfw.wgl.instance)
return GLFW_TRUE;
_glfw.wgl.instance = LoadLibraryA("opengl32.dll"); _glfw.wgl.instance = LoadLibraryA("opengl32.dll");
if (!_glfw.wgl.instance) if (!_glfw.wgl.instance)
{ {
@ -404,6 +440,8 @@ GLFWbool _glfwInitWGL(void)
GetProcAddress(_glfw.wgl.instance, "wglDeleteContext"); GetProcAddress(_glfw.wgl.instance, "wglDeleteContext");
_glfw.wgl.GetProcAddress = (WGLGETPROCADDRESS_T) _glfw.wgl.GetProcAddress = (WGLGETPROCADDRESS_T)
GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress"); GetProcAddress(_glfw.wgl.instance, "wglGetProcAddress");
_glfw.wgl.GetCurrentDC = (WGLGETCURRENTDC_T)
GetProcAddress(_glfw.wgl.instance, "wglGetCurrentDC");
_glfw.wgl.MakeCurrent = (WGLMAKECURRENT_T) _glfw.wgl.MakeCurrent = (WGLMAKECURRENT_T)
GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent"); GetProcAddress(_glfw.wgl.instance, "wglMakeCurrent");
_glfw.wgl.ShareLists = (WGLSHARELISTS_T) _glfw.wgl.ShareLists = (WGLSHARELISTS_T)
@ -434,12 +472,12 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
const _GLFWfbconfig* fbconfig) const _GLFWfbconfig* fbconfig)
{ {
int attribs[40]; int attribs[40];
int pixelFormat = 0; int pixelFormat;
PIXELFORMATDESCRIPTOR pfd; PIXELFORMATDESCRIPTOR pfd;
HGLRC share = NULL; HGLRC share = NULL;
if (ctxconfig->client == GLFW_NO_API) if (!_glfw.wgl.extensionsLoaded)
return GLFW_TRUE; loadWGLExtensions();
if (ctxconfig->share) if (ctxconfig->share)
share = ctxconfig->share->context.wgl.handle; share = ctxconfig->share->context.wgl.handle;
@ -452,7 +490,8 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
return GLFW_FALSE; return GLFW_FALSE;
} }
if (!choosePixelFormat(window, fbconfig, &pixelFormat)) pixelFormat = choosePixelFormat(window, fbconfig);
if (!pixelFormat)
return GLFW_FALSE; return GLFW_FALSE;
if (!DescribePixelFormat(window->context.wgl.dc, if (!DescribePixelFormat(window->context.wgl.dc,
@ -470,6 +509,40 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
return GLFW_FALSE; return GLFW_FALSE;
} }
if (ctxconfig->client == GLFW_OPENGL_API)
{
if (ctxconfig->forward)
{
if (!_glfw.wgl.ARB_create_context)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable");
return GLFW_FALSE;
}
}
if (ctxconfig->profile)
{
if (!_glfw.wgl.ARB_create_context_profile)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable");
return GLFW_FALSE;
}
}
}
else
{
if (!_glfw.wgl.ARB_create_context ||
!_glfw.wgl.ARB_create_context_profile ||
!_glfw.wgl.EXT_create_context_es2_profile)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable");
return GLFW_FALSE;
}
}
if (_glfw.wgl.ARB_create_context) if (_glfw.wgl.ARB_create_context)
{ {
int index = 0, mask = 0, flags = 0; int index = 0, mask = 0, flags = 0;
@ -550,8 +623,44 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
share, attribs); share, attribs);
if (!window->context.wgl.handle) if (!window->context.wgl.handle)
{ {
_glfwInputError(GLFW_VERSION_UNAVAILABLE, const DWORD error = GetLastError();
"WGL: Failed to create OpenGL context");
if (error == (0xc0070000 | ERROR_INVALID_VERSION_ARB))
{
if (ctxconfig->client == GLFW_OPENGL_API)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: Driver does not support OpenGL version %i.%i",
ctxconfig->major,
ctxconfig->minor);
}
else
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: Driver does not support OpenGL ES version %i.%i",
ctxconfig->major,
ctxconfig->minor);
}
}
else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB))
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: Driver does not support the requested OpenGL profile");
}
else
{
if (ctxconfig->client == GLFW_OPENGL_API)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: Failed to create OpenGL context");
}
else
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: Failed to create OpenGL ES context");
}
}
return GLFW_FALSE; return GLFW_FALSE;
} }
} }
@ -588,102 +697,6 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
#undef setWGLattrib #undef setWGLattrib
// Analyzes the specified context for possible recreation
//
int _glfwAnalyzeContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
GLFWbool required = GLFW_FALSE;
if (_glfw.wgl.extensionsLoaded)
return _GLFW_RECREATION_NOT_NEEDED;
makeContextCurrentWGL(window);
loadExtensions();
if (ctxconfig->client == GLFW_OPENGL_API)
{
if (ctxconfig->forward)
{
if (!_glfw.wgl.ARB_create_context)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: A forward compatible OpenGL context requested but WGL_ARB_create_context is unavailable");
return _GLFW_RECREATION_IMPOSSIBLE;
}
required = GLFW_TRUE;
}
if (ctxconfig->profile)
{
if (!_glfw.wgl.ARB_create_context_profile)
{
_glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: OpenGL profile requested but WGL_ARB_create_context_profile is unavailable");
return _GLFW_RECREATION_IMPOSSIBLE;
}
required = GLFW_TRUE;
}
if (ctxconfig->release)
{
if (_glfw.wgl.ARB_context_flush_control)
required = GLFW_TRUE;
}
}
else
{
if (!_glfw.wgl.ARB_create_context ||
!_glfw.wgl.ARB_create_context_profile ||
!_glfw.wgl.EXT_create_context_es2_profile)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"WGL: OpenGL ES requested but WGL_ARB_create_context_es2_profile is unavailable");
return _GLFW_RECREATION_IMPOSSIBLE;
}
required = GLFW_TRUE;
}
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{
if (_glfw.wgl.ARB_create_context)
required = GLFW_TRUE;
}
if (ctxconfig->debug)
{
if (_glfw.wgl.ARB_create_context)
required = GLFW_TRUE;
}
if (fbconfig->samples > 0)
{
// MSAA is not a hard constraint, so do nothing if it's not supported
if (_glfw.wgl.ARB_multisample && _glfw.wgl.ARB_pixel_format)
required = GLFW_TRUE;
}
if (fbconfig->sRGB)
{
// sRGB is not a hard constraint, so do nothing if it's not supported
if ((_glfw.wgl.ARB_framebuffer_sRGB ||
_glfw.wgl.EXT_framebuffer_sRGB) &&
_glfw.wgl.ARB_pixel_format)
{
required = GLFW_TRUE;
}
}
if (required)
return _GLFW_RECREATION_REQUIRED;
return _GLFW_RECREATION_NOT_NEEDED;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW native API ////// ////// GLFW native API //////

View File

@ -73,6 +73,9 @@
#define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0 #define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
#define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098 #define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
#define ERROR_INVALID_VERSION_ARB 0x2095
#define ERROR_INVALID_PROFILE_ARB 0x2096
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*); typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*);
typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void); typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void);
@ -82,6 +85,7 @@ typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*)
typedef HGLRC (WINAPI * WGLCREATECONTEXT_T)(HDC); typedef HGLRC (WINAPI * WGLCREATECONTEXT_T)(HDC);
typedef BOOL (WINAPI * WGLDELETECONTEXT_T)(HGLRC); typedef BOOL (WINAPI * WGLDELETECONTEXT_T)(HGLRC);
typedef PROC (WINAPI * WGLGETPROCADDRESS_T)(LPCSTR); typedef PROC (WINAPI * WGLGETPROCADDRESS_T)(LPCSTR);
typedef HDC (WINAPI * WGLGETCURRENTDC_T)(void);
typedef BOOL (WINAPI * WGLMAKECURRENT_T)(HDC,HGLRC); typedef BOOL (WINAPI * WGLMAKECURRENT_T)(HDC,HGLRC);
typedef BOOL (WINAPI * WGLSHARELISTS_T)(HGLRC,HGLRC); typedef BOOL (WINAPI * WGLSHARELISTS_T)(HGLRC,HGLRC);
@ -89,6 +93,7 @@ typedef BOOL (WINAPI * WGLSHARELISTS_T)(HGLRC,HGLRC);
#define wglCreateContext _glfw.wgl.CreateContext #define wglCreateContext _glfw.wgl.CreateContext
#define wglDeleteContext _glfw.wgl.DeleteContext #define wglDeleteContext _glfw.wgl.DeleteContext
#define wglGetProcAddress _glfw.wgl.GetProcAddress #define wglGetProcAddress _glfw.wgl.GetProcAddress
#define wglGetCurrentDC _glfw.wgl.GetCurrentDC
#define wglMakeCurrent _glfw.wgl.MakeCurrent #define wglMakeCurrent _glfw.wgl.MakeCurrent
#define wglShareLists _glfw.wgl.ShareLists #define wglShareLists _glfw.wgl.ShareLists
@ -118,6 +123,7 @@ typedef struct _GLFWlibraryWGL
WGLCREATECONTEXT_T CreateContext; WGLCREATECONTEXT_T CreateContext;
WGLDELETECONTEXT_T DeleteContext; WGLDELETECONTEXT_T DeleteContext;
WGLGETPROCADDRESS_T GetProcAddress; WGLGETPROCADDRESS_T GetProcAddress;
WGLGETCURRENTDC_T GetCurrentDC;
WGLMAKECURRENT_T MakeCurrent; WGLMAKECURRENT_T MakeCurrent;
WGLSHARELISTS_T ShareLists; WGLSHARELISTS_T ShareLists;
@ -147,8 +153,5 @@ void _glfwTerminateWGL(void);
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig); const _GLFWfbconfig* fbconfig);
int _glfwAnalyzeContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
#endif // _glfw3_wgl_context_h_ #endif // _glfw3_wgl_context_h_

View File

@ -319,6 +319,10 @@ static HWND createHelperWindow(void)
return NULL; return NULL;
} }
// HACK: The first call to ShowWindow is ignored if the parent process
// passed along a STARTUPINFO, so clear that flag with a no-op call
ShowWindow(window, SW_HIDE);
// Register for HID device notifications // Register for HID device notifications
{ {
DEV_BROADCAST_DEVICEINTERFACE_W dbi; DEV_BROADCAST_DEVICEINTERFACE_W dbi;
@ -373,7 +377,7 @@ char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source)
if (!length) if (!length)
return NULL; return NULL;
target = calloc(length, sizeof(char)); target = calloc(length, 1);
if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, length, NULL, NULL)) if (!WideCharToMultiByte(CP_UTF8, 0, source, -1, target, length, NULL, NULL))
{ {
@ -421,10 +425,6 @@ int _glfwPlatformInit(void)
_glfwPlatformPollEvents(); _glfwPlatformPollEvents();
if (!_glfwInitWGL())
return GLFW_FALSE;
_glfwInitEGL();
_glfwInitTimerWin32(); _glfwInitTimerWin32();
_glfwInitJoysticksWin32(); _glfwInitJoysticksWin32();

View File

@ -176,7 +176,7 @@ static int compareJoystickObjects(const void* first, const void* second)
// //
static GLFWbool supportsXInput(const GUID* guid) static GLFWbool supportsXInput(const GUID* guid)
{ {
UINT i, count; UINT i, count = 0;
RAWINPUTDEVICELIST* ridl; RAWINPUTDEVICELIST* ridl;
GLFWbool result = GLFW_FALSE; GLFWbool result = GLFW_FALSE;
@ -185,7 +185,7 @@ static GLFWbool supportsXInput(const GUID* guid)
ridl = calloc(count, sizeof(RAWINPUTDEVICELIST)); ridl = calloc(count, sizeof(RAWINPUTDEVICELIST));
if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == -1) if (GetRawInputDeviceList(ridl, &count, sizeof(RAWINPUTDEVICELIST)) == (UINT) -1)
{ {
free(ridl); free(ridl);
return GLFW_FALSE; return GLFW_FALSE;
@ -211,7 +211,7 @@ static GLFWbool supportsXInput(const GUID* guid)
continue; continue;
} }
if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != guid->Data1) if (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) != (LONG) guid->Data1)
continue; continue;
memset(name, 0, sizeof(name)); memset(name, 0, sizeof(name));

View File

@ -850,9 +850,10 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
return DefWindowProcW(hWnd, uMsg, wParam, lParam); return DefWindowProcW(hWnd, uMsg, wParam, lParam);
} }
// Creates the GLFW window and rendering context // Creates the GLFW window
// //
static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) static int createNativeWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig)
{ {
int xpos, ypos, fullWidth, fullHeight; int xpos, ypos, fullWidth, fullHeight;
WCHAR* wideTitle; WCHAR* wideTitle;
@ -928,21 +929,6 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig)
return GLFW_TRUE; return GLFW_TRUE;
} }
// Destroys the GLFW window and rendering context
//
static void destroyWindow(_GLFWwindow* window)
{
if (_glfw.win32.disabledCursorWindow == window)
_glfw.win32.disabledCursorWindow = NULL;
if (window->win32.handle)
{
RemovePropW(window->win32.handle, L"GLFW");
DestroyWindow(window->win32.handle);
window->win32.handle = NULL;
}
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
////// GLFW internal API ////// ////// GLFW internal API //////
@ -1001,60 +987,22 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig) const _GLFWfbconfig* fbconfig)
{ {
int status; if (!createNativeWindow(window, wndconfig))
if (!createWindow(window, wndconfig))
return GLFW_FALSE; return GLFW_FALSE;
if (ctxconfig->client != GLFW_NO_API) if (ctxconfig->client != GLFW_NO_API)
{ {
if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
{ {
if (!_glfwInitWGL())
return GLFW_FALSE;
if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig)) if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
return GLFW_FALSE; return GLFW_FALSE;
status = _glfwAnalyzeContextWGL(window, ctxconfig, fbconfig);
if (status == _GLFW_RECREATION_IMPOSSIBLE)
return GLFW_FALSE;
if (status == _GLFW_RECREATION_REQUIRED)
{
// Some window hints require us to re-create the context using WGL
// extensions retrieved through the current context, as we cannot
// check for WGL extensions or retrieve WGL entry points before we
// have a current context (actually until we have implicitly loaded
// the vendor ICD)
// Yes, this is strange, and yes, this is the proper way on WGL
// As Windows only allows you to set the pixel format once for
// a window, we need to destroy the current window and create a new
// one to be able to use the new pixel format
// Technically, it may be possible to keep the old window around if
// we're just creating an OpenGL 3.0+ context with the same pixel
// format, but it's not worth the added code complexity
// First we clear the current context (the one we just created)
// This is usually done by glfwDestroyWindow, but as we're not doing
// full GLFW window destruction, it's duplicated here
window->context.makeCurrent(NULL);
// Next destroy the Win32 window and WGL context (without resetting
// or destroying the GLFW window object)
window->context.destroy(window);
destroyWindow(window);
// ...and then create them again, this time with better APIs
if (!createWindow(window, wndconfig))
return GLFW_FALSE;
if (!_glfwCreateContextWGL(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
} }
else else
{ {
if (!_glfwInitEGL())
return GLFW_FALSE;
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -1078,10 +1026,18 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
if (window->monitor) if (window->monitor)
releaseMonitor(window); releaseMonitor(window);
if (window->context.client != GLFW_NO_API) if (window->context.destroy)
window->context.destroy(window); window->context.destroy(window);
destroyWindow(window); if (_glfw.win32.disabledCursorWindow == window)
_glfw.win32.disabledCursorWindow = NULL;
if (window->win32.handle)
{
RemovePropW(window->win32.handle, L"GLFW");
DestroyWindow(window->win32.handle);
window->win32.handle = NULL;
}
if (window->win32.bigIcon) if (window->win32.bigIcon)
DestroyIcon(window->win32.bigIcon); DestroyIcon(window->win32.bigIcon);
@ -1594,52 +1550,55 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string)
{ {
WCHAR* wideString; int characterCount;
HANDLE stringHandle; HANDLE object;
size_t wideSize; WCHAR* buffer;
wideString = _glfwCreateWideStringFromUTF8Win32(string); characterCount = MultiByteToWideChar(CP_UTF8, 0, string, -1, NULL, 0);
if (!wideString) if (!characterCount)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to convert string to UTF-16"); "Win32: Failed to convert clipboard string to UTF-16");
return; return;
} }
wideSize = (wcslen(wideString) + 1) * sizeof(WCHAR); object = GlobalAlloc(GMEM_MOVEABLE, characterCount * sizeof(WCHAR));
if (!object)
stringHandle = GlobalAlloc(GMEM_MOVEABLE, wideSize);
if (!stringHandle)
{ {
free(wideString);
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"Win32: Failed to allocate global handle for clipboard"); "Win32: Failed to allocate global handle for clipboard");
return; return;
} }
memcpy(GlobalLock(stringHandle), wideString, wideSize); buffer = GlobalLock(object);
GlobalUnlock(stringHandle); if (!buffer)
{
GlobalFree(object);
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to lock global handle");
return;
}
MultiByteToWideChar(CP_UTF8, 0, string, -1, buffer, characterCount);
GlobalUnlock(object);
if (!OpenClipboard(_glfw.win32.helperWindowHandle)) if (!OpenClipboard(_glfw.win32.helperWindowHandle))
{ {
GlobalFree(stringHandle); GlobalFree(object);
free(wideString);
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard"); _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to open clipboard");
return; return;
} }
EmptyClipboard(); EmptyClipboard();
SetClipboardData(CF_UNICODETEXT, stringHandle); SetClipboardData(CF_UNICODETEXT, object);
CloseClipboard(); CloseClipboard();
free(wideString);
} }
const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
{ {
HANDLE stringHandle; HANDLE object;
WCHAR* buffer;
if (!OpenClipboard(_glfw.win32.helperWindowHandle)) if (!OpenClipboard(_glfw.win32.helperWindowHandle))
{ {
@ -1647,8 +1606,8 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
return NULL; return NULL;
} }
stringHandle = GetClipboardData(CF_UNICODETEXT); object = GetClipboardData(CF_UNICODETEXT);
if (!stringHandle) if (!object)
{ {
CloseClipboard(); CloseClipboard();
@ -1657,11 +1616,20 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
return NULL; return NULL;
} }
buffer = GlobalLock(object);
if (!buffer)
{
CloseClipboard();
_glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to lock global handle");
return NULL;
}
free(_glfw.win32.clipboardString); free(_glfw.win32.clipboardString);
_glfw.win32.clipboardString = _glfw.win32.clipboardString =
_glfwCreateUTF8FromWideStringWin32(GlobalLock(stringHandle)); _glfwCreateUTF8FromWideStringWin32(buffer);
GlobalUnlock(stringHandle); GlobalUnlock(object);
CloseClipboard(); CloseClipboard();
if (!_glfw.win32.clipboardString) if (!_glfw.win32.clipboardString)

View File

@ -151,7 +151,8 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
if (ctxconfig.share) if (ctxconfig.share)
{ {
if (ctxconfig.share->context.client == GLFW_NO_API) if (ctxconfig.client == GLFW_NO_API ||
ctxconfig.share->context.client == GLFW_NO_API)
{ {
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL); _glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return NULL; return NULL;
@ -627,6 +628,8 @@ GLFWAPI void glfwRestoreWindow(GLFWwindow* handle)
GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle) GLFWAPI void glfwMaximizeWindow(GLFWwindow* handle)
{ {
_GLFWwindow* window = (_GLFWwindow*) handle; _GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT(); _GLFW_REQUIRE_INIT();
_glfwPlatformMaximizeWindow(window); _glfwPlatformMaximizeWindow(window);
} }

View File

@ -600,9 +600,6 @@ int _glfwPlatformInit(void)
if (!_glfwInitThreadLocalStoragePOSIX()) if (!_glfwInitThreadLocalStoragePOSIX())
return GLFW_FALSE; return GLFW_FALSE;
if (!_glfwInitEGL())
return GLFW_FALSE;
if (!_glfwInitJoysticksLinux()) if (!_glfwInitJoysticksLinux())
return GLFW_FALSE; return GLFW_FALSE;

View File

@ -120,7 +120,7 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
struct wl_output *output; struct wl_output *output;
char name_str[80]; char name_str[80];
memset(name_str, 0, 80 * sizeof(char)); memset(name_str, 0, sizeof(name_str));
snprintf(name_str, 79, "wl_output@%u", name); snprintf(name_str, 79, "wl_output@%u", name);
if (version < 2) if (version < 2)

View File

@ -393,6 +393,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
if (ctxconfig->client != GLFW_NO_API) if (ctxconfig->client != GLFW_NO_API)
{ {
if (!_glfwInitEGL())
return GLFW_FALSE;
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig)) if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
return GLFW_FALSE; return GLFW_FALSE;
} }
@ -435,7 +437,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
_glfwInputWindowFocus(window, GLFW_FALSE); _glfwInputWindowFocus(window, GLFW_FALSE);
} }
if (window->context.client != GLFW_NO_API) if (window->context.destroy)
window->context.destroy(window); window->context.destroy(window);
if (window->wl.native) if (window->wl.native)

View File

@ -72,9 +72,8 @@ static int translateKeyCode(int scancode)
default: break; default: break;
} }
// Now try primary keysym for function keys (non-printable keys). These // Now try primary keysym for function keys (non-printable keys)
// should not be layout dependent (i.e. US layout and international // These should not depend on the current keyboard layout
// layouts should give the same result).
keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0); keySym = XkbKeycodeToKeysym(_glfw.x11.display, scancode, 0, 0);
} }
else else
@ -766,13 +765,9 @@ int _glfwPlatformInit(void)
if (!_glfwInitThreadLocalStoragePOSIX()) if (!_glfwInitThreadLocalStoragePOSIX())
return GLFW_FALSE; return GLFW_FALSE;
if (!_glfwInitGLX())
return GLFW_FALSE;
if (!_glfwInitJoysticksLinux()) if (!_glfwInitJoysticksLinux())
return GLFW_FALSE; return GLFW_FALSE;
_glfwInitEGL();
_glfwInitTimerPOSIX(); _glfwInitTimerPOSIX();
return GLFW_TRUE; return GLFW_TRUE;

View File

@ -123,10 +123,8 @@ typedef struct _GLFWwindowX11
int warpCursorPosX, warpCursorPosY; int warpCursorPosX, warpCursorPosY;
// The information from the last KeyPress event // The information from the last KeyPress event
struct { unsigned int lastKeyCode;
unsigned int keycode; Time lastKeyTime;
Time time;
} last;
} _GLFWwindowX11; } _GLFWwindowX11;

View File

@ -49,15 +49,15 @@
#define Button7 7 #define Button7 7
// Wait for data to arrive // Wait for data to arrive using select
// This avoids blocking other threads via the per-display Xlib lock that also
// covers GLX functions
// //
void selectDisplayConnection(struct timeval* timeout) static GLFWbool waitForEvent(double* timeout)
{ {
fd_set fds; fd_set fds;
int result, count;
const int fd = ConnectionNumber(_glfw.x11.display); const int fd = ConnectionNumber(_glfw.x11.display);
int count = fd + 1;
count = fd + 1;
FD_ZERO(&fds); FD_ZERO(&fds);
FD_SET(fd, &fds); FD_SET(fd, &fds);
@ -67,18 +67,49 @@ void selectDisplayConnection(struct timeval* timeout)
if (fd < _glfw.linux_js.inotify) if (fd < _glfw.linux_js.inotify)
count = _glfw.linux_js.inotify + 1; count = _glfw.linux_js.inotify + 1;
#endif #endif
for (;;)
// NOTE: We use select instead of an X function like XNextEvent, as the
// wait inside those are guarded by the mutex protecting the display
// struct, locking out other threads from using X (including GLX)
// NOTE: Only retry on EINTR if there is no timeout, as select is not
// required to update it for the time elapsed
// TODO: Update timeout value manually
do
{ {
result = select(count, &fds, NULL, NULL, timeout); if (timeout)
{
const long seconds = (long) *timeout;
const long microseconds = (long) ((*timeout - seconds) * 1e6);
struct timeval tv = { seconds, microseconds };
const uint64_t base = _glfwPlatformGetTimerValue();
const int result = select(count, &fds, NULL, NULL, &tv);
const int error = errno;
*timeout -= (_glfwPlatformGetTimerValue() - base) /
(double) _glfwPlatformGetTimerFrequency();
if (result > 0)
return GLFW_TRUE;
if ((result == -1 && error == EINTR) || *timeout <= 0.0)
return GLFW_FALSE;
}
else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR)
return GLFW_TRUE;
} }
while (result == -1 && errno == EINTR && timeout == NULL); }
// Waits until a VisibilityNotify event arrives for the specified window or the
// timeout period elapses (ICCCM section 4.2.2)
//
static GLFWbool waitForVisibilityNotify(_GLFWwindow* window)
{
XEvent dummy;
double timeout = 0.1;
while (!XCheckTypedWindowEvent(_glfw.x11.display,
window->x11.handle,
VisibilityNotify,
&dummy))
{
if (!waitForEvent(&timeout))
return GLFW_FALSE;
}
return GLFW_TRUE;
} }
// Returns whether the window is iconified // Returns whether the window is iconified
@ -105,6 +136,15 @@ static int getWindowState(_GLFWwindow* window)
// Returns whether the event is a selection event // Returns whether the event is a selection event
// //
static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer)
{
return event->type == SelectionRequest ||
event->type == SelectionNotify ||
event->type == SelectionClear;
}
// Returns whether it is a _NET_FRAME_EXTENTS event for the specified window
//
static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer) static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer)
{ {
_GLFWwindow* window = (_GLFWwindow*) pointer; _GLFWwindow* window = (_GLFWwindow*) pointer;
@ -218,14 +258,18 @@ static void updateNormalHints(_GLFWwindow* window, int width, int height)
if (window->resizable) if (window->resizable)
{ {
if (window->minwidth != GLFW_DONT_CARE && if (window->minwidth != GLFW_DONT_CARE &&
window->minheight != GLFW_DONT_CARE && window->minheight != GLFW_DONT_CARE)
window->maxwidth != GLFW_DONT_CARE && {
hints->flags |= PMinSize;
hints->min_width = window->minwidth;
hints->min_height = window->minheight;
}
if (window->maxwidth != GLFW_DONT_CARE &&
window->maxheight != GLFW_DONT_CARE) window->maxheight != GLFW_DONT_CARE)
{ {
hints->flags |= (PMinSize | PMaxSize); hints->flags |= PMaxSize;
hints->min_width = window->minwidth; hints->max_width = window->maxwidth;
hints->min_height = window->minheight;
hints->max_width = window->maxwidth;
hints->max_height = window->maxheight; hints->max_height = window->maxheight;
} }
@ -245,6 +289,9 @@ static void updateNormalHints(_GLFWwindow* window, int width, int height)
} }
} }
hints->flags |= PWinGravity;
hints->win_gravity = StaticGravity;
XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints); XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
XFree(hints); XFree(hints);
} }
@ -416,9 +463,9 @@ static void updateCursorImage(_GLFWwindow* window)
// Create the X11 window (and its colormap) // Create the X11 window (and its colormap)
// //
static GLFWbool createWindow(_GLFWwindow* window, static GLFWbool createNativeWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig, const _GLFWwndconfig* wndconfig,
Visual* visual, int depth) Visual* visual, int depth)
{ {
// Create a colormap based on the visual used by the current context // Create a colormap based on the visual used by the current context
window->x11.colormap = XCreateColormap(_glfw.x11.display, window->x11.colormap = XCreateColormap(_glfw.x11.display,
@ -608,15 +655,6 @@ static GLFWbool createWindow(_GLFWwindow* window,
return GLFW_TRUE; return GLFW_TRUE;
} }
// Returns whether the event is a selection event
//
static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer)
{
return event->type == SelectionRequest ||
event->type == SelectionNotify ||
event->type == SelectionClear;
}
// Set the specified property to the selection converted to the requested target // Set the specified property to the selection converted to the requested target
// //
static Atom writeTargetToProperty(const XSelectionRequestEvent* request) static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
@ -815,7 +853,7 @@ static void pushSelectionToManager(_GLFWwindow* window)
} }
} }
selectDisplayConnection(NULL); waitForEvent(NULL);
} }
} }
@ -957,15 +995,15 @@ static void processEvent(XEvent *event)
// HACK: Ignore duplicate key press events generated by ibus // HACK: Ignore duplicate key press events generated by ibus
// Corresponding release events are filtered out by the // Corresponding release events are filtered out by the
// GLFW key repeat logic // GLFW key repeat logic
if (window->x11.last.keycode != keycode || if (window->x11.lastKeyCode != keycode ||
window->x11.last.time != event->xkey.time) window->x11.lastKeyTime != event->xkey.time)
{ {
if (keycode) if (keycode)
_glfwInputKey(window, key, keycode, GLFW_PRESS, mods); _glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
} }
window->x11.last.keycode = keycode; window->x11.lastKeyCode = keycode;
window->x11.last.time = event->xkey.time; window->x11.lastKeyTime = event->xkey.time;
if (!filtered) if (!filtered)
{ {
@ -1514,17 +1552,21 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
{ {
if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API) if (ctxconfig->source == GLFW_NATIVE_CONTEXT_API)
{ {
if (!_glfwInitGLX())
return GLFW_FALSE;
if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth)) if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth))
return GLFW_FALSE; return GLFW_FALSE;
} }
else else
{ {
if (!_glfwInitEGL())
return GLFW_FALSE;
if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth)) if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth))
return GLFW_FALSE; return GLFW_FALSE;
} }
} }
if (!createWindow(window, wndconfig, visual, depth)) if (!createNativeWindow(window, wndconfig, visual, depth))
return GLFW_FALSE; return GLFW_FALSE;
if (ctxconfig->client != GLFW_NO_API) if (ctxconfig->client != GLFW_NO_API)
@ -1569,7 +1611,7 @@ void _glfwPlatformDestroyWindow(_GLFWwindow* window)
window->x11.ic = NULL; window->x11.ic = NULL;
} }
if (window->context.client != GLFW_NO_API) if (window->context.destroy)
window->context.destroy(window); window->context.destroy(window);
if (window->x11.handle) if (window->x11.handle)
@ -1673,21 +1715,11 @@ void _glfwPlatformSetWindowIcon(_GLFWwindow* window,
void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
{ {
Window child; Window dummy;
int x, y; int x, y;
XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root, XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root,
0, 0, &x, &y, &child); 0, 0, &x, &y, &dummy);
if (child)
{
int left, top;
XTranslateCoordinates(_glfw.x11.display, window->x11.handle, child,
0, 0, &left, &top, &child);
x -= left;
y -= top;
}
if (xpos) if (xpos)
*xpos = x; *xpos = x;
@ -1786,19 +1818,16 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
if (!_glfwPlatformWindowVisible(window) && if (!_glfwPlatformWindowVisible(window) &&
_glfw.x11.NET_REQUEST_FRAME_EXTENTS) _glfw.x11.NET_REQUEST_FRAME_EXTENTS)
{ {
uint64_t base;
XEvent event; XEvent event;
double timeout = 0.5;
// Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to
// function before the window is mapped // function before the window is mapped
sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS, sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS,
0, 0, 0, 0, 0); 0, 0, 0, 0, 0);
base = _glfwPlatformGetTimerValue(); // HACK: Use a timeout because earlier versions of some window managers
// (at least Unity, Fluxbox and Xfwm) failed to send the reply
// HACK: Poll with timeout for the required reply instead of blocking
// This is done because some window managers (at least Unity,
// Fluxbox and Xfwm) failed to send the required reply
// They have been fixed but broken versions are still in the wild // They have been fixed but broken versions are still in the wild
// If you are affected by this and your window manager is NOT // If you are affected by this and your window manager is NOT
// listed above, PLEASE report it to their and our issue trackers // listed above, PLEASE report it to their and our issue trackers
@ -1807,21 +1836,12 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window,
isFrameExtentsEvent, isFrameExtentsEvent,
(XPointer) window)) (XPointer) window))
{ {
double remaining; if (!waitForEvent(&timeout))
struct timeval timeout;
remaining = 0.5 - (_glfwPlatformGetTimerValue() - base) /
(double) _glfwPlatformGetTimerFrequency();
if (remaining <= 0.0)
{ {
_glfwInputError(GLFW_PLATFORM_ERROR, _glfwInputError(GLFW_PLATFORM_ERROR,
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
return; return;
} }
timeout.tv_sec = 0;
timeout.tv_usec = (long) (remaining * 1e6);
selectDisplayConnection(&timeout);
} }
} }
@ -1871,8 +1891,11 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
} }
if (_glfwPlatformWindowIconified(window)) if (_glfwPlatformWindowIconified(window))
{
XMapWindow(_glfw.x11.display, window->x11.handle); XMapWindow(_glfw.x11.display, window->x11.handle);
else waitForVisibilityNotify(window);
}
else if (_glfwPlatformWindowVisible(window))
{ {
if (_glfw.x11.NET_WM_STATE && if (_glfw.x11.NET_WM_STATE &&
_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT && _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT &&
@ -1908,8 +1931,11 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window)
void _glfwPlatformShowWindow(_GLFWwindow* window) void _glfwPlatformShowWindow(_GLFWwindow* window)
{ {
if (_glfwPlatformWindowVisible(window))
return;
XMapWindow(_glfw.x11.display, window->x11.handle); XMapWindow(_glfw.x11.display, window->x11.handle);
XFlush(_glfw.x11.display); waitForVisibilityNotify(window);
} }
void _glfwPlatformHideWindow(_GLFWwindow* window) void _glfwPlatformHideWindow(_GLFWwindow* window)
@ -1964,7 +1990,8 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window,
if (window->monitor) if (window->monitor)
{ {
XMapRaised(_glfw.x11.display, window->x11.handle); XMapRaised(_glfw.x11.display, window->x11.handle);
acquireMonitor(window); if (waitForVisibilityNotify(window))
acquireMonitor(window);
} }
else else
{ {
@ -2042,28 +2069,17 @@ void _glfwPlatformPollEvents(void)
void _glfwPlatformWaitEvents(void) void _glfwPlatformWaitEvents(void)
{ {
while (!XPending(_glfw.x11.display)) while (!XPending(_glfw.x11.display))
selectDisplayConnection(NULL); waitForEvent(NULL);
_glfwPlatformPollEvents(); _glfwPlatformPollEvents();
} }
void _glfwPlatformWaitEventsTimeout(double timeout) void _glfwPlatformWaitEventsTimeout(double timeout)
{ {
const double deadline = timeout + _glfwPlatformGetTimerValue() /
(double) _glfwPlatformGetTimerFrequency();
while (!XPending(_glfw.x11.display)) while (!XPending(_glfw.x11.display))
{ {
const double remaining = deadline - _glfwPlatformGetTimerValue() / if (!waitForEvent(&timeout))
(double) _glfwPlatformGetTimerFrequency(); break;
if (remaining <= 0.0)
return;
const long seconds = (long) remaining;
const long microseconds = (long) ((remaining - seconds) * 1e6);
struct timeval tv = { seconds, microseconds };
selectDisplayConnection(&tv);
} }
_glfwPlatformPollEvents(); _glfwPlatformPollEvents();
@ -2254,10 +2270,8 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window)
_glfw.x11.GLFW_SELECTION, _glfw.x11.GLFW_SELECTION,
window->x11.handle, CurrentTime); window->x11.handle, CurrentTime);
// XCheckTypedEvent is used instead of XIfEvent in order not to lock
// other threads out from the display during the entire wait period
while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event)) while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event))
selectDisplayConnection(NULL); waitForEvent(NULL);
if (event.xselection.property == None) if (event.xselection.property == None)
continue; continue;