diff --git a/CMakeLists.txt b/CMakeLists.txt index dcc7c59d6..22a3ef36b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ if (APPLE) option(GLFW_BUILD_UNIVERSAL "Build GLFW as a Universal Binary" OFF) option(GLFW_USE_CHDIR "Make glfwInit chdir to Contents/Resources" ON) option(GLFW_USE_MENUBAR "Populate the menu bar on first window creation" ON) + option(GLFW_USE_RETINA "Use the full resolution of Retina displays" ON) else() option(GLFW_USE_EGL "Use EGL for context creation" OFF) endif() @@ -153,6 +154,9 @@ endif() # Use Win32 for window creation #-------------------------------------------------------------------- if (_GLFW_WIN32) + + set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} -lgdi32 -lwinmm") + # The DLL links against winmm; the static library loads it # That way, both code paths receive testing if (BUILD_SHARED_LIBS) @@ -171,16 +175,21 @@ if (_GLFW_WIN32) # the inclusion of stddef.h (by glfw3.h), which is itself included before # win32_platform.h. We define them here until a saner solution can be found # NOTE: MinGW-w64 and Visual C++ do /not/ need this hack. - add_definitions(-DUNICODE) - add_definitions(-DWINVER=0x0501) + if (CMAKE_COMPILER_IS_GNUC) + add_definitions(-DUNICODE -DWINVER=0x0501) + endif() endif() #-------------------------------------------------------------------- # Use WGL for context creation #-------------------------------------------------------------------- if (_GLFW_WGL) + + set(GLFW_PKG_LIBS "${GLFW_PKG_LIBS} -lopengl32") + list(APPEND glfw_INCLUDE_DIRS ${OPENGL_INCLUDE_DIR}) list(APPEND glfw_LIBRARIES ${OPENGL_gl_LIBRARY}) + endif() #-------------------------------------------------------------------- @@ -307,9 +316,7 @@ if (_GLFW_EGL) list(APPEND glfw_INCLUDE_DIRS ${EGL_INCLUDE_DIR}) list(APPEND glfw_LIBRARIES ${EGL_LIBRARY}) - if (UNIX) - set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} egl") - endif() + set(GLFW_PKG_DEPS "${GLFW_PKG_DEPS} egl") if (_GLFW_USE_OPENGL) list(APPEND glfw_LIBRARIES ${OPENGL_gl_LIBRARY}) @@ -340,6 +347,10 @@ if (_GLFW_COCOA AND _GLFW_NSGL) set(_GLFW_USE_CHDIR 1) endif() + if (GLFW_USE_RETINA) + set(_GLFW_USE_RETINA 1) + endif() + if (GLFW_BUILD_UNIVERSAL) message(STATUS "Building GLFW as Universal Binaries") set(CMAKE_OSX_ARCHITECTURES i386;x86_64) @@ -392,10 +403,8 @@ configure_file(${GLFW_SOURCE_DIR}/src/glfwConfig.cmake.in configure_file(${GLFW_SOURCE_DIR}/src/glfwConfigVersion.cmake.in ${GLFW_BINARY_DIR}/src/glfwConfigVersion.cmake @ONLY) -if (UNIX) - configure_file(${GLFW_SOURCE_DIR}/src/glfw3.pc.in - ${GLFW_BINARY_DIR}/src/glfw3.pc @ONLY) -endif() +configure_file(${GLFW_SOURCE_DIR}/src/glfw3.pc.in + ${GLFW_BINARY_DIR}/src/glfw3.pc @ONLY) #-------------------------------------------------------------------- # Add subdirectories @@ -426,11 +435,9 @@ if (GLFW_INSTALL) ${GLFW_BINARY_DIR}/src/glfwConfigVersion.cmake DESTINATION lib${LIB_SUFFIX}/cmake/glfw) - if (UNIX) - install(EXPORT glfwTargets DESTINATION lib${LIB_SUFFIX}/cmake/glfw) - install(FILES ${GLFW_BINARY_DIR}/src/glfw3.pc - DESTINATION lib${LIB_SUFFIX}/pkgconfig) - endif() + install(EXPORT glfwTargets DESTINATION lib${LIB_SUFFIX}/cmake/glfw) + install(FILES ${GLFW_BINARY_DIR}/src/glfw3.pc + DESTINATION lib${LIB_SUFFIX}/pkgconfig) # Only generate this target if no higher-level project already has if (NOT TARGET uninstall) diff --git a/README.md b/README.md index bd28c1548..80bc5c8d4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Introduction -GLFW is a free, Open Source, portable library for OpenGL and OpenGL ES +GLFW is a free, Open Source, multi-platform library for OpenGL and OpenGL ES application development. It provides a simple, platform-independent API for creating windows and contexts, reading input, handling events, etc. @@ -38,7 +38,7 @@ The following dependencies are needed by GLFW: The following dependencies are needed by the examples and test programs: - - [Free Getopt](http://freegetopt.sourceforge.net/) for getopt + - [getopt\_port](https://github.com/kimgr/getopt_port/) for getopt - [TinyCThread](https://gitorious.org/tinythread/tinycthread/) for threading - An OpenGL loader generated by [glad](https://github.com/Dav1dde/glad) @@ -46,8 +46,21 @@ The following dependencies are needed by the examples and test programs: ## Changelog - Added native monitor handle access to native API + - Added `glfwSetDropCallback` and `GLFWdropfun` for receiving dropped files + - [Cocoa] Added `_GLFW_USE_RETINA` to control whether windows will use the full + resolution on Retina displays - [Cocoa] Bugfix: Using a 1x1 cursor for hidden mode caused some screen recorders to fail + - [Cocoa] Bugfix: Some Core Foundation objects were leaked during joystick + enumeration + - [Win32] Enabled generation of pkg-config file for MinGW + - [Win32] Bugfix: Failure to load winmm or its functions was not reported to + the error callback + - [X11] Bugfix: The case of finding no usable CRTCs was not detected + - [X11] Bugfix: Detection of broken Nvidia RandR gamma support did not verify + that at least one CRTC was present + - [X11] Bugfix: A stale `_NET_SUPPORTING_WM_CHECK` root window property would + cause an uncaught `BadWindow` error ## Contact diff --git a/deps/getopt.c b/deps/getopt.c index 7b3decd21..f7f667a98 100644 --- a/deps/getopt.c +++ b/deps/getopt.c @@ -1,267 +1,230 @@ -/***************************************************************************** -* getopt.c - competent and free getopt library. -* $Header: /cvsroot/freegetopt/freegetopt/getopt.c,v 1.2 2003/10/26 03:10:20 vindaci Exp $ -* -* Copyright (c)2002-2003 Mark K. Kim -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in -* the documentation and/or other materials provided with the -* distribution. -* -* * Neither the original author of this software nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -* DAMAGE. -*/ -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif +/* Copyright (c) 2012, Kim Gräsman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Kim Gräsman nor the names of contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ -#include -#include -#include #include "getopt.h" -/* 2013-01-06 Camilla Berglund - * - * Only define _CRT_SECURE_NO_WARNINGS if not already defined. - */ -/* 2012-08-12 Lambert Clara - * - * Constify third argument of getopt. - */ -/* 2011-07-27 Camilla Berglund - * - * Added _CRT_SECURE_NO_WARNINGS macro. - */ -/* 2009-10-12 Camilla Berglund - * - * Removed unused global static variable 'ID'. - */ +#include +#include -char* optarg = NULL; -int optind = 0; -int opterr = 1; -int optopt = '?'; +const int no_argument = 0; +const int required_argument = 1; +const int optional_argument = 2; +char* optarg; +int optopt; +/* The variable optind [...] shall be initialized to 1 by the system. */ +int optind = 1; +int opterr; -static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ -static int prev_argc = 0; /* tell if getopt params change */ -static int argv_index = 0; /* Option we're checking */ -static int argv_index2 = 0; /* Option argument we're checking */ -static int opt_offset = 0; /* Index into compounded "-option" */ -static int dashdash = 0; /* True if "--" option reached */ -static int nonopt = 0; /* How many nonopts we've found */ +static char* optcursor = NULL; -static void increment_index() -{ - /* Move onto the next option */ - if(argv_index < argv_index2) - { - while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' - && argv_index < argv_index2+1); - } - else argv_index++; - opt_offset = 1; -} +/* Implemented based on [1] and [2] for optional arguments. + optopt is handled FreeBSD-style, per [3]. + Other GNU and FreeBSD extensions are purely accidental. - -/* -* Permutes argv[] so that the argument currently being processed is moved -* to the end. +[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html +[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html +[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE */ -static int permute_argv_once() -{ - /* Movability check */ - if(argv_index + nonopt >= prev_argc) return 1; - /* Move the current option to the end, bring the others to front */ - else - { - char* tmp = prev_argv[argv_index]; +int getopt(int argc, char* const argv[], const char* optstring) { + int optchar = -1; + const char* optdecl = NULL; - /* Move the data */ - memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], - sizeof(char**) * (prev_argc - argv_index - 1)); - prev_argv[prev_argc - 1] = tmp; + optarg = NULL; + opterr = 0; + optopt = 0; - nonopt++; - return 0; - } + /* Unspecified, but we need it to avoid overrunning the argv bounds. */ + if (optind >= argc) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] is a null pointer, getopt() + shall return -1 without changing optind. */ + if (argv[optind] == NULL) + goto no_more_optchars; + + /* If, when getopt() is called *argv[optind] is not the character '-', + getopt() shall return -1 without changing optind. */ + if (*argv[optind] != '-') + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "-", + getopt() shall return -1 without changing optind. */ + if (strcmp(argv[optind], "-") == 0) + goto no_more_optchars; + + /* If, when getopt() is called argv[optind] points to the string "--", + getopt() shall return -1 after incrementing optind. */ + if (strcmp(argv[optind], "--") == 0) { + ++optind; + goto no_more_optchars; + } + + if (optcursor == NULL || *optcursor == '\0') + optcursor = argv[optind] + 1; + + optchar = *optcursor; + + /* FreeBSD: The variable optopt saves the last known option character + returned by getopt(). */ + optopt = optchar; + + /* The getopt() function shall return the next option character (if one is + found) from argv that matches a character in optstring, if there is + one that matches. */ + optdecl = strchr(optstring, optchar); + if (optdecl) { + /* [I]f a character is followed by a colon, the option takes an + argument. */ + if (optdecl[1] == ':') { + optarg = ++optcursor; + if (*optarg == '\0') { + /* GNU extension: Two colons mean an option takes an + optional arg; if there is text in the current argv-element + (i.e., in the same word as the option name itself, for example, + "-oarg"), then it is returned in optarg, otherwise optarg is set + to zero. */ + if (optdecl[2] != ':') { + /* If the option was the last character in the string pointed to by + an element of argv, then optarg shall contain the next element + of argv, and optind shall be incremented by 2. If the resulting + value of optind is greater than argc, this indicates a missing + option-argument, and getopt() shall return an error indication. + + Otherwise, optarg shall point to the string following the + option character in that element of argv, and optind shall be + incremented by 1. + */ + if (++optind < argc) { + optarg = argv[optind]; + } else { + /* If it detects a missing option-argument, it shall return the + colon character ( ':' ) if the first character of optstring + was a colon, or a question-mark character ( '?' ) otherwise. + */ + optarg = NULL; + optchar = (optstring[0] == ':') ? ':' : '?'; + } + } else { + optarg = NULL; + } + } + + optcursor = NULL; + } + } else { + /* If getopt() encounters an option character that is not contained in + optstring, it shall return the question-mark ( '?' ) character. */ + optchar = '?'; + } + + if (optcursor == NULL || *++optcursor == '\0') + ++optind; + + return optchar; + +no_more_optchars: + optcursor = NULL; + return -1; } +/* Implementation based on [1]. -int getopt(int argc, char** argv, const char* optstr) -{ - int c = 0; - - /* If we have new argv, reinitialize */ - if(prev_argv != argv || prev_argc != argc) - { - /* Initialize variables */ - prev_argv = argv; - prev_argc = argc; - argv_index = 1; - argv_index2 = 1; - opt_offset = 1; - dashdash = 0; - nonopt = 0; - } - - /* Jump point in case we want to ignore the current argv_index */ - getopt_top: - - /* Misc. initializations */ - optarg = NULL; - - /* Dash-dash check */ - if(argv[argv_index] && !strcmp(argv[argv_index], "--")) - { - dashdash = 1; - increment_index(); - } - - /* If we're at the end of argv, that's it. */ - if(argv[argv_index] == NULL) - { - c = -1; - } - /* Are we looking at a string? Single dash is also a string */ - else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) - { - /* If we want a string... */ - if(optstr[0] == '-') - { - c = 1; - optarg = argv[argv_index]; - increment_index(); - } - /* If we really don't want it (we're in POSIX mode), we're done */ - else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) - { - c = -1; - - /* Everything else is a non-opt argument */ - nonopt = argc - argv_index; - } - /* If we mildly don't want it, then move it back */ - else - { - if(!permute_argv_once()) goto getopt_top; - else c = -1; - } - } - /* Otherwise we're looking at an option */ - else - { - char* opt_ptr = NULL; - - /* Grab the option */ - c = argv[argv_index][opt_offset++]; - - /* Is the option in the optstr? */ - if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); - else opt_ptr = strchr(optstr, c); - /* Invalid argument */ - if(!opt_ptr) - { - if(opterr) - { - fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); - } - - optopt = c; - c = '?'; - - /* Move onto the next option */ - increment_index(); - } - /* Option takes argument */ - else if(opt_ptr[1] == ':') - { - /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ - if(argv[argv_index][opt_offset] != '\0') - { - optarg = &argv[argv_index][opt_offset]; - increment_index(); - } - /* ie, -o ARGUMENT (only if it's a required argument) */ - else if(opt_ptr[2] != ':') - { - /* One of those "you're not expected to understand this" moment */ - if(argv_index2 < argv_index) argv_index2 = argv_index; - while(argv[++argv_index2] && argv[argv_index2][0] == '-'); - optarg = argv[argv_index2]; - - /* Don't cross into the non-option argument list */ - if(argv_index2 + nonopt >= prev_argc) optarg = NULL; - - /* Move onto the next option */ - increment_index(); - } - else - { - /* Move onto the next option */ - increment_index(); - } - - /* In case we got no argument for an option with required argument */ - if(optarg == NULL && opt_ptr[2] != ':') - { - optopt = c; - c = '?'; - - if(opterr) - { - fprintf(stderr,"%s: option requires an argument -- %c\n", - argv[0], optopt); - } - } - } - /* Option does not take argument */ - else - { - /* Next argv_index */ - if(argv[argv_index][opt_offset] == '\0') - { - increment_index(); - } - } - } - - /* Calculate optind */ - if(c == -1) - { - optind = argc - nonopt; - } - else - { - optind = argv_index; - } - - return c; -} - - -/* vim:ts=3 +[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html */ +int getopt_long(int argc, char* const argv[], const char* optstring, + const struct option* longopts, int* longindex) { + const struct option* o = longopts; + const struct option* match = NULL; + int num_matches = 0; + size_t argument_name_length = 0; + const char* current_argument = NULL; + int retval = -1; + + optarg = NULL; + optopt = 0; + + if (optind >= argc) + return -1; + + if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0) + return getopt(argc, argv, optstring); + + /* It's an option; starts with -- and is longer than two chars. */ + current_argument = argv[optind] + 2; + argument_name_length = strcspn(current_argument, "="); + for (; o->name; ++o) { + if (strncmp(o->name, current_argument, argument_name_length) == 0) { + match = o; + ++num_matches; + } + } + + if (num_matches == 1) { + /* If longindex is not NULL, it points to a variable which is set to the + index of the long option relative to longopts. */ + if (longindex) + *longindex = (match - longopts); + + /* If flag is NULL, then getopt_long() shall return val. + Otherwise, getopt_long() returns 0, and flag shall point to a variable + which shall be set to val if the option is found, but left unchanged if + the option is not found. */ + if (match->flag) + *(match->flag) = match->val; + + retval = match->flag ? 0 : match->val; + + if (match->has_arg != no_argument) { + optarg = strchr(argv[optind], '='); + if (optarg != NULL) + ++optarg; + + if (match->has_arg == required_argument) { + /* Only scan the next argv for required arguments. Behavior is not + specified, but has been observed with Ubuntu and Mac OSX. */ + if (optarg == NULL && ++optind < argc) { + optarg = argv[optind]; + } + + if (optarg == NULL) + retval = ':'; + } + } else if (strchr(argv[optind], '=')) { + /* An argument was provided to a non-argument option. + I haven't seen this specified explicitly, but both GNU and BSD-based + implementations show this behavior. + */ + retval = '?'; + } + } else { + /* Unknown option or ambiguous match. */ + retval = '?'; + } + + ++optind; + return retval; +} diff --git a/deps/getopt.h b/deps/getopt.h index 6d2e4afe3..e1eb540fd 100644 --- a/deps/getopt.h +++ b/deps/getopt.h @@ -1,63 +1,57 @@ -/***************************************************************************** -* getopt.h - competent and free getopt library. -* $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $ -* -* Copyright (c)2002-2003 Mark K. Kim -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* * Redistributions in binary form must reproduce the above copyright -* notice, this list of conditions and the following disclaimer in -* the documentation and/or other materials provided with the -* distribution. -* -* * Neither the original author of this software nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS -* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -* DAMAGE. -*/ -#ifndef GETOPT_H_ -#define GETOPT_H_ +/* Copyright (c) 2012, Kim Gräsman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of Kim Gräsman nor the names of contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL KIM GRÄSMAN BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef INCLUDED_GETOPT_PORT_H +#define INCLUDED_GETOPT_PORT_H -#ifdef __cplusplus +#if defined(__cplusplus) extern "C" { #endif +extern const int no_argument; +extern const int required_argument; +extern const int optional_argument; extern char* optarg; -extern int optind; -extern int opterr; -extern int optopt; +extern int optind, opterr, optopt; -int getopt(int argc, char** argv, const char* optstr); +struct option { + const char* name; + int has_arg; + int* flag; + int val; +}; +int getopt(int argc, char* const argv[], const char* optstring); -#ifdef __cplusplus +int getopt_long(int argc, char* const argv[], + const char* optstring, const struct option* longopts, int* longindex); + +#if defined(__cplusplus) } #endif - -#endif /* GETOPT_H_ */ - - -/* vim:ts=3 -*/ +#endif // INCLUDED_GETOPT_PORT_H diff --git a/docs/compat.dox b/docs/compat.dox index e14263f6d..7d8a5d7d4 100644 --- a/docs/compat.dox +++ b/docs/compat.dox @@ -14,7 +14,7 @@ specification but merely list some of the preconditions for certain parts of the API to function on a given machine. As such, any part of it may change in future versions without this being considered a breaking API change. -@section compat_wm ICCCM and EWMH conformance +@section compat_x11 X11 extensions, protocols and IPC standards As GLFW uses Xlib, directly, without any intervening toolkit library, it has sole responsibility for interacting well with the many and @@ -27,6 +27,10 @@ X11 API; most importantly the [Extended Window Manager Hints](http://standards.freedesktop.org/wm-spec/wm-spec-latest.html) (EWMH) standards. +GLFW uses the `_MOTIF_WM_HINTS` window property to support borderless windows. +If the running window manager does not support this property, the +`GLFW_DECORATED` hint will have no effect. + GLFW uses the ICCCM `WM_DELETE_WINDOW` protocol to intercept the user attempting to close the GLFW window. If the running window manager does not support this protocol, the close callback will never be called. @@ -36,11 +40,16 @@ the user when the application has stopped responding, i.e. when it has ceased to process events. If the running window manager does not support this protocol, the user will not be notified if the application locks up. -GLFW uses the EWMH `_NET_WM_STATE` protocol to tell the window manager to make -the GLFW window full screen. If the running window manager does not support this -protocol, full screen windows may not work properly. GLFW has a fallback code -path in case this protocol is unavailable, but every window manager behaves -slightly differently in this regard. +GLFW uses the EWMH `_NET_WM_STATE_FULLSCREEN` window state to tell the window +manager to make the GLFW window full screen. If the running window manager does +not support this state, full screen windows may not work properly. GLFW has +a fallback code path in case this state is unavailable, but every window manager +behaves slightly differently in this regard. + +GLFW uses the EWMH `_NET_WM_BYPASS_COMPOSITOR` window property to tell a +compositing window manager to un-redirect full screen GLFW windows. If the +running window manager uses compositing but does not support this property then +additional copying may be performed for each buffer swap of full screen windows. GLFW uses the [clipboard manager protocol](http://www.freedesktop.org/wiki/ClipboardManager/) @@ -48,6 +57,28 @@ to push a clipboard string (i.e. selection) owned by a GLFW window about to be destroyed to the clipboard manager. If there is no running clipboard manager, the clipboard string will be unavailable once the window has been destroyed. +GLFW uses the +[X drag-and-drop protocol](http://www.freedesktop.org/wiki/Specifications/XDND/) +to provide file drop events. If the application originating the drag does not +support this protocol, drag and drop will not work. + +GLFW uses the XInput 2 extension to provide sub-pixel cursor motion events. If +the running X server does not support this version of this extension, cursor +motion will be snapped to the pixel grid. + +GLFW uses the XRandR 1.3 extension to provide multi-monitor support. If the +running X server does not support this version of this extension, multi-monitor +support will not function and only a single, desktop-spanning monitor will be +reported. + +GLFW uses the XRandR 1.3 and Xf86vidmode extensions to provide gamma ramp +support. If the running X server does not support either or both of these +extensions, gamma ramp support will not function. + +GLFW requires the Xkb extension with detectable auto-repeat to provide keyboard +input. If the running X server does not support this extension and detectable +auto-repeat, `glfwInit` will fail. + @section compat_glx GLX extensions The GLX API is the default API used to create OpenGL contexts on Unix-like diff --git a/docs/compile.dox b/docs/compile.dox index ef6c3b931..dee7bd9c3 100644 --- a/docs/compile.dox +++ b/docs/compile.dox @@ -165,6 +165,9 @@ directory of bundled applications to the `Contents/Resources` directory. `GLFW_USE_MENUBAR` determines whether the first call to `glfwCreateWindow` sets up a minimal menu bar. +`GLFW_USE_RETINA` determines whether windows will use the full resolution of +Retina displays. + `GLFW_BUILD_UNIVERSAL` determines whether to build Universal Binaries. @@ -257,5 +260,7 @@ available: application bundle during @ref glfwInit (recommended) - `_GLFW_USE_MENUBAR` to create and populate the menu bar when the first window is created (recommended) + - `_GLFW_USE_RETINA` to have windows use the full resolution of Retina displays + (recommended) */ diff --git a/docs/moving.dox b/docs/moving.dox index 8d5c2e83c..04f7e7dc4 100644 --- a/docs/moving.dox +++ b/docs/moving.dox @@ -174,6 +174,17 @@ window to use. There is @ref glfwGetPrimaryMonitor that provides behaviour similar to that of GLFW 2. +@subsection moving_hidpi Separation of window and framebuffer sizes + +Window positions and sizes now use screen coordinates, which may not be the same +as pixels on machines with high-DPI monitors. This is important as OpenGL uses +pixels, not screen coordinates. Most commonly, the rectangle specified with +`glViewport` needs to use pixels. Therefore, framebuffer size functions have +been added. You can retrieve the size of the framebuffer of a window with @ref +glfwGetFramebufferSize function. A framebuffer size callback has been added, +which can be set with @ref glfwSetFramebufferSizeCallback. + + @subsection moving_window_close Window closing Window closing initiated by the user is now just an event like any other. diff --git a/docs/news.dox b/docs/news.dox index bbce25fd1..b02861ec6 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -5,6 +5,14 @@ @tableofcontents +@section news_31 New features in version 3.1 + +@subsection news_31_drop Drop event support + +GLFW now provides a callback for receiving the paths of files dropped onto GLFW +windows. The callback is set with the @ref glfwSetDropCallback function. + + @section news_30 New features in version 3.0 @subsection news_30_cmake CMake build system @@ -80,7 +88,7 @@ GLFW now supports high-DPI monitors on both Windows and OS X, giving windows ful resolution framebuffers where other UI elements are scaled up. To achieve this, @ref glfwGetFramebufferSize and @ref glfwSetFramebufferSizeCallback have been added. These work with pixels, while the rest of the GLFW API works with screen -coordinates. +coordinates. This is important as OpenGL uses pixels, not screen coordinates. @subsection news_30_error Error callback diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index ed301997d..282443703 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1,5 +1,5 @@ /************************************************************************* - * GLFW 3.0 - www.glfw.org + * GLFW 3.1 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard @@ -773,6 +773,21 @@ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); */ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); + +/*! @brief The function signature for drop callbacks. + * + * This is the function signature for drop callbacks. + * + * @param[in] window The window that received the event. + * @param[in] count The number of dropped objects. + * @param[in] names The UTF-8 encoded names of the dropped objects. + * + * @sa glfwSetDropCallback + * + * @ingroup input + */ +typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); + /*! @brief The function signature for monitor configuration callbacks. * * This is the function signature for monitor configuration callback functions. @@ -2014,6 +2029,22 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu */ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun); +/*! @brief Sets the drop callback. + * + * This function sets the drop callback of the specified window, which is + * called when an object is dropped over the window. + * + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new drop callback, or `NULL` to remove the currently + * set callback. + * @return The previously set callback, or `NULL` if no callback was set or an + * error occurred. + * + * @ingroup input + */ +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); + /*! @brief Returns whether the specified joystick is present. * * This function returns whether the specified joystick is present. diff --git a/src/clipboard.c b/src/clipboard.c index f28c5c6ed..b5426c44f 100644 --- a/src/clipboard.c +++ b/src/clipboard.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2010 Camilla Berglund // diff --git a/src/cocoa_clipboard.m b/src/cocoa_clipboard.m index a58eb5c01..6af5df61f 100644 --- a/src/cocoa_clipboard.m +++ b/src/cocoa_clipboard.m @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2010 Camilla Berglund // diff --git a/src/cocoa_gamma.c b/src/cocoa_gamma.c index f2905f4c1..85fb50ad4 100644 --- a/src/cocoa_gamma.c +++ b/src/cocoa_gamma.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2010 Camilla Berglund // diff --git a/src/cocoa_init.m b/src/cocoa_init.m index 42b31c54e..afb1a542a 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // @@ -132,6 +132,9 @@ const char* _glfwPlatformGetVersionString(void) #if defined(_GLFW_USE_MENUBAR) " menubar" #endif +#if defined(_GLFW_USE_RETINA) + " retina" +#endif #if defined(_GLFW_BUILD_DLL) " dynamic" #endif diff --git a/src/cocoa_joystick.m b/src/cocoa_joystick.m index 7af1042b5..dc798b8be 100644 --- a/src/cocoa_joystick.m +++ b/src/cocoa_joystick.m @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // Copyright (c) 2012 Torsten Walluhn @@ -343,6 +343,7 @@ void _glfwInitJoysticks(void) { // This device is not relevant to GLFW CFRelease(valueRef); + CFRelease(propsRef); continue; } @@ -360,6 +361,7 @@ void _glfwInitJoysticks(void) { // This device is not relevant to GLFW CFRelease(valueRef); + CFRelease(propsRef); continue; } @@ -376,7 +378,11 @@ void _glfwInitJoysticks(void) &score); if (kIOReturnSuccess != result) + { + CFRelease(valueRef); + CFRelease(propsRef); return; + } plugInResult = (*ppPlugInInterface)->QueryInterface( ppPlugInInterface, @@ -384,7 +390,11 @@ void _glfwInitJoysticks(void) (void *) &(joystick->interface)); if (plugInResult != S_OK) + { + CFRelease(valueRef); + CFRelease(propsRef); return; + } (*ppPlugInInterface)->Release(ppPlugInInterface); @@ -419,6 +429,7 @@ void _glfwInitJoysticks(void) (void*) joystick); CFRelease(valueRef); } + CFRelease(propsRef); joystick->axes = calloc(CFArrayGetCount(joystick->axisElements), sizeof(float)); diff --git a/src/cocoa_monitor.m b/src/cocoa_monitor.m index 77ff59dc8..2f53a328b 100644 --- a/src/cocoa_monitor.m +++ b/src/cocoa_monitor.m @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -52,6 +52,7 @@ static const char* getDisplayName(CGDirectDisplayID displayID) if (!names || !CFDictionaryGetValueIfPresent(names, CFSTR("en_US"), (const void**) &value)) { + // This may happen if a desktop Mac is running headless _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to retrieve display name"); CFRelease(info); @@ -252,48 +253,30 @@ void _glfwRestoreVideoMode(_GLFWmonitor* monitor) _GLFWmonitor** _glfwPlatformGetMonitors(int* count) { - uint32_t i, found = 0, monitorCount; + uint32_t i, found = 0, displayCount; _GLFWmonitor** monitors; CGDirectDisplayID* displays; *count = 0; - CGGetActiveDisplayList(0, NULL, &monitorCount); + CGGetActiveDisplayList(0, NULL, &displayCount); - displays = calloc(monitorCount, sizeof(CGDirectDisplayID)); - monitors = calloc(monitorCount, sizeof(_GLFWmonitor*)); + displays = calloc(displayCount, sizeof(CGDirectDisplayID)); + monitors = calloc(displayCount, sizeof(_GLFWmonitor*)); - CGGetActiveDisplayList(monitorCount, displays, &monitorCount); - - for (i = 0; i < monitorCount; i++) - { - const CGSize size = CGDisplayScreenSize(displays[i]); - - monitors[found] = _glfwCreateMonitor(getDisplayName(displays[i]), - size.width, size.height); - - monitors[found]->ns.displayID = displays[i]; - found++; - } - - free(displays); - - for (i = 0; i < monitorCount; i++) - { - if (CGDisplayIsMain(monitors[i]->ns.displayID)) - { - _GLFWmonitor* temp = monitors[0]; - monitors[0] = monitors[i]; - monitors[i] = temp; - break; - } - } + CGGetActiveDisplayList(displayCount, displays, &displayCount); NSArray* screens = [NSScreen screens]; - for (i = 0; i < monitorCount; i++) + for (i = 0; i < displayCount; i++) { int j; + const CGSize size = CGDisplayScreenSize(displays[i]); + + monitors[found] = _glfwAllocMonitor(getDisplayName(displays[i]), + size.width, size.height); + + monitors[found]->ns.displayID = displays[i]; for (j = 0; j < [screens count]; j++) { @@ -301,26 +284,29 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) NSDictionary* dictionary = [screen deviceDescription]; NSNumber* number = [dictionary objectForKey:@"NSScreenNumber"]; - if (monitors[i]->ns.displayID == [number unsignedIntegerValue]) + if (monitors[found]->ns.displayID == [number unsignedIntegerValue]) { - monitors[i]->ns.screen = screen; + monitors[found]->ns.screen = screen; break; } } - if (monitors[i]->ns.screen == nil) + if (monitors[found]->ns.screen) + found++; + else { - _glfwDestroyMonitors(monitors, monitorCount); _glfwInputError(GLFW_PLATFORM_ERROR, "Cocoa: Failed to find NSScreen for CGDisplay %s", - monitors[i]->name); + monitors[found]->name); - free(monitors); - return NULL; + _glfwFreeMonitor(monitors[found]); + monitors[found] = NULL; } } - *count = monitorCount; + free(displays); + + *count = found; return monitors; } diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 0e92c4a25..ea512e49c 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // @@ -138,12 +138,4 @@ void _glfwTerminateJoysticks(void); GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoMode(_GLFWmonitor* monitor); -// OpenGL support -int _glfwInitContextAPI(void); -void _glfwTerminateContextAPI(void); -int _glfwCreateContext(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWfbconfig* fbconfig); -void _glfwDestroyContext(_GLFWwindow* window); - #endif // _cocoa_platform_h_ diff --git a/src/cocoa_time.c b/src/cocoa_time.c index cb294cb65..0ecb4c132 100644 --- a/src/cocoa_time.c +++ b/src/cocoa_time.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 4b873fe96..b0f59e905 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // @@ -445,6 +445,8 @@ static int translateKey(unsigned int key) trackingArea = nil; [self updateTrackingAreas]; + [self registerForDraggedTypes:[NSArray arrayWithObjects: + NSFilenamesPboardType, nil]]; } return self; @@ -657,6 +659,67 @@ static int translateKey(unsigned int key) _glfwInputScroll(window, deltaX, deltaY); } +- (void)resetCursorRects +{ + // This makes the cursor dissapear when the window is + // resized or received a drag operation + [self discardCursorRects]; + [self addCursorRect:[self bounds] cursor:_glfw.ns.cursor]; +} + +- (NSDragOperation)draggingEntered:(id )sender +{ + if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) + == NSDragOperationGeneric) + { + [self setNeedsDisplay:YES]; + return NSDragOperationGeneric; + } + + return NSDragOperationNone; +} + +- (BOOL)prepareForDragOperation:(id )sender +{ + [self setNeedsDisplay:YES]; + return YES; +} + +- (BOOL)performDragOperation:(id )sender +{ + NSPasteboard* pasteboard = [sender draggingPasteboard]; + NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType]; + + int height; + _glfwPlatformGetWindowSize(window, NULL, &height); + _glfwInputCursorMotion(window, + [sender draggingLocation].x, + height - [sender draggingLocation].y); + + const int count = [files count]; + if (count) + { + NSEnumerator* e = [files objectEnumerator]; + char** names = calloc(count, sizeof(char*)); + + for (int i = 0; i < count; i++) + names[i] = strdup([[e nextObject] UTF8String]); + + _glfwInputDrop(window, count, (const char**) names); + + for (int i = 0; i < count; i++) + free(names[i]); + free(names); + } + + return YES; +} + +- (void)concludeDragOperation:(id )sender +{ + [self setNeedsDisplay:YES]; +} + @end @@ -877,7 +940,9 @@ static GLboolean createWindow(_GLFWwindow* window, #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_6) { +#if defined(_GLFW_USE_RETINA) [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; +#endif if (wndconfig->resizable) [window->ns.object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; diff --git a/src/context.c b/src/context.c index 3bc86bc50..93b77d653 100644 --- a/src/context.c +++ b/src/context.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund diff --git a/src/egl_context.c b/src/egl_context.c index bab955ff3..f874f8ae8 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 EGL - www.glfw.org +// GLFW 3.1 EGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund diff --git a/src/egl_platform.h b/src/egl_platform.h index 1109eb9be..38581aea8 100644 --- a/src/egl_platform.h +++ b/src/egl_platform.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 EGL - www.glfw.org +// GLFW 3.1 EGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -77,4 +77,18 @@ typedef struct _GLFWlibraryEGL } _GLFWlibraryEGL; +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +int _glfwInitContextAPI(void); +void _glfwTerminateContextAPI(void); +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContext(_GLFWwindow* window); +int _glfwAnalyzeContext(const _GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig); + #endif // _egl_platform_h_ diff --git a/src/gamma.c b/src/gamma.c index 8d7830401..a7ddfcd9f 100644 --- a/src/gamma.c +++ b/src/gamma.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2010 Camilla Berglund // diff --git a/src/glfw3.pc.in b/src/glfw3.pc.in index d56a4944c..f2e4d9769 100644 --- a/src/glfw3.pc.in +++ b/src/glfw3.pc.in @@ -4,7 +4,7 @@ includedir=${prefix}/include libdir=${exec_prefix}/lib@LIB_SUFFIX@ Name: GLFW -Description: A portable library for OpenGL, window and input +Description: A multi-platform library for OpenGL, window and input Version: @GLFW_VERSION_FULL@ URL: http://www.glfw.org/ Requires.private: @GLFW_PKG_DEPS@ diff --git a/src/glfw_config.h.in b/src/glfw_config.h.in index a7318602e..7234eb954 100644 --- a/src/glfw_config.h.in +++ b/src/glfw_config.h.in @@ -73,6 +73,8 @@ #cmakedefine _GLFW_USE_CHDIR // Define this to 1 if glfwCreateWindow should populate the menu bar #cmakedefine _GLFW_USE_MENUBAR +// Define this to 1 if windows should use full resolution on Retina displays +#cmakedefine _GLFW_USE_RETINA // Define this to 1 if using OpenGL as the client library #cmakedefine _GLFW_USE_OPENGL diff --git a/src/glx_context.c b/src/glx_context.c index 6b87000da..5c4cf1d79 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 GLX - www.glfw.org +// GLFW 3.1 GLX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund diff --git a/src/glx_platform.h b/src/glx_platform.h index 4b133a2d4..f07029798 100644 --- a/src/glx_platform.h +++ b/src/glx_platform.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 GLX - www.glfw.org +// GLFW 3.1 GLX - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -122,4 +122,15 @@ typedef struct _GLFWlibraryGLX } _GLFWlibraryGLX; +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +int _glfwInitContextAPI(void); +void _glfwTerminateContextAPI(void); +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContext(_GLFWwindow* window); + #endif // _glx_platform_h_ diff --git a/src/init.c b/src/init.c index d34abea7a..4541462db 100644 --- a/src/init.c +++ b/src/init.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -163,7 +163,7 @@ GLFWAPI void glfwTerminate(void) _glfwPlatformSetGammaRamp(monitor, &monitor->originalRamp); } - _glfwDestroyMonitors(_glfw.monitors, _glfw.monitorCount); + _glfwFreeMonitors(_glfw.monitors, _glfw.monitorCount); _glfw.monitors = NULL; _glfw.monitorCount = 0; diff --git a/src/input.c b/src/input.c index 9e628f062..493f2446e 100644 --- a/src/input.c +++ b/src/input.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -211,6 +211,12 @@ void _glfwInputCursorEnter(_GLFWwindow* window, int entered) window->callbacks.cursorEnter((GLFWwindow*) window, entered); } +void _glfwInputDrop(_GLFWwindow* window, int count, const char** names) +{ + if (window->callbacks.drop) + window->callbacks.drop((GLFWwindow*) window, count, names); +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW public API ////// @@ -394,3 +400,11 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, return cbfun; } +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun); + return cbfun; +} + diff --git a/src/internal.h b/src/internal.h index 748d27b11..1e06460ee 100644 --- a/src/internal.h +++ b/src/internal.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -239,6 +239,7 @@ struct _GLFWwindow GLFWscrollfun scroll; GLFWkeyfun key; GLFWcharfun character; + GLFWdropfun drop; } callbacks; // This is defined in the window API's platform.h @@ -678,6 +679,14 @@ void _glfwInputMonitorChange(void); */ void _glfwInputError(int error, const char* format, ...); +/*! @brief Notifies dropped object over window. + * @param[in] window The window that received the event. + * @param[in] count The number of dropped objects. + * @param[in] names The names of the dropped objects. + * @ingroup event + */ +void _glfwInputDrop(_GLFWwindow* window, int count, const char** names); + //======================================================================== // Utility functions @@ -761,15 +770,15 @@ void _glfwFreeGammaArrays(GLFWgammaramp* ramp); * @return The newly created object. * @ingroup utility */ -_GLFWmonitor* _glfwCreateMonitor(const char* name, int widthMM, int heightMM); +_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM); /*! @brief Frees a monitor object and any data associated with it. * @ingroup utility */ -void _glfwDestroyMonitor(_GLFWmonitor* monitor); +void _glfwFreeMonitor(_GLFWmonitor* monitor); /*! @ingroup utility */ -void _glfwDestroyMonitors(_GLFWmonitor** monitors, int count); +void _glfwFreeMonitors(_GLFWmonitor** monitors, int count); #endif // _internal_h_ diff --git a/src/joystick.c b/src/joystick.c index b53ea11d4..52aee9b62 100644 --- a/src/joystick.c +++ b/src/joystick.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund diff --git a/src/monitor.c b/src/monitor.c index f80d5e9d5..02f7c6af2 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -113,7 +113,7 @@ void _glfwInputMonitorChange(void) { if (_glfwPlatformIsSameMonitor(_glfw.monitors[i], monitors[j])) { - _glfwDestroyMonitor(_glfw.monitors[i]); + _glfwFreeMonitor(_glfw.monitors[i]); _glfw.monitors[i] = monitors[j]; break; } @@ -167,7 +167,7 @@ void _glfwInputMonitorChange(void) _glfw.callbacks.monitor((GLFWmonitor*) _glfw.monitors[i], GLFW_CONNECTED); } - _glfwDestroyMonitors(monitors, monitorCount); + _glfwFreeMonitors(monitors, monitorCount); } @@ -175,7 +175,7 @@ void _glfwInputMonitorChange(void) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -_GLFWmonitor* _glfwCreateMonitor(const char* name, int widthMM, int heightMM) +_GLFWmonitor* _glfwAllocMonitor(const char* name, int widthMM, int heightMM) { _GLFWmonitor* monitor = calloc(1, sizeof(_GLFWmonitor)); monitor->name = strdup(name); @@ -185,7 +185,7 @@ _GLFWmonitor* _glfwCreateMonitor(const char* name, int widthMM, int heightMM) return monitor; } -void _glfwDestroyMonitor(_GLFWmonitor* monitor) +void _glfwFreeMonitor(_GLFWmonitor* monitor) { if (monitor == NULL) return; @@ -198,12 +198,12 @@ void _glfwDestroyMonitor(_GLFWmonitor* monitor) free(monitor); } -void _glfwDestroyMonitors(_GLFWmonitor** monitors, int count) +void _glfwFreeMonitors(_GLFWmonitor** monitors, int count) { int i; for (i = 0; i < count; i++) - _glfwDestroyMonitor(monitors[i]); + _glfwFreeMonitor(monitors[i]); free(monitors); } diff --git a/src/nsgl_context.m b/src/nsgl_context.m index 71638ad19..d3213dab2 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // diff --git a/src/nsgl_platform.h b/src/nsgl_platform.h index 31da2f675..ad2ee782b 100644 --- a/src/nsgl_platform.h +++ b/src/nsgl_platform.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 OS X - www.glfw.org +// GLFW 3.1 OS X - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2009-2010 Camilla Berglund // @@ -61,4 +61,15 @@ typedef struct _GLFWlibraryNSGL } _GLFWlibraryNSGL; +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +int _glfwInitContextAPI(void); +void _glfwTerminateContextAPI(void); +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContext(_GLFWwindow* window); + #endif // _nsgl_platform_h_ diff --git a/src/time.c b/src/time.c index 6af4813da..1a8712584 100644 --- a/src/time.c +++ b/src/time.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund diff --git a/src/wgl_context.c b/src/wgl_context.c index 0b3610bd9..49e4f6274 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 WGL - www.glfw.org +// GLFW 3.1 WGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund diff --git a/src/wgl_platform.h b/src/wgl_platform.h index bffdf742b..5e793410e 100644 --- a/src/wgl_platform.h +++ b/src/wgl_platform.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 WGL - www.glfw.org +// GLFW 3.1 WGL - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -85,4 +85,18 @@ typedef struct _GLFWlibraryWGL } _GLFWlibraryWGL; +//======================================================================== +// Prototypes for platform specific internal functions +//======================================================================== + +int _glfwInitContextAPI(void); +void _glfwTerminateContextAPI(void); +int _glfwCreateContext(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig); +void _glfwDestroyContext(_GLFWwindow* window); +int _glfwAnalyzeContext(const _GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig); + #endif // _wgl_platform_h_ diff --git a/src/win32_clipboard.c b/src/win32_clipboard.c index 8fcba4679..1b7f97238 100644 --- a/src/win32_clipboard.c +++ b/src/win32_clipboard.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2010 Camilla Berglund // diff --git a/src/win32_gamma.c b/src/win32_gamma.c index b062bcf46..71abacc29 100644 --- a/src/win32_gamma.c +++ b/src/win32_gamma.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2010 Camilla Berglund // diff --git a/src/win32_init.c b/src/win32_init.c index aae46a9b8..cc33bc38c 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -65,7 +65,11 @@ static GLboolean initLibraries(void) _glfw.win32.winmm.instance = LoadLibrary(L"winmm.dll"); if (!_glfw.win32.winmm.instance) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to load winmm.dll"); return GL_FALSE; + } _glfw.win32.winmm.joyGetDevCaps = (JOYGETDEVCAPS_T) GetProcAddress(_glfw.win32.winmm.instance, "joyGetDevCapsW"); @@ -81,6 +85,8 @@ static GLboolean initLibraries(void) !_glfw.win32.winmm.joyGetPosEx || !_glfw.win32.winmm.timeGetTime) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Win32: Failed to load winmm functions"); return GL_FALSE; } #endif // _GLFW_NO_DLOAD_WINMM @@ -90,6 +96,8 @@ static GLboolean initLibraries(void) { _glfw.win32.user32.SetProcessDPIAware = (SETPROCESSDPIAWARE_T) GetProcAddress(_glfw.win32.user32.instance, "SetProcessDPIAware"); + _glfw.win32.user32.ChangeWindowMessageFilterEx = (CHANGEWINDOWMESSAGEFILTEREX_T) + GetProcAddress(_glfw.win32.user32.instance, "ChangeWindowMessageFilterEx"); } _glfw.win32.dwmapi.instance = LoadLibrary(L"dwmapi.dll"); diff --git a/src/win32_joystick.c b/src/win32_joystick.c index 1a1723687..a68a9b4d1 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund diff --git a/src/win32_monitor.c b/src/win32_monitor.c index fb62cc609..ae4524609 100644 --- a/src/win32_monitor.c +++ b/src/win32_monitor.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -148,7 +148,7 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) name = _glfwCreateUTF8FromWideString(display.DeviceString); if (!name) { - _glfwDestroyMonitors(monitors, found); + _glfwFreeMonitors(monitors, found); _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to convert string to UTF-8"); @@ -156,7 +156,7 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) return NULL; } - monitors[found] = _glfwCreateMonitor(name, + monitors[found] = _glfwAllocMonitor(name, GetDeviceCaps(dc, HORZSIZE), GetDeviceCaps(dc, VERTSIZE)); diff --git a/src/win32_platform.h b/src/win32_platform.h index 11d774b71..ce80e4d80 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -77,6 +77,21 @@ #ifndef WM_DWMCOMPOSITIONCHANGED #define WM_DWMCOMPOSITIONCHANGED 0x031E #endif +#ifndef WM_COPYGLOBALDATA + #define WM_COPYGLOBALDATA 0x0049 +#endif + +#if WINVER < 0x0601 +typedef struct tagCHANGEFILTERSTRUCT +{ + DWORD cbSize; + DWORD ExtStatus; + +} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT; +#ifndef MSGFLT_ALLOW + #define MSGFLT_ALLOW 1 +#endif +#endif /*Windows 7*/ //======================================================================== @@ -107,7 +122,9 @@ typedef DWORD (WINAPI * TIMEGETTIME_T) (void); // user32.dll function pointer typedefs typedef BOOL (WINAPI * SETPROCESSDPIAWARE_T)(void); +typedef BOOL (WINAPI * CHANGEWINDOWMESSAGEFILTEREX_T)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); #define _glfw_SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware +#define _glfw_ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*); @@ -192,6 +209,7 @@ typedef struct _GLFWlibraryWin32 struct { HINSTANCE instance; SETPROCESSDPIAWARE_T SetProcessDPIAware; + CHANGEWINDOWMESSAGEFILTEREX_T ChangeWindowMessageFilterEx; } user32; // dwmapi.dll @@ -238,17 +256,6 @@ void _glfwInitTimer(void); void _glfwInitJoysticks(void); void _glfwTerminateJoysticks(void); -// OpenGL support -int _glfwInitContextAPI(void); -void _glfwTerminateContextAPI(void); -int _glfwCreateContext(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWfbconfig* fbconfig); -void _glfwDestroyContext(_GLFWwindow* window); -int _glfwAnalyzeContext(const _GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWfbconfig* fbconfig); - // Fullscreen support GLboolean _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoMode(_GLFWmonitor* monitor); diff --git a/src/win32_time.c b/src/win32_time.c index 6c9089550..4331119bf 100644 --- a/src/win32_time.c +++ b/src/win32_time.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund diff --git a/src/win32_window.c b/src/win32_window.c index aa2aa4bbf..ae520c447 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 Win32 - www.glfw.org +// GLFW 3.1 Win32 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -30,6 +30,7 @@ #include #include #include +#include #define _GLFW_KEY_INVALID -2 @@ -747,6 +748,40 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, // TODO: Restore vsync if compositing was disabled break; } + + case WM_DROPFILES: + { + HDROP hDrop = (HDROP) wParam; + POINT pt; + int i; + + const int count = DragQueryFile(hDrop, 0xffffffff, NULL, 0); + char** names = calloc(count, sizeof(char*)); + + // Move the mouse to the position of the drop + DragQueryPoint(hDrop, &pt); + _glfwInputCursorMotion(window, pt.x, pt.y); + + for (i = 0; i < count; i++) + { + const UINT length = DragQueryFile(hDrop, i, NULL, 0); + WCHAR* buffer = calloc(length + 1, sizeof(WCHAR)); + + DragQueryFile(hDrop, i, buffer, length + 1); + names[i] = _glfwCreateUTF8FromWideString(buffer); + + free(buffer); + } + + _glfwInputDrop(window, count, (const char**) names); + + for (i = 0; i < count; i++) + free(names[i]); + free(names); + + DragFinish(hDrop); + return 0; + } } return DefWindowProc(hWnd, uMsg, wParam, lParam); @@ -866,6 +901,18 @@ static int createWindow(_GLFWwindow* window, free(wideTitle); + if (_glfw_ChangeWindowMessageFilterEx) + { + _glfw_ChangeWindowMessageFilterEx(window->win32.handle, + WM_DROPFILES, MSGFLT_ALLOW, NULL); + _glfw_ChangeWindowMessageFilterEx(window->win32.handle, + WM_COPYDATA, MSGFLT_ALLOW, NULL); + _glfw_ChangeWindowMessageFilterEx(window->win32.handle, + WM_COPYGLOBALDATA, MSGFLT_ALLOW, NULL); + } + + DragAcceptFiles(window->win32.handle, TRUE); + if (!window->win32.handle) { _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create window"); diff --git a/src/window.c b/src/window.c index 4e2b27701..03d08fa3b 100644 --- a/src/window.c +++ b/src/window.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 - www.glfw.org +// GLFW 3.1 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund diff --git a/src/x11_clipboard.c b/src/x11_clipboard.c index 614ba363e..d8fd4d394 100644 --- a/src/x11_clipboard.c +++ b/src/x11_clipboard.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2010 Camilla Berglund // diff --git a/src/x11_gamma.c b/src/x11_gamma.c index 1831263d7..2582500ac 100644 --- a/src/x11_gamma.c +++ b/src/x11_gamma.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2010 Camilla Berglund // @@ -38,27 +38,21 @@ // void _glfwInitGammaRamp(void) { - // RandR gamma support is only available with version 1.2 and above - if (_glfw.x11.randr.available && - (_glfw.x11.randr.versionMajor > 1 || - (_glfw.x11.randr.versionMajor == 1 && - _glfw.x11.randr.versionMinor >= 2))) + if (_glfw.x11.randr.available) { - // FIXME: Assumes that all monitors have the same size gamma tables - // This is reasonable as I suspect the that if they did differ, it - // would imply that setting the gamma size to an arbitary size is - // possible as well. - XRRScreenResources* rr = XRRGetScreenResources(_glfw.x11.display, + XRRScreenResources* sr = XRRGetScreenResources(_glfw.x11.display, _glfw.x11.root); - if (XRRGetCrtcGammaSize(_glfw.x11.display, rr->crtcs[0]) == 0) + if (!sr->ncrtc || !XRRGetCrtcGammaSize(_glfw.x11.display, sr->crtcs[0])) { // This is probably older Nvidia RandR with broken gamma support - // Flag it as useless and try Xf86VidMode below, if available + // Flag it as useless and fall back to Xf86VidMode, if available + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: RandR gamma ramp support seems broken"); _glfw.x11.randr.gammaBroken = GL_TRUE; } - XRRFreeScreenResources(rr); + XRRFreeScreenResources(sr); } } diff --git a/src/x11_init.c b/src/x11_init.c index 5b477f045..84ecbf523 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -32,6 +32,7 @@ #include #include #include +#include // Translate an X11 key code to a GLFW key code. @@ -358,6 +359,8 @@ static void detectEWMH(void) return; } + _glfwGrabXErrorHandler(); + // It should be the ID of a child window (of the root) // Then we look for the same property on the child window if (_glfwGetWindowProperty(*windowFromRoot, @@ -370,6 +373,10 @@ static void detectEWMH(void) return; } + _glfwReleaseXErrorHandler(); + if (_glfw.x11.errorCode != Success) + return; + // It should be the ID of that same child window if (*windowFromRoot != *windowFromChild) { @@ -394,7 +401,6 @@ static void detectEWMH(void) (unsigned char**) &supportedAtoms); // See which of the atoms we support that are supported by the WM - _glfw.x11.NET_WM_STATE = getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE"); _glfw.x11.NET_WM_STATE_FULLSCREEN = @@ -539,6 +545,17 @@ static GLboolean initExtensions(void) _glfw.x11.SAVE_TARGETS = XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False); + // Find Xdnd (drag and drop) atoms, if available + _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", True); + _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", True); + _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", True); + _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", True); + _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", True); + _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", True); + _glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", True); + _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", True); + _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", True); + return GL_TRUE; } diff --git a/src/x11_joystick.c b/src/x11_joystick.c index 248ab127c..0c49e618d 100644 --- a/src/x11_joystick.c +++ b/src/x11_joystick.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund diff --git a/src/x11_monitor.c b/src/x11_monitor.c index 052b3c09a..97eaf1abc 100644 --- a/src/x11_monitor.c +++ b/src/x11_monitor.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -62,7 +62,7 @@ static const XRRModeInfo* getModeInfo(const XRRScreenResources* sr, RRMode id) // void _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) { - if (_glfw.x11.randr.available) + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { int i, j; XRRScreenResources* sr; @@ -136,7 +136,7 @@ void _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired) // void _glfwRestoreVideoMode(_GLFWmonitor* monitor) { - if (_glfw.x11.randr.available) + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRScreenResources* sr; XRRCrtcInfo* ci; @@ -170,13 +170,13 @@ void _glfwRestoreVideoMode(_GLFWmonitor* monitor) _GLFWmonitor** _glfwPlatformGetMonitors(int* count) { + int i, found = 0; _GLFWmonitor** monitors = NULL; *count = 0; if (_glfw.x11.randr.available) { - int i, found = 0; RROutput primary; XRRScreenResources* sr; @@ -218,8 +218,8 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) continue; } - monitors[found] = _glfwCreateMonitor(oi->name, - oi->mm_width, oi->mm_height); + monitors[found] = _glfwAllocMonitor(oi->name, + oi->mm_width, oi->mm_height); monitors[found]->x11.output = output; monitors[found]->x11.crtc = oi->crtc; @@ -245,23 +245,27 @@ _GLFWmonitor** _glfwPlatformGetMonitors(int* count) if (found == 0) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: RandR monitor support seems broken"); + _glfw.x11.randr.monitorBroken = GL_TRUE; + free(monitors); monitors = NULL; } - - *count = found; } - else + + if (!monitors) { monitors = calloc(1, sizeof(_GLFWmonitor*)); - monitors[0] = _glfwCreateMonitor("Display", - DisplayWidthMM(_glfw.x11.display, - _glfw.x11.screen), - DisplayHeightMM(_glfw.x11.display, - _glfw.x11.screen)); - *count = 1; + monitors[0] = _glfwAllocMonitor("Display", + DisplayWidthMM(_glfw.x11.display, + _glfw.x11.screen), + DisplayHeightMM(_glfw.x11.display, + _glfw.x11.screen)); + found = 1; } + *count = found; return monitors; } @@ -272,7 +276,7 @@ GLboolean _glfwPlatformIsSameMonitor(_GLFWmonitor* first, _GLFWmonitor* second) void _glfwPlatformGetMonitorPos(_GLFWmonitor* monitor, int* xpos, int* ypos) { - if (_glfw.x11.randr.available) + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRScreenResources* sr; XRRCrtcInfo* ci; @@ -309,7 +313,7 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) // Build array of available resolutions - if (_glfw.x11.randr.available) + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { int i, j; XRRScreenResources* sr; @@ -375,7 +379,7 @@ GLFWvidmode* _glfwPlatformGetVideoModes(_GLFWmonitor* monitor, int* found) void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode) { - if (_glfw.x11.randr.available) + if (_glfw.x11.randr.available && !_glfw.x11.randr.monitorBroken) { XRRScreenResources* sr; XRRCrtcInfo* ci; diff --git a/src/x11_platform.h b/src/x11_platform.h index e1e1e7cc8..398af82ad 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -119,7 +119,18 @@ typedef struct _GLFWlibraryX11 Atom NET_ACTIVE_WINDOW; Atom MOTIF_WM_HINTS; - // Selection atoms + // Xdnd (drag and drop) atoms + Atom XdndAware; + Atom XdndEnter; + Atom XdndPosition; + Atom XdndStatus; + Atom XdndActionCopy; + Atom XdndDrop; + Atom XdndLeave; + Atom XdndFinished; + Atom XdndSelection; + + // Selection (clipboard) atoms Atom TARGETS; Atom MULTIPLE; Atom CLIPBOARD; @@ -149,6 +160,7 @@ typedef struct _GLFWlibraryX11 int versionMajor; int versionMinor; GLboolean gammaBroken; + GLboolean monitorBroken; } randr; struct { @@ -189,6 +201,10 @@ typedef struct _GLFWlibraryX11 char* string; } selection; + struct { + Window source; + } xdnd; + struct { int present; int fd; @@ -224,14 +240,6 @@ void _glfwInitTimer(void); // Gamma void _glfwInitGammaRamp(void); -// OpenGL support -int _glfwInitContextAPI(void); -void _glfwTerminateContextAPI(void); -int _glfwCreateContext(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig, - const _GLFWfbconfig* fbconfig); -void _glfwDestroyContext(_GLFWwindow* window); - // Fullscreen support void _glfwSetVideoMode(_GLFWmonitor* monitor, const GLFWvidmode* desired); void _glfwRestoreVideoMode(_GLFWmonitor* monitor); diff --git a/src/x11_time.c b/src/x11_time.c index d787d895d..da8350f5b 100644 --- a/src/x11_time.c +++ b/src/x11_time.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund diff --git a/src/x11_unicode.c b/src/x11_unicode.c index b847e0f69..6b6a13db6 100644 --- a/src/x11_unicode.c +++ b/src/x11_unicode.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -854,38 +854,36 @@ static struct codepair { // Convert X11 KeySym to Unicode // -long _glfwKeySym2Unicode( KeySym keysym ) +long _glfwKeySym2Unicode(KeySym keysym) { int min = 0; int max = sizeof(keysymtab) / sizeof(struct codepair) - 1; int mid; - /* First check for Latin-1 characters (1:1 mapping) */ - if( (keysym >= 0x0020 && keysym <= 0x007e) || - (keysym >= 0x00a0 && keysym <= 0x00ff) ) - { return keysym; + // First check for Latin-1 characters (1:1 mapping) + if ((keysym >= 0x0020 && keysym <= 0x007e) || + (keysym >= 0x00a0 && keysym <= 0x00ff)) + { + return keysym; } - /* Also check for directly encoded 24-bit UCS characters */ - if( (keysym & 0xff000000) == 0x01000000 ) + // Also check for directly encoded 24-bit UCS characters + if ((keysym & 0xff000000) == 0x01000000) return keysym & 0x00ffffff; - /* Binary search in table */ - while( max >= min ) + // Binary search in table + while (max >= min) { mid = (min + max) / 2; - if( keysymtab[mid].keysym < keysym ) + if (keysymtab[mid].keysym < keysym) min = mid + 1; - else if( keysymtab[mid].keysym > keysym ) + else if (keysymtab[mid].keysym > keysym) max = mid - 1; else - { - /* Found it! */ return keysymtab[mid].ucs; - } } - /* No matching Unicode value found */ + // No matching Unicode value found return -1; } diff --git a/src/x11_window.c b/src/x11_window.c index 0dd5f30e6..fd7fbd219 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1,5 +1,5 @@ //======================================================================== -// GLFW 3.0 X11 - www.glfw.org +// GLFW 3.1 X11 - www.glfw.org //------------------------------------------------------------------------ // Copyright (c) 2002-2006 Marcus Geelnard // Copyright (c) 2006-2010 Camilla Berglund @@ -97,6 +97,51 @@ static int translateChar(XKeyEvent* event) return (int) _glfwKeySym2Unicode(keysym); } +// Splits a text/uri-list into separate file paths +// +static char** splitUriList(char* text, int* count) +{ + const char* prefix = "file://"; + char** names = NULL; + char* line; + + *count = 0; + + while ((line = strtok(text, "\r\n"))) + { + text = NULL; + + if (*line == '#') + continue; + + if (strncmp(line, prefix, strlen(prefix)) == 0) + line += strlen(prefix); + + (*count)++; + + char* name = calloc(strlen(line) + 1, 1); + names = realloc(names, *count * sizeof(char*)); + names[*count - 1] = name; + + while (*line) + { + if (line[0] == '%' && line[1] && line[2]) + { + const char digits[3] = { line[1], line[2], '\0' }; + *name = strtol(digits, NULL, 16); + line += 2; + } + else + *name = *line; + + name++; + line++; + } + } + + return names; +} + // Create the X11 window (and its colormap) // static GLboolean createWindow(_GLFWwindow* window, @@ -306,6 +351,15 @@ static GLboolean createWindow(_GLFWwindow* window, XISelectEvents(_glfw.x11.display, window->x11.handle, &eventmask, 1); } + if (_glfw.x11.XdndAware) + { + // Announce support for Xdnd (drag and drop) + const Atom version = 5; + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.XdndAware, XA_ATOM, 32, + PropModeReplace, (unsigned char*) &version, 1); + } + _glfwPlatformSetWindowTitle(window, wndconfig->title); XRRSelectInput(_glfw.x11.display, window->x11.handle, @@ -494,6 +548,7 @@ static void leaveFullscreenMode(_GLFWwindow* window) } } + // Process the specified X event // static void processEvent(XEvent *event) @@ -704,6 +759,95 @@ static void processEvent(XEvent *event) SubstructureNotifyMask | SubstructureRedirectMask, event); } + else if (event->xclient.message_type == _glfw.x11.XdndEnter) + { + // A drag operation has entered the window + // TODO: Check if UTF-8 string is supported by the source + } + else if (event->xclient.message_type == _glfw.x11.XdndDrop) + { + // The drag operation has finished dropping on + // the window, ask to convert it to a UTF-8 string + _glfw.x11.xdnd.source = event->xclient.data.l[0]; + XConvertSelection(_glfw.x11.display, + _glfw.x11.XdndSelection, + _glfw.x11.UTF8_STRING, + _glfw.x11.XdndSelection, + window->x11.handle, CurrentTime); + } + else if (event->xclient.message_type == _glfw.x11.XdndPosition) + { + // The drag operation has moved over the window + const int absX = (event->xclient.data.l[2] >> 16) & 0xFFFF; + const int absY = (event->xclient.data.l[2]) & 0xFFFF; + int x, y; + + _glfwPlatformGetWindowPos(window, &x, &y); + _glfwInputCursorMotion(window, absX - x, absY - y); + + // Reply that we are ready to copy the dragged data + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.type = ClientMessage; + reply.xclient.window = event->xclient.data.l[0]; + reply.xclient.message_type = _glfw.x11.XdndStatus; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = 1; // Always accept the dnd with no rectangle + reply.xclient.data.l[2] = 0; // Specify an empty rectangle + reply.xclient.data.l[3] = 0; + reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy; + + XSendEvent(_glfw.x11.display, event->xclient.data.l[0], + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } + + break; + } + + case SelectionNotify: + { + if (event->xselection.property) + { + // The converted data from the drag operation has arrived + char* data; + const int result = _glfwGetWindowProperty(event->xselection.requestor, + event->xselection.property, + event->xselection.target, + (unsigned char**) &data); + + if (result) + { + int i, count; + char** names = splitUriList(data, &count); + + _glfwInputDrop(window, count, (const char**) names); + + for (i = 0; i < count; i++) + free(names[i]); + free(names); + } + + XFree(data); + + XEvent reply; + memset(&reply, 0, sizeof(reply)); + + reply.type = ClientMessage; + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = result; + reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; + + // Reply that all is well + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } break; } @@ -897,7 +1041,7 @@ unsigned long _glfwGetWindowProperty(Window window, &bytesAfter, value); - if (actualType != type) + if (type != AnyPropertyType && actualType != type) return 0; return itemCount; @@ -1001,7 +1145,6 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) if (child) { int left, top; - XTranslateCoordinates(_glfw.x11.display, window->x11.handle, child, 0, 0, &left, &top, &child); diff --git a/tests/events.c b/tests/events.c index 7ac69c8e8..28c70c274 100644 --- a/tests/events.c +++ b/tests/events.c @@ -381,6 +381,16 @@ static void char_callback(GLFWwindow* window, unsigned int codepoint) get_character_string(codepoint)); } +static void drop_callback(GLFWwindow* window, int count, const char** names) +{ + int i; + + printf("%08x at %0.3f: Drop input\n", counter++, glfwGetTime()); + + for (i = 0; i < count; i++) + printf(" %i: \"%s\"\n", i, names[i]); +} + void monitor_callback(GLFWmonitor* monitor, int event) { if (event == GLFW_CONNECTED) @@ -457,6 +467,7 @@ int main(int argc, char** argv) glfwSetScrollCallback(window, scroll_callback); glfwSetKeyCallback(window, key_callback); glfwSetCharCallback(window, char_callback); + glfwSetDropCallback(window, drop_callback); glfwMakeContextCurrent(window); glfwSwapInterval(1);