Compare commits

...

9 Commits

Author SHA1 Message Date
kunitoki
c77e6c0412
Merge 09efa97ef5 into 161fb1b6f6 2025-08-14 12:34:23 +02:00
Camilla Löwy
161fb1b6f6 Wayland: Fix fallback decoration scroll events
The fallback decorations would emit scroll events as if scrolling had
occurred over the content area of the window.
2025-08-12 17:11:27 +02:00
Camilla Löwy
645a35a38e Wayland: Cleanup 2025-08-12 17:11:27 +02:00
Camilla Löwy
7523b0e6bd Wayland: Move fallback decoration pointer logic
Decluttered the wl_pointer handlers by moving the bulk of fallback
decoration related logic to separate functions.
2025-08-12 17:11:26 +02:00
Camilla Löwy
5190a30d8a Wayland: Move fallback decoration struct member
The cursorPreviousName member was only used for the fallback decorations
but was not grouped with other related members.
2025-08-12 17:11:26 +02:00
Camilla Löwy
ddbb8e0f2c Wayland: Fix fallback decoration cursor position
If fallback decorations were in use, pointer motion over a decoration
surface would cause glfwGetCursorPos to provide incorrect cursor
positions.

The cursor position is now only updated when the pointer is over the
content area of the window, similar to libdecor and XDG decorations.
2025-08-12 17:11:24 +02:00
Camilla Löwy
5245180c56 Formatting 2025-08-12 17:10:43 +02:00
Lucio Asnaghi
09efa97ef5 Returns the audio_app without a window 2024-12-04 01:48:11 +01:00
Lucio Asnaghi
de06756d4d Restore android support, rebase to 3.5 2024-12-03 17:07:08 +01:00
18 changed files with 1370 additions and 196 deletions

View File

@ -24,10 +24,11 @@ if (DEFINED GLFW_USE_WAYLAND AND UNIX AND NOT APPLE)
"GLFW_USE_WAYLAND has been removed; delete the CMake cache and set GLFW_BUILD_WAYLAND and GLFW_BUILD_X11 instead")
endif()
cmake_dependent_option(GLFW_BUILD_WIN32 "Build support for Win32" ON "WIN32" OFF)
cmake_dependent_option(GLFW_BUILD_COCOA "Build support for Cocoa" ON "APPLE" OFF)
cmake_dependent_option(GLFW_BUILD_X11 "Build support for X11" ON "UNIX;NOT APPLE" OFF)
cmake_dependent_option(GLFW_BUILD_WAYLAND "Build support for Wayland" ON "UNIX;NOT APPLE" OFF)
cmake_dependent_option(GLFW_BUILD_WIN32 "Build support for Win32" ON "WIN32;NOT ANDROID" OFF)
cmake_dependent_option(GLFW_BUILD_COCOA "Build support for Cocoa" ON "APPLE;NOT ANDROID" OFF)
cmake_dependent_option(GLFW_BUILD_X11 "Build support for X11" ON "UNIX;NOT APPLE;NOT ANDROID" OFF)
cmake_dependent_option(GLFW_BUILD_WAYLAND "Build support for Wayland" ON "UNIX;NOT APPLE;NOT ANDROID" OFF)
cmake_dependent_option(GLFW_BUILD_ANDROID "Build support for Android" ON "ANDROID" OFF)
cmake_dependent_option(GLFW_USE_HYBRID_HPG "Force use of high-performance GPU on hybrid systems" OFF
"WIN32" OFF)
@ -66,6 +67,9 @@ endif()
if (GLFW_BUILD_X11)
message(STATUS "Including X11 support")
endif()
if (GLFW_BUILD_ANDROID)
message(STATUS "Including Android support")
endif()
#--------------------------------------------------------------------
# Apply Microsoft C runtime library option

View File

@ -135,6 +135,9 @@ information on what to include when reporting a bug.
- [Wayland] Bugfix: Reset key repeat timer when window destroyed (#2741,#2727)
- [Wayland] Bugfix: Memory would leak if reading a data offer failed midway
- [Wayland] Bugfix: Keyboard leave event handler now processes key repeats (#2736)
- [Wayland] Bugfix: Retrieved cursor position would be incorrect when hovering over
fallback decorations
- [Wayland] Bugfix: Fallback decorations would report scroll events
- [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631)
- [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface`
- [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless`

View File

@ -1341,7 +1341,8 @@ extern "C" {
#define GLFW_PLATFORM_COCOA 0x00060002
#define GLFW_PLATFORM_WAYLAND 0x00060003
#define GLFW_PLATFORM_X11 0x00060004
#define GLFW_PLATFORM_NULL 0x00060005
#define GLFW_PLATFORM_ANDROID 0x00060005
#define GLFW_PLATFORM_NULL 0x00060006
/*! @} */
#define GLFW_DONT_CARE -1

View File

@ -155,6 +155,10 @@ extern "C" {
#include <GL/osmesa.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_ANDROID)
#include <android_native_app_glue.h>
#endif
#endif /*GLFW_NATIVE_INCLUDE_NONE*/
@ -655,6 +659,24 @@ GLFWAPI int glfwGetOSMesaDepthBuffer(GLFWwindow* window, int* width, int* height
GLFWAPI OSMesaContext glfwGetOSMesaContext(GLFWwindow* window);
#endif
#if defined(GLFW_EXPOSE_NATIVE_ANDROID)
/*! @brief Returns the `struct android_app` of the current application.
*
* @return The `struct android_app` of the current, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*
* @since Added in version 3.5.
*
* @ingroup native
*/
GLFWAPI struct android_app* glfwGetAndroidApp(void);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -57,6 +57,14 @@ if (GLFW_BUILD_WAYLAND)
wl_monitor.c wl_window.c)
endif()
if (GLFW_BUILD_ANDROID)
target_compile_definitions(glfw PRIVATE _GLFW_ANDROID)
target_include_directories(glfw PRIVATE "${ANDROID_NDK}/sources/android/native_app_glue")
target_sources(glfw PRIVATE android_platform.h android_joystick.h android_init.c
android_monitor.c android_window.c android_joystick.c
"${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c")
endif()
if (GLFW_BUILD_X11 OR GLFW_BUILD_WAYLAND)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_sources(glfw PRIVATE linux_joystick.h linux_joystick.c)

203
src/android_init.c Normal file
View File

@ -0,0 +1,203 @@
//========================================================================
// GLFW 3.5 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 kunitoki <kunitoki@gmail.com>
// Copyright (c) 2017 Curi0 <curi0minecraft@gmail.com>
//
// 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 <android_native_app_glue.h>
#include <android/native_window.h>
#include <android/log.h>
#include "internal.h"
struct android_app* _globalAndroidApp = NULL;
extern int main();
void handleAppCmd(struct android_app* app, int32_t cmd)
{
switch (cmd)
{
case APP_CMD_START:
break;
case APP_CMD_RESUME:
//_glfwInputWindowIconify(_glfw.windowListHead, GLFW_FALSE);
break;
case APP_CMD_PAUSE:
//_glfwInputWindowIconify(_glfw.windowListHead, GLFW_TRUE);
break;
case APP_CMD_STOP:
break;
case APP_CMD_DESTROY:
break;
case APP_CMD_INIT_WINDOW:
break;
case APP_CMD_TERM_WINDOW:
//_glfwInputWindowCloseRequest(_glfw.windowListHead);
break;
case APP_CMD_LOST_FOCUS:
//_glfwInputWindowFocus(_glfw.windowListHead, GLFW_FALSE);
break;
case APP_CMD_GAINED_FOCUS:
//_glfwInputWindowFocus(_glfw.windowListHead, GLFW_TRUE);
break;
case APP_CMD_WINDOW_RESIZED:
_glfwInputWindowSize(_glfw.windowListHead, ANativeWindow_getWidth(app->window), ANativeWindow_getHeight(app->window));
break;
case APP_CMD_WINDOW_REDRAW_NEEDED:
_glfwInputWindowDamage(_glfw.windowListHead);
break;
case APP_CMD_CONTENT_RECT_CHANGED:
_glfwInputFramebufferSize(_glfw.windowListHead, ANativeWindow_getWidth(app->window), ANativeWindow_getHeight(app->window));
break;
case APP_CMD_CONFIG_CHANGED:
break;
case APP_CMD_INPUT_CHANGED:
break;
}
}
// Android Entry Point
void android_main(struct android_app* app)
{
app_dummy();
app->onAppCmd = handleAppCmd;
_globalAndroidApp = app;
main();
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwConnectAndroid(int platformID, _GLFWplatform* platform)
{
const _GLFWplatform android =
{
.platformID = GLFW_PLATFORM_ANDROID,
.init = _glfwInitAndroid,
.terminate = _glfwTerminateAndroid,
.getCursorPos = _glfwGetCursorPosAndroid,
.setCursorPos = _glfwSetCursorPosAndroid,
.setCursorMode = _glfwSetCursorModeAndroid,
.setRawMouseMotion = _glfwSetRawMouseMotionAndroid,
.rawMouseMotionSupported = _glfwRawMouseMotionSupportedAndroid,
.createCursor = _glfwCreateCursorAndroid,
.createStandardCursor = _glfwCreateStandardCursorAndroid,
.destroyCursor = _glfwDestroyCursorAndroid,
.setCursor = _glfwSetCursorAndroid,
.getScancodeName = _glfwGetScancodeNameAndroid,
.getKeyScancode = _glfwGetKeyScancodeAndroid,
.setClipboardString = _glfwSetClipboardStringAndroid,
.getClipboardString = _glfwGetClipboardStringAndroid,
.initJoysticks = _glfwInitJoysticksAndroid,
.terminateJoysticks = _glfwTerminateJoysticksAndroid,
.pollJoystick = _glfwPollJoystickAndroid,
.getMappingName = _glfwGetMappingNameAndroid,
.updateGamepadGUID = _glfwUpdateGamepadGUIDAndroid,
.freeMonitor = _glfwFreeMonitorAndroid,
.getMonitorPos = _glfwGetMonitorPosAndroid,
.getMonitorContentScale = _glfwGetMonitorContentScaleAndroid,
.getMonitorWorkarea = _glfwGetMonitorWorkareaAndroid,
.getVideoModes = _glfwGetVideoModesAndroid,
.getVideoMode = _glfwGetVideoModeAndroid,
.getGammaRamp = _glfwGetGammaRampAndroid,
.setGammaRamp = _glfwSetGammaRampAndroid,
.createWindow = _glfwCreateWindowAndroid,
.destroyWindow = _glfwDestroyWindowAndroid,
.setWindowTitle = _glfwSetWindowTitleAndroid,
.setWindowIcon = _glfwSetWindowIconAndroid,
.getWindowPos = _glfwGetWindowPosAndroid,
.setWindowPos = _glfwSetWindowPosAndroid,
.getWindowSize = _glfwGetWindowSizeAndroid,
.setWindowSize = _glfwSetWindowSizeAndroid,
.setWindowSizeLimits = _glfwSetWindowSizeLimitsAndroid,
.setWindowAspectRatio = _glfwSetWindowAspectRatioAndroid,
.getFramebufferSize = _glfwGetFramebufferSizeAndroid,
.getWindowFrameSize = _glfwGetWindowFrameSizeAndroid,
.getWindowContentScale = _glfwGetWindowContentScaleAndroid,
.iconifyWindow = _glfwIconifyWindowAndroid,
.restoreWindow = _glfwRestoreWindowAndroid,
.maximizeWindow = _glfwMaximizeWindowAndroid,
.showWindow = _glfwShowWindowAndroid,
.hideWindow = _glfwHideWindowAndroid,
.requestWindowAttention = _glfwRequestWindowAttentionAndroid,
.focusWindow = _glfwFocusWindowAndroid,
.setWindowMonitor = _glfwSetWindowMonitorAndroid,
.windowFocused = _glfwWindowFocusedAndroid,
.windowIconified = _glfwWindowIconifiedAndroid,
.windowVisible = _glfwWindowVisibleAndroid,
.windowMaximized = _glfwWindowMaximizedAndroid,
.windowHovered = _glfwWindowHoveredAndroid,
.framebufferTransparent = _glfwFramebufferTransparentAndroid,
.getWindowOpacity = _glfwGetWindowOpacityAndroid,
.setWindowResizable = _glfwSetWindowResizableAndroid,
.setWindowDecorated = _glfwSetWindowDecoratedAndroid,
.setWindowFloating = _glfwSetWindowFloatingAndroid,
.setWindowOpacity = _glfwSetWindowOpacityAndroid,
.setWindowMousePassthrough = _glfwSetWindowMousePassthroughAndroid,
.pollEvents = _glfwPollEventsAndroid,
.waitEvents = _glfwWaitEventsAndroid,
.waitEventsTimeout = _glfwWaitEventsTimeoutAndroid,
.postEmptyEvent = _glfwPostEmptyEventAndroid,
.getEGLPlatform = _glfwGetEGLPlatformAndroid,
.getEGLNativeDisplay = _glfwGetEGLNativeDisplayAndroid,
.getEGLNativeWindow = _glfwGetEGLNativeWindowAndroid,
.getRequiredInstanceExtensions = _glfwGetRequiredInstanceExtensionsAndroid,
.getPhysicalDevicePresentationSupport = _glfwGetPhysicalDevicePresentationSupportAndroid,
.createWindowSurface = _glfwCreateWindowSurfaceAndroid
};
*platform = android;
return GLFW_TRUE;
}
int _glfwInitAndroid(void)
{
_glfw.gstate.app = _globalAndroidApp;
_glfw.gstate.source = NULL;
return GLFW_TRUE;
}
void _glfwTerminateAndroid(void)
{
_glfw.gstate.app = NULL;
}

56
src/android_joystick.c Normal file
View File

@ -0,0 +1,56 @@
//========================================================================
// GLFW 3.5 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 kunitoki <kunitoki@gmail.com>
// Copyright (c) 2017 Curi0 <curi0minecraft@gmail.com>
//
// 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 "internal.h"
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwInitJoysticksAndroid(void)
{
return GLFW_FALSE;
}
void _glfwTerminateJoysticksAndroid(void)
{
}
GLFWbool _glfwPollJoystickAndroid(_GLFWjoystick* js, int mode)
{
return GLFW_FALSE;
}
const char* _glfwGetMappingNameAndroid(void)
{
return "Android";
}
void _glfwUpdateGamepadGUIDAndroid(char* guid)
{
}

35
src/android_joystick.h Normal file
View File

@ -0,0 +1,35 @@
//========================================================================
// GLFW 3.5 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 kunitoki <kunitoki@gmail.com>
// Copyright (c) 2017 Curi0 <curi0minecraft@gmail.com>
//
// 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.
//
//========================================================================
#define GLFW_ANDROID_JOYSTICK_STATE
#define GLFW_ANDROID_LIBRARY_JOYSTICK_STATE
GLFWbool _glfwInitJoysticksAndroid(void);
void _glfwTerminateJoysticksAndroid(void);
GLFWbool _glfwPollJoystickAndroid(_GLFWjoystick* js, int mode);
const char* _glfwGetMappingNameAndroid(void);
void _glfwUpdateGamepadGUIDAndroid(char* guid);

82
src/android_monitor.c Normal file
View File

@ -0,0 +1,82 @@
//========================================================================
// GLFW 3.5 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 kunitoki <kunitoki@gmail.com>
// Copyright (c) 2017 Curi0 <curi0minecraft@gmail.com>
//
// 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 "internal.h"
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
void _glfwPollMonitorsAndroid(void)
{
}
void _glfwSetVideoModeAndroid(_GLFWmonitor* monitor, const GLFWvidmode* desired)
{
}
void _glfwRestoreVideoModeAndroid(_GLFWmonitor* monitor)
{
}
void _glfwFreeMonitorAndroid(_GLFWmonitor* monitor)
{
}
void _glfwGetMonitorPosAndroid(_GLFWmonitor* monitor, int* xpos, int* ypos)
{
}
void _glfwGetMonitorContentScaleAndroid(_GLFWmonitor* monitor,
float* xscale, float* yscale)
{
}
void _glfwGetMonitorWorkareaAndroid(_GLFWmonitor* monitor,
int* xpos, int* ypos,
int* width, int* height)
{
}
GLFWvidmode* _glfwGetVideoModesAndroid(_GLFWmonitor* monitor, int* count)
{
return NULL;
}
GLFWbool _glfwGetVideoModeAndroid(_GLFWmonitor* monitor, GLFWvidmode *mode)
{
return GLFW_FALSE;
}
GLFWbool _glfwGetGammaRampAndroid(_GLFWmonitor* monitor, GLFWgammaramp* ramp)
{
return GLFW_FALSE;
}
void _glfwSetGammaRampAndroid(_GLFWmonitor* monitor, const GLFWgammaramp* ramp)
{
}

134
src/android_platform.h Normal file
View File

@ -0,0 +1,134 @@
//========================================================================
// GLFW 3.5 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 kunitoki <kunitoki@gmail.com>
// Copyright (c) 2017 Curi0 <curi0minecraft@gmail.com>
//
// 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 <android_native_app_glue.h>
#include <android/native_window.h>
#include <android/log.h>
#define GLFW_ANDROID_WINDOW_STATE struct android_app* android;
#define GLFW_ANDROID_LIBRARY_WINDOW_STATE android_gstate gstate;
#define GLFW_ANDROID_MONITOR_STATE
#define GLFW_ANDROID_CONTEXT_STATE
#define GLFW_ANDROID_CURSOR_STATE
#define GLFW_ANDROID_LIBRARY_CONTEXT_STATE
#define GLFW_ANDROID_JOYSTICK_STATE
#define GLFW_ANDROID_LIBRARY_JOYSTICK_STATE
typedef struct android_gstate
{
struct android_app* app;
struct android_poll_source* source;
} android_gstate;
typedef VkFlags VkAndroidSurfaceCreateFlagsKHR;
typedef struct VkAndroidSurfaceCreateInfoKHR
{
VkStructureType sType;
const void* pNext;
VkAndroidSurfaceCreateFlagsKHR flags;
ANativeWindow* window;
} VkAndroidSurfaceCreateInfoKHR;
typedef VkResult (APIENTRY *PFN_vkCreateAndroidSurfaceKHR)(VkInstance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*);
GLFWbool _glfwConnectAndroid(int platformID, _GLFWplatform* platform);
int _glfwInitAndroid(void);
void _glfwTerminateAndroid(void);
void _glfwFreeMonitorAndroid(_GLFWmonitor* monitor);
void _glfwGetMonitorPosAndroid(_GLFWmonitor* monitor, int* xpos, int* ypos);
void _glfwGetMonitorContentScaleAndroid(_GLFWmonitor* monitor, float* xscale, float* yscale);
void _glfwGetMonitorWorkareaAndroid(_GLFWmonitor* monitor, int* xpos, int* ypos, int* width, int* height);
GLFWvidmode* _glfwGetVideoModesAndroid(_GLFWmonitor* monitor, int* found);
GLFWbool _glfwGetVideoModeAndroid(_GLFWmonitor* monitor, GLFWvidmode* mode);
GLFWbool _glfwGetGammaRampAndroid(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
void _glfwSetGammaRampAndroid(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
void _glfwPollMonitorsAndroid(void);
GLFWbool _glfwCreateWindowAndroid(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
void _glfwDestroyWindowAndroid(_GLFWwindow* window);
void _glfwSetWindowTitleAndroid(_GLFWwindow* window, const char* title);
void _glfwSetWindowIconAndroid(_GLFWwindow* window, int count, const GLFWimage* images);
void _glfwSetWindowMonitorAndroid(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate);
void _glfwGetWindowPosAndroid(_GLFWwindow* window, int* xpos, int* ypos);
void _glfwSetWindowPosAndroid(_GLFWwindow* window, int xpos, int ypos);
void _glfwGetWindowSizeAndroid(_GLFWwindow* window, int* width, int* height);
void _glfwSetWindowSizeAndroid(_GLFWwindow* window, int width, int height);
void _glfwSetWindowSizeLimitsAndroid(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight);
void _glfwSetWindowAspectRatioAndroid(_GLFWwindow* window, int n, int d);
void _glfwGetFramebufferSizeAndroid(_GLFWwindow* window, int* width, int* height);
void _glfwGetWindowFrameSizeAndroid(_GLFWwindow* window, int* left, int* top, int* right, int* bottom);
void _glfwGetWindowContentScaleAndroid(_GLFWwindow* window, float* xscale, float* yscale);
void _glfwIconifyWindowAndroid(_GLFWwindow* window);
void _glfwRestoreWindowAndroid(_GLFWwindow* window);
void _glfwMaximizeWindowAndroid(_GLFWwindow* window);
GLFWbool _glfwWindowMaximizedAndroid(_GLFWwindow* window);
GLFWbool _glfwWindowHoveredAndroid(_GLFWwindow* window);
GLFWbool _glfwFramebufferTransparentAndroid(_GLFWwindow* window);
void _glfwSetWindowResizableAndroid(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowDecoratedAndroid(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowFloatingAndroid(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowMousePassthroughAndroid(_GLFWwindow* window, GLFWbool enabled);
float _glfwGetWindowOpacityAndroid(_GLFWwindow* window);
void _glfwSetWindowOpacityAndroid(_GLFWwindow* window, float opacity);
void _glfwSetRawMouseMotionAndroid(_GLFWwindow *window, GLFWbool enabled);
GLFWbool _glfwRawMouseMotionSupportedAndroid(void);
void _glfwShowWindowAndroid(_GLFWwindow* window);
void _glfwRequestWindowAttentionAndroid(_GLFWwindow* window);
void _glfwHideWindowAndroid(_GLFWwindow* window);
void _glfwFocusWindowAndroid(_GLFWwindow* window);
GLFWbool _glfwWindowFocusedAndroid(_GLFWwindow* window);
GLFWbool _glfwWindowIconifiedAndroid(_GLFWwindow* window);
GLFWbool _glfwWindowVisibleAndroid(_GLFWwindow* window);
void _glfwPollEventsAndroid(void);
void _glfwWaitEventsAndroid(void);
void _glfwWaitEventsTimeoutAndroid(double timeout);
void _glfwPostEmptyEventAndroid(void);
void _glfwGetCursorPosAndroid(_GLFWwindow* window, double* xpos, double* ypos);
void _glfwSetCursorPosAndroid(_GLFWwindow* window, double x, double y);
void _glfwSetCursorModeAndroid(_GLFWwindow* window, int mode);
GLFWbool _glfwCreateCursorAndroid(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
GLFWbool _glfwCreateStandardCursorAndroid(_GLFWcursor* cursor, int shape);
void _glfwDestroyCursorAndroid(_GLFWcursor* cursor);
void _glfwSetCursorAndroid(_GLFWwindow* window, _GLFWcursor* cursor);
void _glfwSetClipboardStringAndroid(const char* string);
const char* _glfwGetClipboardStringAndroid(void);
const char* _glfwGetScancodeNameAndroid(int scancode);
int _glfwGetKeyScancodeAndroid(int key);
EGLenum _glfwGetEGLPlatformAndroid(EGLint** attribs);
EGLNativeDisplayType _glfwGetEGLNativeDisplayAndroid(void);
EGLNativeWindowType _glfwGetEGLNativeWindowAndroid(_GLFWwindow* window);
void _glfwGetRequiredInstanceExtensionsAndroid(char** extensions);
GLFWbool _glfwGetPhysicalDevicePresentationSupportAndroid(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
VkResult _glfwCreateWindowSurfaceAndroid(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
GLFWAPI struct android_app* glfwGetAndroidApp(void);

562
src/android_window.c Normal file
View File

@ -0,0 +1,562 @@
//========================================================================
// GLFW 3.5 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2024 kunitoki <kunitoki@gmail.com>
// Copyright (c) 2017 Curi0 <curi0minecraft@gmail.com>
//
// 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 "internal.h"
#include <jni.h>
#include <android/log.h>
#include <android/native_activity.h>
#include <android/configuration.h>
#include <android/window.h>
#include <android/input.h>
#include <string.h>
static float lastCursorPosX = 0.0f;
static float lastCursorPosY = 0.0f;
static void moveNativeWindowToBackground(ANativeActivity* nativeActivity)
{
JNIEnv* env = NULL;
(*nativeActivity->vm)->AttachCurrentThread(nativeActivity->vm, &env, NULL);
jmethodID moveTaskToBackMethod = (*env)->GetMethodID(env, nativeActivity->clazz, "moveTaskToBack", "(Z)Z");
if (moveTaskToBackMethod == NULL)
return;
(*env)->CallBooleanMethod(env, nativeActivity->clazz, moveTaskToBackMethod, JNI_TRUE);
}
static int32_t handleInput(struct android_app* app, AInputEvent* event)
{
if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION)
{
size_t pointerCount = AMotionEvent_getPointerCount(event);
for (size_t i = 0; i < pointerCount; ++i)
{
lastCursorPosX = AMotionEvent_getX(event, i);
lastCursorPosY = AMotionEvent_getY(event, i);
int32_t action = AMotionEvent_getAction(event) & AMOTION_EVENT_ACTION_MASK;
// Map Android touch events to GLFW touch events
switch (action)
{
case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_POINTER_DOWN:
_glfwInputMouseClick(_glfw.windowListHead, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, 0);
break;
case AMOTION_EVENT_ACTION_UP:
case AMOTION_EVENT_ACTION_POINTER_UP:
_glfwInputMouseClick(_glfw.windowListHead, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, 0);
break;
case AMOTION_EVENT_ACTION_MOVE:
_glfwInputCursorPos(_glfw.windowListHead, lastCursorPosX, lastCursorPosY);
break;
case AMOTION_EVENT_ACTION_CANCEL:
// Handle cancel if necessary
break;
}
}
return 1;
}
else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY)
{
_glfwInputKey(_glfw.windowListHead, 0 , AKeyEvent_getKeyCode(event), GLFW_PRESS, 0);
return 1;
}
return 0;
}
static void handleEvents(int timeout)
{
ALooper_pollOnce(timeout, NULL, NULL, (void**)&_glfw.gstate.source);
if (_glfw.gstate.source != NULL)
_glfw.gstate.source->process(_glfw.gstate.app, _glfw.gstate.source);
}
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwCreateWindowAndroid(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
// wait for window to become ready
while (_glfw.gstate.app->window == NULL)
handleEvents(-1);
// hmmm maybe should be ANative_Window only?
window->android = _glfw.gstate.app;
window->android->onInputEvent = handleInput;
if (ctxconfig->client != GLFW_NO_API)
{
if ((ctxconfig->source == GLFW_NATIVE_CONTEXT_API) |
(ctxconfig->source == GLFW_EGL_CONTEXT_API))
{
if (!_glfwInitEGL())
return GLFW_FALSE;
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
else if (ctxconfig->source == GLFW_OSMESA_CONTEXT_API)
{
if (!_glfwInitOSMesa())
return GLFW_FALSE;
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
if (!_glfwRefreshContextAttribs(window, ctxconfig))
return GLFW_FALSE;
}
return GLFW_TRUE;
}
void _glfwDestroyWindowAndroid(_GLFWwindow* window)
{
if (window->context.destroy)
window->context.destroy(window);
ANativeActivity_finish(window->android->activity);
}
void _glfwSetWindowTitleAndroid(_GLFWwindow* window, const char* title)
{
}
void _glfwSetWindowIconAndroid(_GLFWwindow* window, int count,
const GLFWimage* images)
{
}
void _glfwSetWindowMonitorAndroid(_GLFWwindow* window,
_GLFWmonitor* monitor,
int xpos, int ypos,
int width, int height,
int refreshRate)
{
}
void _glfwGetWindowPosAndroid(_GLFWwindow* window, int* xpos, int* ypos)
{
if (xpos)
*xpos = 0;
if (ypos)
*ypos = 0;
}
void _glfwSetWindowPosAndroid(_GLFWwindow* window, int xpos, int ypos)
{
}
void _glfwGetWindowSizeAndroid(_GLFWwindow* window, int* width, int* height)
{
if (width)
{
*width = (window->android->window != NULL)
? ANativeWindow_getWidth(window->android->window)
: 0;
}
if (height)
{
*height = (window->android->window != NULL)
? ANativeWindow_getHeight(window->android->window)
: 0;
}
}
void _glfwSetWindowSizeAndroid(_GLFWwindow* window, int width, int height)
{
}
void _glfwSetWindowSizeLimitsAndroid(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight)
{
}
void _glfwSetWindowAspectRatioAndroid(_GLFWwindow* window, int n, int d)
{
}
void _glfwGetFramebufferSizeAndroid(_GLFWwindow* window, int* width, int* height)
{
// the underlying buffer geometry is currently being initialized from the window width and height...
// so high resolution displays are currently not supported...so it is safe to just call _glfwGetWindowSizeAndroid() for now
_glfwGetWindowSizeAndroid(window, width, height);
}
void _glfwGetWindowFrameSizeAndroid(_GLFWwindow* window,
int* left, int* top,
int* right, int* bottom)
{
if (left)
*left = window->android->contentRect.left;
if (top)
*top = window->android->contentRect.top;
if (right)
{
int windowWidth = (window->android->window != NULL)
? ANativeWindow_getWidth(window->android->window)
: 0;
int rightFrame = windowWidth - window->android->contentRect.right;
if (rightFrame < 0) rightFrame = 0;
*right = rightFrame;
}
if (bottom)
{
int windowHeight = (window->android->window != NULL)
? ANativeWindow_getHeight(window->android->window)
: 0;
int bottomFrame = windowHeight - window->android->contentRect.bottom;
if (bottomFrame < 0) bottomFrame = 0;
*bottom = bottomFrame;
}
}
void _glfwGetWindowContentScaleAndroid(_GLFWwindow* window, float* xscale, float* yscale)
{
if (xscale)
{
int32_t widthDensity = AConfiguration_getScreenWidthDp(window->android->config);
if (widthDensity == ACONFIGURATION_SCREEN_WIDTH_DP_ANY)
{
*xscale = 1.0f;
}
else
{
int32_t widthPixels = ANativeWindow_getWidth(window->android->window);
*xscale = (float)widthPixels / (float)widthDensity;
}
}
if (yscale)
{
int32_t heightDensity = AConfiguration_getScreenHeightDp(window->android->config);
if (heightDensity == ACONFIGURATION_SCREEN_HEIGHT_DP_ANY)
{
*yscale = 1.0f;
}
else
{
int32_t heightPixels = ANativeWindow_getHeight(window->android->window);
*yscale = (float)heightPixels / (float)heightDensity;
}
}
}
void _glfwIconifyWindowAndroid(_GLFWwindow* window)
{
moveNativeWindowToBackground(window->android->activity);
}
void _glfwRestoreWindowAndroid(_GLFWwindow* window)
{
}
void _glfwMaximizeWindowAndroid(_GLFWwindow* window)
{
}
GLFWbool _glfwWindowMaximizedAndroid(_GLFWwindow* window)
{
return GLFW_TRUE;
}
GLFWbool _glfwWindowHoveredAndroid(_GLFWwindow* window)
{
return GLFW_FALSE;
}
GLFWbool _glfwFramebufferTransparentAndroid(_GLFWwindow* window)
{
return GLFW_FALSE;
}
void _glfwSetWindowResizableAndroid(_GLFWwindow* window, GLFWbool enabled)
{
}
void _glfwSetWindowDecoratedAndroid(_GLFWwindow* window, GLFWbool enabled)
{
}
void _glfwSetWindowFloatingAndroid(_GLFWwindow* window, GLFWbool enabled)
{
}
void _glfwSetWindowMousePassthroughAndroid(_GLFWwindow* window, GLFWbool enabled)
{
}
float _glfwGetWindowOpacityAndroid(_GLFWwindow* window)
{
return 1.0f;
}
void _glfwSetWindowOpacityAndroid(_GLFWwindow* window, float opacity)
{
}
void _glfwSetRawMouseMotionAndroid(_GLFWwindow *window, GLFWbool enabled)
{
}
GLFWbool _glfwRawMouseMotionSupportedAndroid(void)
{
return GLFW_FALSE;
}
void _glfwShowWindowAndroid(_GLFWwindow* window)
{
}
void _glfwRequestWindowAttentionAndroid(_GLFWwindow* window)
{
}
void _glfwHideWindowAndroid(_GLFWwindow* window)
{
}
void _glfwFocusWindowAndroid(_GLFWwindow* window)
{
}
GLFWbool _glfwWindowFocusedAndroid(_GLFWwindow* window)
{
return GLFW_FALSE;
}
GLFWbool _glfwWindowIconifiedAndroid(_GLFWwindow* window)
{
return GLFW_FALSE;
}
GLFWbool _glfwWindowVisibleAndroid(_GLFWwindow* window)
{
return GLFW_FALSE;
}
void _glfwPollEventsAndroid(void)
{
handleEvents(0);
}
void _glfwWaitEventsAndroid(void)
{
handleEvents(-1);
}
void _glfwWaitEventsTimeoutAndroid(double timeout)
{
handleEvents(timeout * 1e3);
}
void _glfwPostEmptyEventAndroid(void)
{
}
void _glfwGetCursorPosAndroid(_GLFWwindow* window, double* xpos, double* ypos)
{
if (xpos)
*xpos = (double)lastCursorPosX;
if (ypos)
*ypos = (double)lastCursorPosY;
}
void _glfwSetCursorPosAndroid(_GLFWwindow* window, double x, double y)
{
}
void _glfwSetCursorModeAndroid(_GLFWwindow* window, int mode)
{
}
GLFWbool _glfwCreateCursorAndroid(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
{
return GLFW_TRUE;
}
GLFWbool _glfwCreateStandardCursorAndroid(_GLFWcursor* cursor, int shape)
{
return GLFW_TRUE;
}
void _glfwDestroyCursorAndroid(_GLFWcursor* cursor)
{
}
void _glfwSetCursorAndroid(_GLFWwindow* window, _GLFWcursor* cursor)
{
}
void _glfwSetClipboardStringAndroid(const char* string)
{
}
const char* _glfwGetClipboardStringAndroid(void)
{
return NULL;
}
const char* _glfwGetScancodeNameAndroid(int scancode)
{
return "";
}
int _glfwGetKeyScancodeAndroid(int key)
{
return -1;
}
EGLenum _glfwGetEGLPlatformAndroid(EGLint** attribs)
{
if (_glfw.egl.ANGLE_platform_angle)
{
int type = 0;
if (_glfw.egl.ANGLE_platform_angle_opengl)
{
if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGL)
type = EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE;
else if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_OPENGLES)
type = EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE;
}
if (_glfw.egl.ANGLE_platform_angle_vulkan)
{
if (_glfw.hints.init.angleType == GLFW_ANGLE_PLATFORM_TYPE_VULKAN)
type = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
}
if (type)
{
*attribs = _glfw_calloc(3, sizeof(EGLint));
(*attribs)[0] = EGL_PLATFORM_ANGLE_TYPE_ANGLE;
(*attribs)[1] = type;
(*attribs)[2] = EGL_NONE;
return EGL_PLATFORM_ANGLE_ANGLE;
}
}
return 0;
}
EGLNativeDisplayType _glfwGetEGLNativeDisplayAndroid(void)
{
return EGL_DEFAULT_DISPLAY;
}
EGLNativeWindowType _glfwGetEGLNativeWindowAndroid(_GLFWwindow* window)
{
return ((EGLNativeWindowType) window->android->window);
}
void _glfwGetRequiredInstanceExtensionsAndroid(char** extensions)
{
if (!_glfw.vk.KHR_surface || !_glfw.vk.KHR_android_surface)
return;
extensions[0] = "VK_KHR_surface";
extensions[1] = "VK_KHR_android_surface";
}
GLFWbool _glfwGetPhysicalDevicePresentationSupportAndroid(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
return GLFW_TRUE;
}
VkResult _glfwCreateWindowSurfaceAndroid(VkInstance instance,
_GLFWwindow* window,
const VkAllocationCallbacks* allocator,
VkSurfaceKHR* surface)
{
VkResult err;
VkAndroidSurfaceCreateInfoKHR sci;
PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR;
vkCreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR)vkGetInstanceProcAddr(instance, "vkCreateAndroidSurfaceKHR");
if (!vkCreateAndroidSurfaceKHR)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"Android: Vulkan instance missing VK_KHR_android_surface extension");
return VK_ERROR_EXTENSION_NOT_PRESENT;
}
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
sci.window = window->android->window;
err = vkCreateAndroidSurfaceKHR(instance, &sci, allocator, surface);
if (err)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Android: Failed to create Vulkan surface: %s",
_glfwGetVulkanResultString(err));
}
return err;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW native API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI struct android_app* glfwGetAndroidApp(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return _glfw.gstate.app;
}

View File

@ -374,6 +374,8 @@ GLFWbool _glfwInitEGL(void)
"EGL.dll",
#elif defined(_GLFW_COCOA)
"libEGL.dylib",
#elif defined(_GLFW_ANDROID)
"libEGL.so",
#elif defined(__CYGWIN__)
"libEGL-1.so",
#elif defined(__OpenBSD__) || defined(__NetBSD__)
@ -773,6 +775,9 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
"libGLES_CM.dll",
#elif defined(_GLFW_COCOA)
"libGLESv1_CM.dylib",
#elif defined(_GLFW_ANDROID)
"libGLESv1_CM.so",
"libGLES_CM.so",
#elif defined(__OpenBSD__) || defined(__NetBSD__)
"libGLESv1_CM.so",
#else
@ -790,6 +795,8 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
"libGLESv2.dll",
#elif defined(_GLFW_COCOA)
"libGLESv2.dylib",
#elif defined(_GLFW_ANDROID)
"libGLESv2.so",
#elif defined(__CYGWIN__)
"libGLESv2-2.so",
#elif defined(__OpenBSD__) || defined(__NetBSD__)

View File

@ -285,6 +285,7 @@ typedef enum VkStructureType
VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT = 1000217000,
VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000,
VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT = 1000256000,
VK_STRUCTURE_TYPE_MAX_ENUM = 0x7FFFFFFF
} VkStructureType;
@ -872,6 +873,7 @@ struct _GLFWlibrary
GLFWbool KHR_xlib_surface;
GLFWbool KHR_xcb_surface;
GLFWbool KHR_wayland_surface;
GLFWbool KHR_android_surface;
GLFWbool EXT_headless_surface;
} vk;

View File

@ -56,6 +56,9 @@ static const struct
#if defined(_GLFW_X11)
{ GLFW_PLATFORM_X11, _glfwConnectX11 },
#endif
#if defined(_GLFW_ANDROID)
{ GLFW_PLATFORM_ANDROID, _glfwConnectAndroid },
#endif
};
GLFWbool _glfwSelectPlatform(int desiredID, _GLFWplatform* platform)
@ -68,6 +71,7 @@ GLFWbool _glfwSelectPlatform(int desiredID, _GLFWplatform* platform)
desiredID != GLFW_PLATFORM_COCOA &&
desiredID != GLFW_PLATFORM_WAYLAND &&
desiredID != GLFW_PLATFORM_X11 &&
desiredID != GLFW_PLATFORM_ANDROID &&
desiredID != GLFW_PLATFORM_NULL)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid platform ID 0x%08X", desiredID);
@ -147,6 +151,7 @@ GLFWAPI int glfwPlatformSupported(int platformID)
platformID != GLFW_PLATFORM_COCOA &&
platformID != GLFW_PLATFORM_WAYLAND &&
platformID != GLFW_PLATFORM_X11 &&
platformID != GLFW_PLATFORM_ANDROID &&
platformID != GLFW_PLATFORM_NULL)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid platform ID 0x%08X", platformID);
@ -181,6 +186,9 @@ GLFWAPI const char* glfwGetVersionString(void)
#endif
#if defined(_GLFW_X11)
" X11 GLX"
#endif
#if defined(_GLFW_ANDROID)
" Android"
#endif
" Null"
" EGL"
@ -207,4 +215,3 @@ GLFWAPI const char* glfwGetVersionString(void)
#endif
;
}

View File

@ -90,6 +90,18 @@
#define GLFW_GLX_LIBRARY_CONTEXT_STATE
#endif
#if defined(_GLFW_ANDROID)
#include "android_platform.h"
#define GLFW_EXPOSE_NATIVE_EGL
#else
#define GLFW_ANDROID_WINDOW_STATE
#define GLFW_ANDROID_MONITOR_STATE
#define GLFW_ANDROID_CURSOR_STATE
#define GLFW_ANDROID_LIBRARY_WINDOW_STATE
#define GLFW_ANDROID_CONTEXT_STATE
#define GLFW_ANDROID_LIBRARY_CONTEXT_STATE
#endif
#include "null_joystick.h"
#if defined(_GLFW_WIN32)
@ -106,6 +118,13 @@
#define GLFW_COCOA_LIBRARY_JOYSTICK_STATE
#endif
#if defined(_GLFW_ANDROID)
#include "android_joystick.h"
#else
#define GLFW_ANDROID_JOYSTICK_STATE
#define GLFW_ANDROID_LIBRARY_JOYSTICK_STATE
#endif
#if (defined(_GLFW_X11) || defined(_GLFW_WAYLAND)) && defined(__linux__)
#define GLFW_BUILD_LINUX_JOYSTICK
#endif
@ -122,6 +141,7 @@
GLFW_COCOA_WINDOW_STATE \
GLFW_WAYLAND_WINDOW_STATE \
GLFW_X11_WINDOW_STATE \
GLFW_ANDROID_WINDOW_STATE \
GLFW_NULL_WINDOW_STATE \
#define GLFW_PLATFORM_MONITOR_STATE \
@ -129,6 +149,7 @@
GLFW_COCOA_MONITOR_STATE \
GLFW_WAYLAND_MONITOR_STATE \
GLFW_X11_MONITOR_STATE \
GLFW_ANDROID_MONITOR_STATE \
GLFW_NULL_MONITOR_STATE \
#define GLFW_PLATFORM_CURSOR_STATE \
@ -136,11 +157,13 @@
GLFW_COCOA_CURSOR_STATE \
GLFW_WAYLAND_CURSOR_STATE \
GLFW_X11_CURSOR_STATE \
GLFW_ANDROID_CURSOR_STATE \
GLFW_NULL_CURSOR_STATE \
#define GLFW_PLATFORM_JOYSTICK_STATE \
GLFW_WIN32_JOYSTICK_STATE \
GLFW_COCOA_JOYSTICK_STATE \
GLFW_ANDROID_JOYSTICK_STATE \
GLFW_LINUX_JOYSTICK_STATE
#define GLFW_PLATFORM_LIBRARY_WINDOW_STATE \
@ -148,12 +171,14 @@
GLFW_COCOA_LIBRARY_WINDOW_STATE \
GLFW_WAYLAND_LIBRARY_WINDOW_STATE \
GLFW_X11_LIBRARY_WINDOW_STATE \
GLFW_NULL_LIBRARY_WINDOW_STATE \
GLFW_ANDROID_LIBRARY_WINDOW_STATE \
GLFW_NULL_LIBRARY_WINDOW_STATE
#define GLFW_PLATFORM_LIBRARY_JOYSTICK_STATE \
GLFW_WIN32_LIBRARY_JOYSTICK_STATE \
GLFW_COCOA_LIBRARY_JOYSTICK_STATE \
GLFW_LINUX_LIBRARY_JOYSTICK_STATE
GLFW_LINUX_LIBRARY_JOYSTICK_STATE \
GLFW_ANDROID_LIBRARY_JOYSTICK_STATE
#define GLFW_PLATFORM_CONTEXT_STATE \
GLFW_WGL_CONTEXT_STATE \

View File

@ -61,6 +61,8 @@ GLFWbool _glfwInitVulkan(int mode)
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib");
if (!_glfw.vk.handle)
_glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa();
#elif defined(_GLFW_ANDROID)
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so");
#elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so");
#else
@ -142,6 +144,8 @@ GLFWbool _glfwInitVulkan(int mode)
_glfw.vk.KHR_xcb_surface = GLFW_TRUE;
else if (strcmp(ep[i].extensionName, "VK_KHR_wayland_surface") == 0)
_glfw.vk.KHR_wayland_surface = GLFW_TRUE;
else if (strcmp(ep[i].extensionName, "VK_KHR_android_surface") == 0)
_glfw.vk.KHR_android_surface = GLFW_TRUE;
else if (strcmp(ep[i].extensionName, "VK_EXT_headless_surface") == 0)
_glfw.vk.EXT_headless_surface = GLFW_TRUE;
}

View File

@ -413,6 +413,8 @@ typedef struct _GLFWwindowWayland
struct wl_buffer* buffer;
_GLFWfallbackEdgeWayland top, left, right, bottom;
struct wl_surface* focus;
wl_fixed_t pointerX, pointerY;
const char* cursorName;
} fallback;
} _GLFWwindowWayland;
@ -454,7 +456,6 @@ typedef struct _GLFWlibraryWayland
struct wl_cursor_theme* cursorTheme;
struct wl_cursor_theme* cursorThemeHiDPI;
struct wl_surface* cursorSurface;
const char* cursorPreviousName;
int cursorTimerfd;
uint32_t serial;
uint32_t pointerEnterSerial;

View File

@ -275,6 +275,146 @@ static void destroyFallbackDecorations(_GLFWwindow* window)
destroyFallbackEdge(&window->wl.fallback.bottom);
}
static void updateFallbackDecorationCursor(_GLFWwindow* window,
wl_fixed_t sx,
wl_fixed_t sy)
{
window->wl.fallback.pointerX = sx;
window->wl.fallback.pointerY = sy;
const double xpos = wl_fixed_to_double(sx);
const double ypos = wl_fixed_to_double(sy);
const char* cursorName = "left_ptr";
if (window->resizable)
{
if (window->wl.fallback.focus == window->wl.fallback.top.surface)
{
if (ypos < GLFW_BORDER_SIZE)
cursorName = "n-resize";
}
else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
{
if (ypos < GLFW_BORDER_SIZE)
cursorName = "nw-resize";
else
cursorName = "w-resize";
}
else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
{
if (ypos < GLFW_BORDER_SIZE)
cursorName = "ne-resize";
else
cursorName = "e-resize";
}
else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
{
if (xpos < GLFW_BORDER_SIZE)
cursorName = "sw-resize";
else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
cursorName = "se-resize";
else
cursorName = "s-resize";
}
}
if (window->wl.fallback.cursorName != cursorName)
{
struct wl_surface* surface = _glfw.wl.cursorSurface;
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
int scale = 1;
if (window->wl.bufferScale > 1 && _glfw.wl.cursorThemeHiDPI)
{
// We only support up to scale=2 for now, since libwayland-cursor
// requires us to load a different theme for each size.
scale = 2;
theme = _glfw.wl.cursorThemeHiDPI;
}
struct wl_cursor* cursor = wl_cursor_theme_get_cursor(theme, cursorName);
if (!cursor)
return;
// TODO: handle animated cursors too.
struct wl_cursor_image* image = cursor->images[0];
if (!image)
return;
struct wl_buffer* buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
surface,
image->hotspot_x / scale,
image->hotspot_y / scale);
wl_surface_set_buffer_scale(surface, scale);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0, image->width, image->height);
wl_surface_commit(surface);
window->wl.fallback.cursorName = cursorName;
}
}
static void handleFallbackDecorationButton(_GLFWwindow* window,
uint32_t serial,
uint32_t button)
{
const double xpos = wl_fixed_to_double(window->wl.fallback.pointerX);
const double ypos = wl_fixed_to_double(window->wl.fallback.pointerY);
if (button == BTN_LEFT)
{
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
if (window->wl.fallback.focus == window->wl.fallback.top.surface)
{
if (ypos < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
else
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
}
else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
{
if (ypos < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
}
else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
{
if (ypos < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
}
else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
{
if (xpos < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
}
if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, serial, edges);
}
else if (button == BTN_RIGHT)
{
if (window->wl.xdg.toplevel)
{
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
_glfw.wl.seat, serial,
window->wl.cursorPosX,
window->wl.cursorPosY);
}
}
}
static void xdgDecorationHandleConfigure(void* userData,
struct zxdg_toplevel_decoration_v1* decoration,
uint32_t mode)
@ -1417,7 +1557,6 @@ static void pointerHandleLeave(void* userData,
_glfw.wl.serial = serial;
_glfw.wl.pointerFocus = NULL;
_glfw.wl.cursorPreviousName = NULL;
if (window->wl.hovered)
{
@ -1427,7 +1566,10 @@ static void pointerHandleLeave(void* userData,
else
{
if (window->wl.fallback.decorations)
{
window->wl.fallback.focus = NULL;
window->wl.fallback.cursorName = NULL;
}
}
}
@ -1444,92 +1586,16 @@ static void pointerHandleMotion(void* userData,
if (window->cursorMode == GLFW_CURSOR_DISABLED)
return;
const double xpos = wl_fixed_to_double(sx);
const double ypos = wl_fixed_to_double(sy);
window->wl.cursorPosX = xpos;
window->wl.cursorPosY = ypos;
if (window->wl.hovered)
{
_glfw.wl.cursorPreviousName = NULL;
_glfwInputCursorPos(window, xpos, ypos);
return;
window->wl.cursorPosX = wl_fixed_to_double(sx);
window->wl.cursorPosY = wl_fixed_to_double(sy);
_glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY);
}
else
{
if (window->wl.fallback.decorations)
{
const char* cursorName = "left_ptr";
if (window->resizable)
{
if (window->wl.fallback.focus == window->wl.fallback.top.surface)
{
if (ypos < GLFW_BORDER_SIZE)
cursorName = "n-resize";
}
else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
{
if (ypos < GLFW_BORDER_SIZE)
cursorName = "nw-resize";
else
cursorName = "w-resize";
}
else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
{
if (ypos < GLFW_BORDER_SIZE)
cursorName = "ne-resize";
else
cursorName = "e-resize";
}
else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
{
if (xpos < GLFW_BORDER_SIZE)
cursorName = "sw-resize";
else if (xpos > window->wl.width + GLFW_BORDER_SIZE)
cursorName = "se-resize";
else
cursorName = "s-resize";
}
}
if (_glfw.wl.cursorPreviousName != cursorName)
{
struct wl_surface* surface = _glfw.wl.cursorSurface;
struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
int scale = 1;
if (window->wl.bufferScale > 1 && _glfw.wl.cursorThemeHiDPI)
{
// We only support up to scale=2 for now, since libwayland-cursor
// requires us to load a different theme for each size.
scale = 2;
theme = _glfw.wl.cursorThemeHiDPI;
}
struct wl_cursor* cursor = wl_cursor_theme_get_cursor(theme, cursorName);
if (!cursor)
return;
// TODO: handle animated cursors too.
struct wl_cursor_image* image = cursor->images[0];
if (!image)
return;
struct wl_buffer* buffer = wl_cursor_image_get_buffer(image);
if (!buffer)
return;
wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerEnterSerial,
surface,
image->hotspot_x / scale,
image->hotspot_y / scale);
wl_surface_set_buffer_scale(surface, scale);
wl_surface_attach(surface, buffer, 0, 0);
wl_surface_damage(surface, 0, 0, image->width, image->height);
wl_surface_commit(surface);
_glfw.wl.cursorPreviousName = cursorName;
}
updateFallbackDecorationCursor(window, sx, sy);
}
}
@ -1552,62 +1618,11 @@ static void pointerHandleButton(void* userData,
button - BTN_LEFT,
state == WL_POINTER_BUTTON_STATE_PRESSED,
_glfw.wl.xkb.modifiers);
return;
}
else
{
if (window->wl.fallback.decorations)
{
if (button == BTN_LEFT)
{
uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
if (window->wl.fallback.focus == window->wl.fallback.top.surface)
{
if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
else
xdg_toplevel_move(window->wl.xdg.toplevel, _glfw.wl.seat, serial);
}
else if (window->wl.fallback.focus == window->wl.fallback.left.surface)
{
if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
}
else if (window->wl.fallback.focus == window->wl.fallback.right.surface)
{
if (window->wl.cursorPosY < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
}
else if (window->wl.fallback.focus == window->wl.fallback.bottom.surface)
{
if (window->wl.cursorPosX < GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
else if (window->wl.cursorPosX > window->wl.width + GLFW_BORDER_SIZE)
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
else
edges = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
}
if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE)
{
xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat,
serial, edges);
}
}
else if (button == BTN_RIGHT)
{
if (window->wl.xdg.toplevel)
{
xdg_toplevel_show_window_menu(window->wl.xdg.toplevel,
_glfw.wl.seat, serial,
window->wl.cursorPosX,
window->wl.cursorPosY);
}
}
handleFallbackDecorationButton(window, serial, button);
}
}
@ -1621,12 +1636,15 @@ static void pointerHandleAxis(void* userData,
if (!window)
return;
if (window->wl.hovered)
{
// NOTE: 10 units of motion per mouse wheel step seems to be a common ratio
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
_glfwInputScroll(window, -wl_fixed_to_double(value) / 10.0, 0.0);
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
_glfwInputScroll(window, 0.0, -wl_fixed_to_double(value) / 10.0);
}
}
static const struct wl_pointer_listener pointerListener =
{