diff --git a/.gitignore b/.gitignore index c5bbc0770..9fc9bef05 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ examples/heightmap examples/offscreen examples/particles examples/splitview +examples/sharing examples/simple examples/wave tests/*.app @@ -74,7 +75,6 @@ tests/joysticks tests/monitors tests/msaa tests/reopen -tests/sharing tests/tearing tests/threads tests/timeout diff --git a/CMakeLists.txt b/CMakeLists.txt index 239a8bfce..8acfe359a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -401,6 +401,7 @@ if (GLFW_INSTALL) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${GLFW_BINARY_DIR}/cmake_uninstall.cmake") + set_target_properties(uninstall PROPERTIES FOLDER "GLFW3") endif() endif() diff --git a/README.md b/README.md index 4048baf10..1aa9bf129 100644 --- a/README.md +++ b/README.md @@ -148,12 +148,14 @@ information on what to include when reporting a bug. - Added `glfwGetJoystickHats` function for querying joystick hats (#889,#906,#934) - Added `glfwInitHint` and `glfwInitHintString` for setting initialization hints +- Added `glfwGetWindowOpacity` and `glfwSetWindowOpacity` for controlling whole + window transparency (#1089) - Added `glfwGetX11SelectionString` and `glfwSetX11SelectionString` functions for accessing X11 primary selection (#894,#1056) - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850) - Added definition of `GLAPIENTRY` to public header -- Added `GLFW_TRANSPARENT` window hint for enabling window framebuffer - transparency (#197,#663,#715,#723,#1078) +- Added `GLFW_TRANSPARENT_FRAMEBUFFER` window hint and attribute for controlling + per-pixel framebuffer transparency (#197,#663,#715,#723,#1078) - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering (#749,#842) - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) @@ -168,6 +170,7 @@ information on what to include when reporting a bug. - Added `GLFW_OSMESA_CONTEXT_API` for creating OpenGL contexts with [OSMesa](https://www.mesa3d.org/osmesa.html) (#281) - Added `GenerateMappings.cmake` script for updating gamepad mappings +- Deprecated window parameter of clipboard string functions - Removed `GLFW_USE_RETINA` compile-time option - Removed `GLFW_USE_CHDIR` compile-time option - Removed `GLFW_USE_MENUBAR` compile-time option @@ -201,6 +204,7 @@ information on what to include when reporting a bug. (#650,#1071) - [Win32] Bugfix: Returned key names did not match other platforms (#943) - [Win32] Bugfix: Undecorated windows did not maximize to workarea (#899) +- [Win32] Bugfix: Window was resized twice when entering full screen (#1085) - [X11] Moved to XI2 `XI_RawMotion` for disable cursor mode motion input (#125) - [X11] Replaced `_GLFW_HAS_XF86VM` compile-time option with dynamic loading - [X11] Bugfix: `glfwGetVideoMode` would segfault on Cygwin/X @@ -241,6 +245,8 @@ information on what to include when reporting a bug. notification was shown (#971,#1028) - [Cocoa] Bugfix: Some characters did not repeat due to Press and Hold (#1010) - [Cocoa] Bugfix: Window title was lost when full screen or undecorated (#1082) +- [Cocoa] Bugfix: Window was resized twice when entering full screen (#1085) +- [Cocoa] Bugfix: Duplicate size events were not filtered (#1085) - [WGL] Added support for `WGL_EXT_colorspace` for OpenGL ES contexts - [WGL] Added support for `WGL_ARB_create_context_no_error` - [GLX] Added support for `GLX_ARB_create_context_no_error` diff --git a/docs/compat.dox b/docs/compat.dox index a27f58f3d..380244662 100644 --- a/docs/compat.dox +++ b/docs/compat.dox @@ -82,8 +82,8 @@ extension, regular accelerated mouse motion will be used. GLFW uses both the XRender extension and the compositing manager to support transparent window framebuffers. If the running X server does not support this -extension or there is no running compositing manager, the `GLFW_TRANSPARENT` -framebuffer hint will have no effect. +extension or there is no running compositing manager, the +`GLFW_TRANSPARENT_FRAMEBUFFER` framebuffer hint will have no effect. @section compat_glx GLX extensions diff --git a/docs/context.dox b/docs/context.dox index 61292849d..58c622174 100644 --- a/docs/context.dox +++ b/docs/context.dox @@ -61,7 +61,7 @@ information. The name and number of this chapter unfortunately varies between versions and APIs, but has at times been named _Shared Objects and Multiple Contexts_. -GLFW comes with a barebones object sharing test program called `sharing`. +GLFW comes with a barebones object sharing example program called `sharing`. @subsection context_offscreen Offscreen contexts @@ -103,6 +103,9 @@ Before you can make OpenGL or OpenGL ES calls, you need to have a current context of the correct type. A context can only be current for a single thread at a time, and a thread can only have a single context current at a time. +When moving a context between threads, you must make it non-current on the old +thread before making it current on the new one. + The context of a window is made current with @ref glfwMakeContextCurrent. @code diff --git a/docs/input.dox b/docs/input.dox index 318d48d5c..89ff98320 100644 --- a/docs/input.dox +++ b/docs/input.dox @@ -846,7 +846,7 @@ converted to one, you can retrieve it with @ref glfwGetClipboardString. See the reference documentation for the lifetime of the returned string. @code -const char* text = glfwGetClipboardString(window); +const char* text = glfwGetClipboardString(NULL); if (text) { insert_text(text); @@ -860,13 +860,9 @@ The contents of the system clipboard can be set to a UTF-8 encoded string with @ref glfwSetClipboardString. @code -glfwSetClipboardString(window, "A string with words in it"); +glfwSetClipboardString(NULL, "A string with words in it"); @endcode -The clipboard functions take a window handle argument because some window -systems require a window to communicate with the system clipboard. Any valid -window may be used. - @section path_drop Path drop input diff --git a/docs/news.dox b/docs/news.dox index 03a9c8dc5..adbb7724f 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -94,11 +94,17 @@ be disabled with the @ref GLFW_JOYSTICK_HAT_BUTTONS init hint. @see @ref joystick_hat -@subsection news_33_transparent Support for transparent window framebuffer +@subsection news_33_transparent Support for transparent windows and framebuffers GLFW now supports the creation of windows with transparent framebuffers on -systems with desktop compositing enabled with the @ref GLFW_TRANSPARENT window -hint and attribute. Any window decorations will still be opaque. +systems with desktop compositing enabled with the @ref +GLFW_TRANSPARENT_FRAMEBUFFER window hint and attribute. This hint must be set +before window creation and leaves any window decorations opaque. + +GLFW now also supports whole window transparency with @ref glfwGetWindowOpacity +and @ref glfwSetWindowOpacity. This value controls the opacity of the whole +window including decorations and unlike framebuffer transparency can be changed +at any time after window creation. @subsection news_33_centercursor Cursor centering window hint diff --git a/docs/window.dox b/docs/window.dox index 3e8c748f0..2c9cec917 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -225,9 +225,9 @@ __GLFW_CENTER_CURSOR__ specifies whether the cursor should be centered over newly created full screen windows. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. This hint is ignored for windowed mode windows. -@anchor GLFW_TRANSPARENT_hint -__GLFW_TRANSPARENT__ specifies whether the window framebuffer will be -transparent. If enabled and supported by the system, the window framebuffer +@anchor GLFW_TRANSPARENT_FRAMEBUFFER_hint +__GLFW_TRANSPARENT_FRAMEBUFFER__ specifies whether the window framebuffer will +be transparent. If enabled and supported by the system, the window framebuffer alpha channel will be used to combine the framebuffer with the background. This does not affect window decorations. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. @@ -477,7 +477,7 @@ GLFW_AUTO_ICONIFY | `GLFW_TRUE` | `GLFW_TRUE` or `GL GLFW_FLOATING | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_MAXIMIZED | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_CENTER_CURSOR | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` -GLFW_TRANSPARENT | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` +GLFW_TRANSPARENT_FRAMEBUFFER | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_RED_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` GLFW_GREEN_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` GLFW_BLUE_BITS | 8 | 0 to `INT_MAX` or `GLFW_DONT_CARE` @@ -1091,27 +1091,63 @@ the window or framebuffer is resized. @subsection window_transparency Window transparency +GLFW supports two kinds of transparency for windows; framebuffer transparency +and whole window transparency. A single window may not use both methods. The +results of doing this are undefined. + +Both methods require the platform to support it and not every version of every +platform GLFW supports does this, so there are mechanisms to check whether the +window really is transparent. + Window framebuffers can be made transparent on a per-pixel per-frame basis with -the [GLFW_TRANSPARENT](@ref GLFW_TRANSPARENT_hint) window hint. +the [GLFW_TRANSPARENT_FRAMEBUFFER](@ref GLFW_TRANSPARENT_FRAMEBUFFER_hint) +window hint. @code -glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE); +glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); @endcode -If supported by the system, the window framebuffer will be composited with the +If supported by the system, the window content area will be composited with the background using the framebuffer per-pixel alpha channel. This requires desktop compositing to be enabled on the system. It does not affect window decorations. You can check whether the window framebuffer was successfully made transparent -with the [GLFW_TRANSPARENT](@ref GLFW_TRANSPARENT_attrib) window attribute. +with the +[GLFW_TRANSPARENT_FRAMEBUFFER](@ref GLFW_TRANSPARENT_FRAMEBUFFER_attrib) +window attribute. @code -if (glfwGetWindowAttrib(window, GLFW_TRANSPARENT)) +if (glfwGetWindowAttrib(window, GLFW_TRANSPARENT_FRAMEBUFFER)) { // window framebuffer is currently transparent } @endcode +GLFW comes with an example that enabled framebuffer transparency called `gears`. + +The opacity of the whole window, including any decorations, can be set with @ref +glfwSetWindowOpacity. + +@code +glfwSetWindowOpacity(window, 0.5f); +@endcode + +The opacity (or alpha) value is a positive finite number between zero and one, +where 0 (zero) is fully transparent and 1 (one) is fully opaque. The initial +opacity value for newly created windows is 1. + +The current opacity of a window can be queried with @ref glfwGetWindowOpacity. + +@code +float opacity = glfwGetWindowOpacity(window); +@endcode + +If the system does not support whole window transparency, this function always +returns one. + +GLFW comes with a test program that lets you control whole window transparency +at run-time called `opacity`. + @subsection window_attribs Window attributes @@ -1182,10 +1218,11 @@ called topmost or always-on-top. This can be set before creation with the [GLFW_FLOATING](@ref GLFW_FLOATING_hint) window hint or after with @ref glfwSetWindowAttrib. -@anchor GLFW_TRANSPARENT_attrib -__GLFW_TRANSPARENT__ indicates whether the specified window has a transparent -framebuffer, i.e. the window contents is composited with the background using -the window framebuffer alpha channel. See @ref window_transparency for details. +@anchor GLFW_TRANSPARENT_FRAMEBUFFER_attrib +__GLFW_TRANSPARENT_FRAMEBUFFER__ indicates whether the specified window has +a transparent framebuffer, i.e. the window contents is composited with the +background using the window framebuffer alpha channel. See @ref +window_transparency for details. @subsubsection window_attribs_ctx Context related attributes diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 6203a67e1..3508f5d11 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -35,17 +35,17 @@ add_executable(gears WIN32 MACOSX_BUNDLE gears.c ${ICON} ${GLAD}) add_executable(heightmap WIN32 MACOSX_BUNDLE heightmap.c ${ICON} ${GLAD}) add_executable(offscreen offscreen.c ${ICON} ${GLAD}) add_executable(particles WIN32 MACOSX_BUNDLE particles.c ${ICON} ${TINYCTHREAD} ${GETOPT} ${GLAD}) +add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c ${ICON} ${GLAD}) add_executable(simple WIN32 MACOSX_BUNDLE simple.c ${ICON} ${GLAD}) add_executable(splitview WIN32 MACOSX_BUNDLE splitview.c ${ICON} ${GLAD}) add_executable(wave WIN32 MACOSX_BUNDLE wave.c ${ICON} ${GLAD}) -add_executable(pen WIN32 MACOSX_BUNDLE pen.c ${ICON} ${GLAD}) target_link_libraries(particles "${CMAKE_THREAD_LIBS_INIT}") if (RT_LIBRARY) target_link_libraries(particles "${RT_LIBRARY}") endif() -set(WINDOWS_BINARIES boing gears heightmap particles simple splitview wave pen) +set(WINDOWS_BINARIES boing gears heightmap particles sharing simple splitview wave) set(CONSOLE_BINARIES offscreen) set_target_properties(${WINDOWS_BINARIES} ${CONSOLE_BINARIES} PROPERTIES @@ -62,6 +62,7 @@ if (APPLE) set_target_properties(gears PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gears") set_target_properties(heightmap PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Heightmap") set_target_properties(particles PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Particles") + set_target_properties(sharing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Sharing") set_target_properties(simple PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Simple") set_target_properties(splitview PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "SplitView") set_target_properties(wave PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Wave") diff --git a/examples/gears.c b/examples/gears.c index f14b300a7..467a955b2 100644 --- a/examples/gears.c +++ b/examples/gears.c @@ -312,7 +312,7 @@ int main(int argc, char *argv[]) } glfwWindowHint(GLFW_DEPTH_BITS, 16); - glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE); + glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL ); if (!window) diff --git a/tests/sharing.c b/examples/sharing.c similarity index 86% rename from tests/sharing.c rename to examples/sharing.c index e5ffadc95..be35fafff 100644 --- a/tests/sharing.c +++ b/examples/sharing.c @@ -1,5 +1,5 @@ //======================================================================== -// Context sharing test program +// Context sharing example // Copyright (c) Camilla Löwy // // This software is provided 'as-is', without any express or implied @@ -22,15 +22,10 @@ // distribution. // //======================================================================== -// -// This program is used to test sharing of objects between contexts -// -//======================================================================== #include #include -#include #include #include @@ -71,17 +66,6 @@ static void error_callback(int error, const char* description) fprintf(stderr, "Error: %s\n", description); } -void APIENTRY debug_callback(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar* message, - const void* user) -{ - fprintf(stderr, "Error: %s\n", message); -} - static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (action == GLFW_PRESS && key == GLFW_KEY_ESCAPE) @@ -90,28 +74,15 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, int main(int argc, char** argv) { - int ch; GLFWwindow* windows[2]; GLuint texture, program, vertex_buffer; GLint mvp_location, vpos_location, color_location, texture_location; - srand((unsigned int) time(NULL)); - glfwSetErrorCallback(error_callback); if (!glfwInit()) exit(EXIT_FAILURE); - while ((ch = getopt(argc, argv, "d")) != -1) - { - switch (ch) - { - case 'd': - glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE); - break; - } - } - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); @@ -134,12 +105,6 @@ int main(int argc, char** argv) // pointers should be re-usable between them gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); - if (GLAD_GL_KHR_debug) - { - glDebugMessageCallback(debug_callback, NULL); - glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE); - } - // Create the OpenGL objects inside the first context, created above // All objects will be shared with the second context, created below { @@ -150,6 +115,8 @@ int main(int argc, char** argv) glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); + srand((unsigned int) glfwGetTimerValue()); + for (y = 0; y < 16; y++) { for (x = 0; x < 16; x++) @@ -235,8 +202,8 @@ int main(int argc, char** argv) int i; const vec3 colors[2] = { - { 0.3f, 0.4f, 1.f }, - { 0.8f, 0.4f, 1.f } + { 0.8f, 0.4f, 1.f }, + { 0.3f, 0.4f, 1.f } }; for (i = 0; i < 2; i++) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index ecf62d5dc..7d1787dd8 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -791,10 +791,11 @@ extern "C" { #define GLFW_CENTER_CURSOR 0x00020009 /*! @brief Window framebuffer transparency hint and attribute * - * Window framebuffer transparency [window hint](@ref GLFW_TRANSPARENT_hint) - * and [window attribute](@ref GLFW_TRANSPARENT_attrib). + * Window framebuffer transparency + * [window hint](@ref GLFW_TRANSPARENT_FRAMEBUFFER_hint) and + * [window attribute](@ref GLFW_TRANSPARENT_FRAMEBUFFER_attrib). */ -#define GLFW_TRANSPARENT 0x0002000A +#define GLFW_TRANSPARENT_FRAMEBUFFER 0x0002000A /*! @brief Framebuffer bit depth hint. * @@ -1404,6 +1405,8 @@ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); * @sa @ref input_char * @sa @ref glfwSetCharModsCallback * + * @deprecated Scheduled for removal in version 4.0. + * * @since Added in version 3.1. * * @ingroup input @@ -2309,8 +2312,8 @@ GLFWAPI void glfwWindowHint(int hint, int value); * * @remark @win32 If the executable has an icon resource named `GLFW_ICON,` it * will be set as the initial icon for the window. If no such icon is present, - * the `IDI_WINLOGO` icon will be used instead. To set a different icon, see - * @ref glfwSetWindowIcon. + * the `IDI_APPLICATION` icon will be used instead. To set a different icon, + * see @ref glfwSetWindowIcon. * * @remark @win32 The context to share resources with must not be current on * any other thread. @@ -2855,6 +2858,62 @@ GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int */ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* window, float* xscale, float* yscale); +/*! @brief Returns the opacity of the whole window. + * + * This function returns the opacity of the window, including any decorations. + * + * The opacity (or alpha) value is a positive finite number between zero and + * one, where zero is fully transparent and one is fully opaque. If the system + * does not support whole window transparency, this function always returns one. + * + * The initial opacity value for newly created windows is one. + * + * @param[in] window The window to query. + * @return The opacity value of the specified window. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_transparency + * @sa @ref glfwSetWindowOpacity + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI float glfwGetWindowOpacity(GLFWwindow* window); + +/*! @brief Sets the opacity of the whole window. + * + * This function sets the opacity of the window, including any decorations. + * + * The opacity (or alpha) value is a positive finite number between zero and + * one, where zero is fully transparent and one is fully opaque. + * + * The initial opacity value for newly created windows is one. + * + * A window created with framebuffer transparency may not use whole window + * transparency. The results of doing this are undefined. + * + * @param[in] window The window to set the opacity for. + * @param[in] opacity The desired opacity of the specified window. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref window_transparency + * @sa @ref glfwGetWindowOpacity + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI void glfwSetWindowOpacity(GLFWwindow* window, float opacity); + /*! @brief Iconifies the specified window. * * This function iconifies (minimizes) the specified window if it was @@ -4164,6 +4223,8 @@ GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); * @return The previously set callback, or `NULL` if no callback was set or an * [error](@ref error_handling) occurred. * + * @deprecated Scheduled for removal in version 4.0. + * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. * * @thread_safety This function must only be called from the main thread. @@ -4722,7 +4783,7 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state); * This function sets the system clipboard to the specified, UTF-8 encoded * string. * - * @param[in] window The window that will own the clipboard contents. + * @param[in] window Deprecated. Any valid window or `NULL`. * @param[in] string A UTF-8 encoded string. * * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref @@ -4751,7 +4812,7 @@ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); * if its contents cannot be converted, `NULL` is returned and a @ref * GLFW_FORMAT_UNAVAILABLE error is generated. * - * @param[in] window The window that will request the clipboard contents. + * @param[in] window Deprecated. Any valid window or `NULL`. * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` * if an [error](@ref error_handling) occurred. * @@ -4876,10 +4937,13 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void); * thread. * * This function makes the OpenGL or OpenGL ES context of the specified window - * current on the calling thread. A context can only be made current on + * current on the calling thread. A context must only be made current on * a single thread at a time and each thread can have only a single current * context at a time. * + * When moving a context between threads, you must make it non-current on the + * old thread before making it current on the new one. + * * By default, making a context non-current implicitly forces a pipeline flush. * On machines that support `GL_KHR_context_flush_control`, you can control * whether a context performs this flush by setting the diff --git a/src/cocoa_platform.h b/src/cocoa_platform.h index 61d0ee916..d5cc2379a 100644 --- a/src/cocoa_platform.h +++ b/src/cocoa_platform.h @@ -88,6 +88,10 @@ typedef struct _GLFWwindowNS GLFWbool maximized; + // Cached window and framebuffer sizes used to filter out duplicate events + int width, height; + int fbWidth, fbHeight; + // The total sum of the distances the cursor has been warped // since the last cursor motion event was processed // This is kept to counteract Cocoa doing the same internally diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 1ee85bc60..16fbb7bfd 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -267,8 +267,21 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; - _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); - _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); + if (fbRect.size.width != window->ns.fbWidth || + fbRect.size.height != window->ns.fbHeight) + { + window->ns.fbWidth = fbRect.size.width; + window->ns.fbHeight = fbRect.size.height; + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + } + + if (contentRect.size.width != window->ns.width || + contentRect.size.height != window->ns.height) + { + window->ns.width = contentRect.size.width; + window->ns.height = contentRect.size.height; + _glfwInputWindowSize(window, contentRect.size.width, contentRect.size.height); + } } - (void)windowDidMove:(NSNotification *)notification @@ -551,7 +564,13 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; const NSRect contentRect = [window->ns.view frame]; const NSRect fbRect = [window->ns.view convertRectToBacking:contentRect]; - _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + if (fbRect.size.width != window->ns.fbWidth || + fbRect.size.height != window->ns.fbHeight) + { + window->ns.fbWidth = fbRect.size.width; + window->ns.fbHeight = fbRect.size.height; + _glfwInputFramebufferSize(window, fbRect.size.width, fbRect.size.height); + } } - (void)drawRect:(NSRect)rect @@ -1095,6 +1114,9 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, [window->ns.object setAcceptsMouseMovedEvents:YES]; [window->ns.object setRestorable:NO]; + _glfwPlatformGetWindowSize(window, &window->ns.width, &window->ns.height); + _glfwPlatformGetFramebufferSize(window, &window->ns.fbWidth, &window->ns.fbHeight); + return GLFW_TRUE; } @@ -1385,28 +1407,6 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, [window->ns.object setStyleMask:styleMask]; [window->ns.object makeFirstResponder:window->ns.view]; - NSRect contentRect; - - if (monitor) - { - GLFWvidmode mode; - - _glfwPlatformGetVideoMode(window->monitor, &mode); - _glfwPlatformGetMonitorPos(window->monitor, &xpos, &ypos); - - contentRect = NSMakeRect(xpos, transformY(ypos + mode.height), - mode.width, mode.height); - } - else - { - contentRect = NSMakeRect(xpos, transformY(ypos + height), - width, height); - } - - NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect - styleMask:styleMask]; - [window->ns.object setFrame:frameRect display:YES]; - if (monitor) { [window->ns.object setLevel:NSMainMenuWindowLevel + 1]; @@ -1416,6 +1416,12 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, } else { + NSRect contentRect = NSMakeRect(xpos, transformY(ypos + height), + width, height); + NSRect frameRect = [window->ns.object frameRectForContentRect:contentRect + styleMask:styleMask]; + [window->ns.object setFrame:frameRect display:YES]; + if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE) { @@ -1493,6 +1499,16 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) [window->ns.object setLevel:NSNormalWindowLevel]; } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return (float) [window->ns.object alphaValue]; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ + [window->ns.object setAlphaValue:opacity]; +} + void _glfwPlatformPollEvents(void) { for (;;) @@ -1740,7 +1756,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) updateCursorImage(window); } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { NSArray* types = [NSArray arrayWithObjects:NSStringPboardType, nil]; @@ -1750,7 +1766,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) forType:NSStringPboardType]; } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; diff --git a/src/glx_context.c b/src/glx_context.c index 708663a9e..40da6c2fd 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -634,7 +634,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, // Returns the Visual and depth of the chosen GLXFBConfig // GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, - const _GLFWctxconfig* ctxconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth) { diff --git a/src/init.c b/src/init.c index 19a13e0df..5d6577ebb 100644 --- a/src/init.c +++ b/src/init.c @@ -205,12 +205,13 @@ GLFWAPI int glfwInit(void) return GLFW_FALSE; } - if (!_glfwPlatformCreateMutex(&_glfw.errorLock)) - return GLFW_FALSE; - if (!_glfwPlatformCreateTls(&_glfw.errorSlot)) - return GLFW_FALSE; - if (!_glfwPlatformCreateTls(&_glfw.contextSlot)) + if (!_glfwPlatformCreateMutex(&_glfw.errorLock) || + !_glfwPlatformCreateTls(&_glfw.errorSlot) || + !_glfwPlatformCreateTls(&_glfw.contextSlot)) + { + terminate(); return GLFW_FALSE; + } _glfwPlatformSetTls(&_glfw.errorSlot, &_glfwMainThreadError); @@ -218,7 +219,12 @@ GLFWAPI int glfwInit(void) _glfw.timer.offset = _glfwPlatformGetTimerValue(); glfwDefaultWindowHints(); - glfwUpdateGamepadMappings(_glfwDefaultMappings); + + if (!glfwUpdateGamepadMappings(_glfwDefaultMappings)) + { + terminate(); + return GLFW_FALSE; + } return GLFW_TRUE; } diff --git a/src/input.c b/src/input.c index 3138e8f0a..e3cfed46e 100644 --- a/src/input.c +++ b/src/input.c @@ -1133,21 +1133,16 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) { - _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window != NULL); assert(string != NULL); _GLFW_REQUIRE_INIT(); - _glfwPlatformSetClipboardString(window, string); + _glfwPlatformSetClipboardString(string); } GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) { - _GLFWwindow* window = (_GLFWwindow*) handle; - assert(window != NULL); - _GLFW_REQUIRE_INIT_OR_RETURN(NULL); - return _glfwPlatformGetClipboardString(window); + return _glfwPlatformGetClipboardString(); } GLFWAPI double glfwGetTime(void) diff --git a/src/internal.h b/src/internal.h index 9908e951f..2f8b18045 100644 --- a/src/internal.h +++ b/src/internal.h @@ -25,6 +25,8 @@ // //======================================================================== +#pragma once + #if defined(_GLFW_USE_CONFIG_H) #include "glfw_config.h" #endif @@ -651,8 +653,8 @@ void _glfwPlatformGetVideoMode(_GLFWmonitor* monitor, GLFWvidmode* mode); void _glfwPlatformGetGammaRamp(_GLFWmonitor* monitor, GLFWgammaramp* ramp); void _glfwPlatformSetGammaRamp(_GLFWmonitor* monitor, const GLFWgammaramp* ramp); -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string); -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window); +void _glfwPlatformSetClipboardString(const char* string); +const char* _glfwPlatformGetClipboardString(void); int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode); void _glfwPlatformUpdateGamepadGUID(char* guid); @@ -689,9 +691,11 @@ int _glfwPlatformWindowIconified(_GLFWwindow* window); int _glfwPlatformWindowVisible(_GLFWwindow* window); int _glfwPlatformWindowMaximized(_GLFWwindow* window); int _glfwPlatformFramebufferTransparent(_GLFWwindow* window); +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window); void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled); void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled); +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity); void _glfwPlatformPollEvents(void); void _glfwPlatformWaitEvents(void); diff --git a/src/mir_window.c b/src/mir_window.c index c752cdb47..fd8f2914d 100644 --- a/src/mir_window.c +++ b/src/mir_window.c @@ -648,6 +648,15 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) "Mir: Unsupported function %s", __PRETTY_FUNCTION__); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ +} + void _glfwPlatformPollEvents(void) { EventNode* node = NULL; @@ -858,13 +867,13 @@ int _glfwPlatformGetKeyScancode(int key) return _glfw.mir.scancodes[key]; } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { _glfwInputError(GLFW_PLATFORM_ERROR, "Mir: Unsupported function %s", __PRETTY_FUNCTION__); } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { _glfwInputError(GLFW_PLATFORM_ERROR, "Mir: Unsupported function %s", __PRETTY_FUNCTION__); diff --git a/src/monitor.c b/src/monitor.c index 0dfb19584..6f64cca5d 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -113,9 +113,11 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement) { if (window->monitor == monitor) { - int width, height; + int width, height, xoff, yoff; _glfwPlatformGetWindowSize(window, &width, &height); _glfwPlatformSetWindowMonitor(window, NULL, 0, 0, width, height, 0); + _glfwPlatformGetWindowFrameSize(window, &xoff, &yoff, NULL, NULL); + _glfwPlatformSetWindowPos(window, xoff, yoff); } } diff --git a/src/null_window.c b/src/null_window.c index 3cc3905d1..6eb4ac6e2 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -182,6 +182,15 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) { } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ +} + void _glfwPlatformShowWindow(_GLFWwindow* window) { } @@ -266,11 +275,11 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) { } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { return NULL; } diff --git a/src/win32_joystick.c b/src/win32_joystick.c index ad2dbb2f1..d9d341ff5 100644 --- a/src/win32_joystick.c +++ b/src/win32_joystick.c @@ -711,9 +711,9 @@ int _glfwPlatformPollJoystick(_GLFWjoystick* js, int mode) return GLFW_TRUE; _glfwInputJoystickAxis(js, 0, (xis.Gamepad.sThumbLX + 0.5f) / 32767.5f); - _glfwInputJoystickAxis(js, 1, (xis.Gamepad.sThumbLY + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 1, -(xis.Gamepad.sThumbLY + 0.5f) / 32767.5f); _glfwInputJoystickAxis(js, 2, (xis.Gamepad.sThumbRX + 0.5f) / 32767.5f); - _glfwInputJoystickAxis(js, 3, (xis.Gamepad.sThumbRY + 0.5f) / 32767.5f); + _glfwInputJoystickAxis(js, 3, -(xis.Gamepad.sThumbRY + 0.5f) / 32767.5f); _glfwInputJoystickAxis(js, 4, xis.Gamepad.bLeftTrigger / 127.5f - 1.f); _glfwInputJoystickAxis(js, 5, xis.Gamepad.bRightTrigger / 127.5f - 1.f); diff --git a/src/win32_platform.h b/src/win32_platform.h index 8f0b34a15..ac54c4d95 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -348,8 +348,8 @@ typedef struct _GLFWmonitorWin32 // This size matches the static size of DISPLAY_DEVICE.DeviceName WCHAR adapterName[32]; WCHAR displayName[32]; - char publicAdapterName[64]; - char publicDisplayName[64]; + char publicAdapterName[32]; + char publicDisplayName[32]; GLFWbool modesPruned; GLFWbool modeChanged; diff --git a/src/win32_window.c b/src/win32_window.c index 9fd5c13cf..df75d2deb 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1559,58 +1559,51 @@ void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _glfwInputWindowMonitor(window, monitor); - if (monitor) - { - GLFWvidmode mode; - DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); - UINT flags = SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOCOPYBITS; + if (monitor) + { + if (window->decorated) + { + DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_FRAMECHANGED | SWP_SHOWWINDOW | + SWP_NOACTIVATE | SWP_NOCOPYBITS | + SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE; - if (window->decorated) - { - style &= ~WS_OVERLAPPEDWINDOW; - style |= getWindowStyle(window); - SetWindowLongW(window->win32.handle, GWL_STYLE, style); + style &= ~WS_OVERLAPPEDWINDOW; + style |= getWindowStyle(window); + SetWindowLongW(window->win32.handle, GWL_STYLE, style); + SetWindowPos(window->win32.handle, HWND_TOPMOST, 0, 0, 0, 0, flags); + } - flags |= SWP_FRAMECHANGED; - } + acquireMonitor(window); + } + else + { + HWND after; + RECT rect = { xpos, ypos, xpos + width, ypos + height }; + DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); + UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS; - _glfwPlatformGetVideoMode(monitor, &mode); - _glfwPlatformGetMonitorPos(monitor, &xpos, &ypos); + if (window->decorated) + { + style &= ~WS_POPUP; + style |= getWindowStyle(window); + SetWindowLongW(window->win32.handle, GWL_STYLE, style); - SetWindowPos(window->win32.handle, HWND_TOPMOST, - xpos, ypos, mode.width, mode.height, - flags); + flags |= SWP_FRAMECHANGED; + } - acquireMonitor(window); - } - else - { - HWND after; - RECT rect = { xpos, ypos, xpos + width, ypos + height }; - DWORD style = GetWindowLongW(window->win32.handle, GWL_STYLE); - UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS; + if (window->floating) + after = HWND_TOPMOST; + else + after = HWND_NOTOPMOST; - if (window->decorated) - { - style &= ~WS_POPUP; - style |= getWindowStyle(window); - SetWindowLongW(window->win32.handle, GWL_STYLE, style); - - flags |= SWP_FRAMECHANGED; - } - - if (window->floating) - after = HWND_TOPMOST; - else - after = HWND_NOTOPMOST; - - AdjustWindowRectEx(&rect, getWindowStyle(window), - FALSE, getWindowExStyle(window)); - SetWindowPos(window->win32.handle, after, - rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, - flags); - } + AdjustWindowRectEx(&rect, getWindowStyle(window), + FALSE, getWindowExStyle(window)); + SetWindowPos(window->win32.handle, after, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + flags); + } } int _glfwPlatformWindowFocused(_GLFWwindow* window) @@ -1655,6 +1648,39 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + BYTE alpha; + DWORD flags; + + if ((GetWindowLongW(window->win32.handle, GWL_EXSTYLE) & WS_EX_LAYERED) && + GetLayeredWindowAttributes(window->win32.handle, NULL, &alpha, &flags)) + { + if (flags & LWA_ALPHA) + return alpha / 255.f; + } + + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ + if (opacity < 1.f) + { + const BYTE alpha = (BYTE) (255 * opacity); + DWORD style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + style |= WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + SetLayeredWindowAttributes(window->win32.handle, 0, alpha, LWA_ALPHA); + } + else + { + DWORD style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE); + style &= ~WS_EX_LAYERED; + SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style); + } +} + void _glfwPlatformPollEvents(void) { MSG msg; @@ -1860,7 +1886,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) updateCursorImage(window); } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { int characterCount; HANDLE object; @@ -1903,7 +1929,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) CloseClipboard(); } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { HANDLE object; WCHAR* buffer; diff --git a/src/window.c b/src/window.c index 2c6f8dd00..27684f74d 100644 --- a/src/window.c +++ b/src/window.c @@ -315,7 +315,7 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_DOUBLEBUFFER: _glfw.hints.framebuffer.doublebuffer = value ? GLFW_TRUE : GLFW_FALSE; return; - case GLFW_TRANSPARENT: + case GLFW_TRANSPARENT_FRAMEBUFFER: _glfw.hints.framebuffer.transparent = value ? GLFW_TRUE : GLFW_FALSE; return; case GLFW_SAMPLES: @@ -647,6 +647,34 @@ GLFWAPI void glfwGetWindowContentScale(GLFWwindow* handle, _glfwPlatformGetWindowContentScale(window, xscale, yscale); } +GLFWAPI float glfwGetWindowOpacity(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(1.f); + return _glfwPlatformGetWindowOpacity(window); +} + +GLFWAPI void glfwSetWindowOpacity(GLFWwindow* handle, float opacity) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + assert(opacity == opacity); + assert(opacity >= 0.f); + assert(opacity <= 1.f); + + _GLFW_REQUIRE_INIT(); + + if (opacity != opacity || opacity < 0.f || opacity > 1.f) + { + _glfwInputError(GLFW_INVALID_VALUE, "Invalid window opacity %f", opacity); + return; + } + + _glfwPlatformSetWindowOpacity(window, opacity); +} + GLFWAPI void glfwIconifyWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; @@ -742,7 +770,7 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return _glfwPlatformWindowVisible(window); case GLFW_MAXIMIZED: return _glfwPlatformWindowMaximized(window); - case GLFW_TRANSPARENT: + case GLFW_TRANSPARENT_FRAMEBUFFER: return _glfwPlatformFramebufferTransparent(window); case GLFW_RESIZABLE: return window->resizable; diff --git a/src/wl_window.c b/src/wl_window.c index f0f2637e4..b2ae7aae2 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -692,6 +692,15 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) "Wayland: Window attribute setting not implemented yet"); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + return 1.f; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ +} + void _glfwPlatformPollEvents(void) { handleEvents(0); @@ -1008,14 +1017,14 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) } } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { // TODO _glfwInputError(GLFW_PLATFORM_ERROR, "Wayland: Clipboard setting not implemented yet"); } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { // TODO _glfwInputError(GLFW_PLATFORM_ERROR, diff --git a/src/x11_init.c b/src/x11_init.c index b603a15f2..4c863c38c 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -737,9 +737,18 @@ static GLFWbool initExtensions(void) XInternAtom(_glfw.x11.display, "_NET_WM_ICON_NAME", False); _glfw.x11.NET_WM_BYPASS_COMPOSITOR = XInternAtom(_glfw.x11.display, "_NET_WM_BYPASS_COMPOSITOR", False); + _glfw.x11.NET_WM_WINDOW_OPACITY = + XInternAtom(_glfw.x11.display, "_NET_WM_WINDOW_OPACITY", False); _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); + // The compositing manager selection name contains the screen number + { + char name[32]; + snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen); + _glfw.x11.NET_WM_CM_Sx = XInternAtom(_glfw.x11.display, name, False); + } + return GLFW_TRUE; } diff --git a/src/x11_platform.h b/src/x11_platform.h index 7eba441d5..c5a11cf24 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -257,6 +257,8 @@ typedef struct _GLFWlibraryX11 Atom NET_WM_STATE_DEMANDS_ATTENTION; Atom NET_WM_BYPASS_COMPOSITOR; Atom NET_WM_FULLSCREEN_MONITORS; + Atom NET_WM_WINDOW_OPACITY; + Atom NET_WM_CM_Sx; Atom NET_ACTIVE_WINDOW; Atom NET_FRAME_EXTENTS; Atom NET_REQUEST_FRAME_EXTENTS; diff --git a/src/x11_window.c b/src/x11_window.c index c89d2ec51..32fff63b6 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2449,11 +2449,7 @@ int _glfwPlatformFramebufferTransparent(_GLFWwindow* window) if (!window->x11.transparent) return GLFW_FALSE; - // Check whether a compositing manager is running - char name[32]; - snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen); - const Atom selection = XInternAtom(_glfw.x11.display, name, False); - return XGetSelectionOwner(_glfw.x11.display, selection) != None; + return XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx) != None; } void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled) @@ -2559,6 +2555,37 @@ void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled) XFlush(_glfw.x11.display); } +float _glfwPlatformGetWindowOpacity(_GLFWwindow* window) +{ + float opacity = 1.f; + + if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx)) + { + CARD32* value = NULL; + + if (_glfwGetWindowPropertyX11(window->x11.handle, + _glfw.x11.NET_WM_WINDOW_OPACITY, + XA_CARDINAL, + (unsigned char**) &value)) + { + opacity = (float) (*value / (double) 0xffffffffu); + } + + if (value) + XFree(value); + } + + return opacity; +} + +void _glfwPlatformSetWindowOpacity(_GLFWwindow* window, float opacity) +{ + const CARD32 value = (CARD32) (0xffffffffu * (double) opacity); + XChangeProperty(_glfw.x11.display, window->x11.handle, + _glfw.x11.NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, + PropModeReplace, (unsigned char*) &value, 1); +} + void _glfwPlatformPollEvents(void) { _GLFWwindow* window; @@ -2773,7 +2800,7 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) } } -void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) +void _glfwPlatformSetClipboardString(const char* string) { free(_glfw.x11.clipboardString); _glfw.x11.clipboardString = strdup(string); @@ -2791,7 +2818,7 @@ void _glfwPlatformSetClipboardString(_GLFWwindow* window, const char* string) } } -const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) +const char* _glfwPlatformGetClipboardString(void) { return getSelectionString(_glfw.x11.CLIPBOARD); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1a39d59d4..52b08389d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,7 +32,7 @@ add_executable(gamma WIN32 MACOSX_BUNDLE gamma.c ${GLAD}) add_executable(icon WIN32 MACOSX_BUNDLE icon.c ${GLAD}) add_executable(inputlag WIN32 MACOSX_BUNDLE inputlag.c ${GETOPT} ${GLAD}) add_executable(joysticks WIN32 MACOSX_BUNDLE joysticks.c ${GLAD}) -add_executable(sharing WIN32 MACOSX_BUNDLE sharing.c ${GETOPT} ${GLAD}) +add_executable(opacity WIN32 MACOSX_BUNDLE opacity.c ${GLAD}) add_executable(tearing WIN32 MACOSX_BUNDLE tearing.c ${GETOPT} ${GLAD}) add_executable(threads WIN32 MACOSX_BUNDLE threads.c ${TINYCTHREAD} ${GLAD}) add_executable(timeout WIN32 MACOSX_BUNDLE timeout.c ${GLAD}) @@ -46,8 +46,8 @@ if (RT_LIBRARY) target_link_libraries(threads "${RT_LIBRARY}") endif() -set(WINDOWS_BINARIES empty gamma icon inputlag joysticks sharing tearing threads - timeout title windows) +set(WINDOWS_BINARIES empty gamma icon inputlag joysticks opacity tearing + threads timeout title windows) set(CONSOLE_BINARIES clipboard events msaa glfwinfo iconify monitors reopen cursor) @@ -76,7 +76,7 @@ if (APPLE) set_target_properties(gamma PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Gamma") set_target_properties(inputlag PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Input Lag") set_target_properties(joysticks PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Joysticks") - set_target_properties(sharing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Sharing") + set_target_properties(opacity PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Opacity") set_target_properties(tearing PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Tearing") set_target_properties(threads PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Threads") set_target_properties(timeout PROPERTIES MACOSX_BUNDLE_BUNDLE_NAME "Timeout") diff --git a/tests/clipboard.c b/tests/clipboard.c index a24d0c07c..7281a05dd 100644 --- a/tests/clipboard.c +++ b/tests/clipboard.c @@ -67,7 +67,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, { const char* string; - string = glfwGetClipboardString(window); + string = glfwGetClipboardString(NULL); if (string) printf("Clipboard contains \"%s\"\n", string); else @@ -79,7 +79,7 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action, if (mods == MODIFIER) { const char* string = "Hello GLFW World!"; - glfwSetClipboardString(window, string); + glfwSetClipboardString(NULL, string); printf("Setting clipboard to \"%s\"\n", string); } break; diff --git a/tests/opacity.c b/tests/opacity.c new file mode 100644 index 000000000..3176c9ff9 --- /dev/null +++ b/tests/opacity.c @@ -0,0 +1,106 @@ +//======================================================================== +// Window opacity test program +// Copyright (c) Camilla Löwy +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would +// be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not +// be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +//======================================================================== + +#include +#include + +#define NK_IMPLEMENTATION +#define NK_INCLUDE_FIXED_TYPES +#define NK_INCLUDE_FONT_BAKING +#define NK_INCLUDE_DEFAULT_FONT +#define NK_INCLUDE_DEFAULT_ALLOCATOR +#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT +#define NK_INCLUDE_STANDARD_VARARGS +#include + +#define NK_GLFW_GL2_IMPLEMENTATION +#include + +#include +#include + +static void error_callback(int error, const char* description) +{ + fprintf(stderr, "Error: %s\n", description); +} + +int main(int argc, char** argv) +{ + GLFWmonitor* monitor = NULL; + GLFWwindow* window; + struct nk_context* nk; + struct nk_font_atlas* atlas; + + glfwSetErrorCallback(error_callback); + + if (!glfwInit()) + exit(EXIT_FAILURE); + + window = glfwCreateWindow(400, 400, "Opacity", NULL, NULL); + if (!window) + { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); + glfwSwapInterval(1); + + nk = nk_glfw3_init(window, NK_GLFW3_INSTALL_CALLBACKS); + nk_glfw3_font_stash_begin(&atlas); + nk_glfw3_font_stash_end(); + + while (!glfwWindowShouldClose(window)) + { + int width, height; + struct nk_rect area; + + glfwGetWindowSize(window, &width, &height); + area = nk_rect(0.f, 0.f, (float) width, (float) height); + + glClear(GL_COLOR_BUFFER_BIT); + nk_glfw3_new_frame(); + if (nk_begin(nk, "", area, 0)) + { + float opacity = glfwGetWindowOpacity(window); + nk_layout_row_dynamic(nk, 30, 2); + if (nk_slider_float(nk, 0.f, &opacity, 1.f, 0.001f)) + glfwSetWindowOpacity(window, opacity); + nk_labelf(nk, NK_TEXT_LEFT, "%0.3f", opacity); + } + + nk_end(nk); + nk_glfw3_render(NK_ANTI_ALIASING_ON); + + glfwSwapBuffers(window); + glfwWaitEventsTimeout(1.0); + } + + nk_glfw3_shutdown(); + glfwTerminate(); + exit(EXIT_SUCCESS); +} +