diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 2c0a3c272..f835854db 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -3219,6 +3219,29 @@ GLFWAPI void glfwFocusWindow(GLFWwindow* window); */ GLFWAPI void glfwRequestWindowAttention(GLFWwindow* window); +/*! @brief Sounds an audible bell associated with the window + * + * This function sounds an audible bell, on platforms where it is + * supported. Currently (macOS, Windows, X11 and Wayland). + * + * @param[in] window The window with which the bell is associated. + * @return GLFW_TRUE if the bell succeeded otherwise GLFW_FALSE + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref + * GLFW_PLATFORM_ERROR. + * + * @remark @macos Bell is associated to the application as a whole, not the + * specific window. + * + * @thread_safety This function must only be called from the main thread. + * + * @since Added in version 3.3. + * + * @ingroup window + */ +GLFWAPI int glfwWindowBell(GLFWwindow* window); + + /*! @brief Returns the monitor that the window uses for full screen mode. * * This function returns the handle of the monitor that the specified window is @@ -5552,4 +5575,3 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window #endif #endif /* _glfw3_h_ */ - diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 9c018eb8b..3f34b4855 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -1384,6 +1384,12 @@ void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) [NSApp requestUserAttention:NSInformationalRequest]; } +int _glfwPlatformWindowBell(_GLFWwindow* window) +{ + NSBeep(); + return GLFW_TRUE; +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { // Make us the active application @@ -1905,4 +1911,3 @@ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle) _GLFW_REQUIRE_INIT_OR_RETURN(nil); return window->ns.object; } - diff --git a/src/internal.h b/src/internal.h index 7be2b267c..86a150abf 100644 --- a/src/internal.h +++ b/src/internal.h @@ -651,6 +651,7 @@ void _glfwPlatformMaximizeWindow(_GLFWwindow* window); void _glfwPlatformShowWindow(_GLFWwindow* window); void _glfwPlatformHideWindow(_GLFWwindow* window); void _glfwPlatformRequestWindowAttention(_GLFWwindow* window); +int _glfwPlatformWindowBell(_GLFWwindow* window); void _glfwPlatformFocusWindow(_GLFWwindow* window); void _glfwPlatformSetWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, @@ -766,4 +767,3 @@ void _glfwTerminateVulkan(void); const char* _glfwGetVulkanResultString(VkResult result); char* _glfw_strdup(const char* source); - diff --git a/src/null_window.c b/src/null_window.c index 6a54cfe56..0e380c58d 100644 --- a/src/null_window.c +++ b/src/null_window.c @@ -205,6 +205,11 @@ void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) { } +int _glfwPlatformWindowBell(_GLFWwindow* window) +{ + return GLFW_FALSE; +} + void _glfwPlatformUnhideWindow(_GLFWwindow* window) { } @@ -318,4 +323,3 @@ VkResult _glfwPlatformCreateWindowSurface(VkInstance instance, // This seems like the most appropriate error to return here return VK_ERROR_INITIALIZATION_FAILED; } - diff --git a/src/win32_window.c b/src/win32_window.c index 796ae150e..6b7497683 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -1638,6 +1638,11 @@ void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) FlashWindow(window->win32.handle, TRUE); } +int _glfwPlatformWindowBell(_GLFWwindow* window) +{ + return MessageBeep(0xFFFFFFFF) ? GLFW_TRUE : GLFW_FALSE; +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { BringWindowToTop(window->win32.handle); @@ -2191,4 +2196,3 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return window->win32.handle; } - diff --git a/src/window.c b/src/window.c index 4e365cb47..6344d7a46 100644 --- a/src/window.c +++ b/src/window.c @@ -778,6 +778,16 @@ GLFWAPI void glfwRequestWindowAttention(GLFWwindow* handle) _glfwPlatformRequestWindowAttention(window); } +GLFWAPI int glfwWindowBell(GLFWwindow* handle) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); + + return _glfwPlatformWindowBell(window); +} + GLFWAPI void glfwHideWindow(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle; @@ -1110,4 +1120,3 @@ GLFWAPI void glfwPostEmptyEvent(void) _glfwPlatformPostEmptyEvent(); } - diff --git a/src/wl_window.c b/src/wl_window.c index 98a646590..171f8e177 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1209,6 +1209,18 @@ void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) "Wayland: Window attention request not implemented yet"); } +int _glfwPlatformWindowBell(_GLFWwindow* window) +{ + // TODO: Use an actual Wayland API to implement this when one becomes available + int fd = open("/dev/tty", O_WRONLY | O_CLOEXEC); + if (fd > -1) { + int ret = write(fd, "\x07", 1) == 1 ? GLFW_TRUE : GLFW_FALSE; + close(fd); + return ret; + } + return GLFW_FALSE; +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -1854,4 +1866,3 @@ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* handle) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return window->wl.surface; } - diff --git a/src/x11_window.c b/src/x11_window.c index 5e9161072..c07f8a0cb 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2374,6 +2374,11 @@ void _glfwPlatformRequestWindowAttention(_GLFWwindow* window) 0, 1, 0); } +int _glfwPlatformWindowBell(_GLFWwindow* window) +{ + return XkbBell(_glfw.x11.display, window->x11.handle, 100, (Atom)0) ? GLFW_TRUE : GLFW_FALSE; +} + void _glfwPlatformFocusWindow(_GLFWwindow* window) { if (_glfw.x11.NET_ACTIVE_WINDOW) @@ -3059,4 +3064,3 @@ GLFWAPI const char* glfwGetX11SelectionString(void) _GLFW_REQUIRE_INIT_OR_RETURN(NULL); return getSelectionString(_glfw.x11.PRIMARY); } -