Created
February 15, 2026 19:35
-
-
Save maidis/368af226d08b1a3a3565ecd9beb8237d to your computer and use it in GitHub Desktop.
SFML on Haiku
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- /Users/anilozbek/.gemini/antigravity/scratch/sfml_port/temp_extract/SFML/extlibs/headers/miniaudio/miniaudio.h 2026-02-12 01:36:54 | |
| +++ /Users/anilozbek/.gemini/antigravity/scratch/sfml_port/SFML/extlibs/headers/miniaudio/miniaudio.h 2026-02-15 20:05:17 | |
| @@ -6547,6 +6547,9 @@ | |
| #define MA_SUPPORT_JACK /* JACK is technically supported on Windows, but I don't know how many people use it in practice... */ | |
| #endif | |
| #endif | |
| +#endif | |
| +#if defined(MA_HAIKU) | |
| + #define MA_SUPPORT_HAIKU | |
| #endif | |
| #if defined(MA_UNIX) && !defined(MA_ORBIS) && !defined(MA_PROSPERO) | |
| #if defined(MA_LINUX) | |
| @@ -6612,6 +6615,9 @@ | |
| #if defined(MA_SUPPORT_SNDIO) && !defined(MA_NO_SNDIO) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_SNDIO)) | |
| #define MA_HAS_SNDIO | |
| #endif | |
| +#if defined(MA_SUPPORT_HAIKU) && !defined(MA_NO_HAIKU) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_HAIKU)) | |
| + #define MA_HAS_HAIKU | |
| +#endif | |
| #if defined(MA_SUPPORT_AUDIO4) && !defined(MA_NO_AUDIO4) && (!defined(MA_ENABLE_ONLY_SPECIFIC_BACKENDS) || defined(MA_ENABLE_AUDIO4)) | |
| #define MA_HAS_AUDIO4 | |
| #endif | |
| @@ -6665,6 +6671,7 @@ | |
| ma_backend_coreaudio, | |
| ma_backend_sndio, | |
| ma_backend_audio4, | |
| + ma_backend_haiku, | |
| ma_backend_oss, | |
| ma_backend_pulseaudio, | |
| ma_backend_alsa, | |
| @@ -7597,6 +7604,12 @@ | |
| { | |
| int _unused; | |
| } audio4; | |
| +#endif | |
| +#ifdef MA_SUPPORT_HAIKU | |
| + struct | |
| + { | |
| + int _unused; | |
| + } haiku; | |
| #endif | |
| #ifdef MA_SUPPORT_OSS | |
| struct | |
| @@ -7929,6 +7942,12 @@ | |
| int fdPlayback; | |
| int fdCapture; | |
| } audio4; | |
| +#endif | |
| +#ifdef MA_SUPPORT_HAIKU | |
| + struct | |
| + { | |
| + void* pPlayer; | |
| + } haiku; | |
| #endif | |
| #ifdef MA_SUPPORT_OSS | |
| struct | |
| @@ -17971,6 +17990,7 @@ | |
| {ma_backend_coreaudio, "Core Audio"}, | |
| {ma_backend_sndio, "sndio"}, | |
| {ma_backend_audio4, "audio(4)"}, | |
| + {ma_backend_haiku, "Haiku"}, | |
| {ma_backend_oss, "OSS"}, | |
| {ma_backend_pulseaudio, "PulseAudio"}, | |
| {ma_backend_alsa, "ALSA"}, | |
| @@ -18053,6 +18073,12 @@ | |
| #endif | |
| case ma_backend_audio4: | |
| #if defined(MA_HAS_AUDIO4) | |
| + return MA_TRUE; | |
| + #else | |
| + return MA_FALSE; | |
| + #endif | |
| + case ma_backend_haiku: | |
| + #if defined(MA_HAS_HAIKU) | |
| return MA_TRUE; | |
| #else | |
| return MA_FALSE; | |
| @@ -28587,8 +28613,322 @@ | |
| } | |
| #endif /* ALSA */ | |
| + | |
| +/****************************************************************************** | |
| +Haiku Backend | |
| +******************************************************************************/ | |
| +#ifdef MA_HAS_HAIKU | |
| +#ifdef __cplusplus | |
| +#include <SoundPlayer.h> | |
| +#include <media/MediaDefs.h> | |
| +#include <signal.h> | |
| +#include <OS.h> | |
| + | |
| +static void ma_haiku_callback(void* pCookie, void* pBuffer, size_t size, const media_raw_audio_format& format) | |
| +{ | |
| + ma_device* pDevice = (ma_device*)pCookie; | |
| + | |
| + if (pDevice == NULL || pBuffer == NULL) { | |
| + return; | |
| + } | |
| + | |
| + /* | |
| + BSoundPlayer starts its thread immediately, which means this callback can be fired | |
| + before ma_device_start() has been called. We MUST guard against this to avoid | |
| + accessing uninitialized state or firing data callbacks too early. | |
| + */ | |
| + if (ma_device_get_state(pDevice) != ma_device_state_started) { | |
| + memset(pBuffer, 0, size); | |
| + return; | |
| + } | |
| + | |
| + /* Boost priority on first callback to ensure stable RT performance */ | |
| + #ifndef B_AUDIO_PLAYBACK_PRIORITY | |
| + #define B_AUDIO_PLAYBACK_PRIORITY 120 | |
| + #endif | |
| + static thread_id lastCheckedThread = -1; | |
| + thread_id currentThread = find_thread(NULL); | |
| + if (currentThread != lastCheckedThread) { | |
| + set_thread_priority(currentThread, B_AUDIO_PLAYBACK_PRIORITY); | |
| + lastCheckedThread = currentThread; | |
| + } | |
| + | |
| + ma_uint32 targetChannels = format.channel_count; | |
| + ma_format targetFormat; | |
| + switch (format.format) { | |
| + case media_raw_audio_format::B_AUDIO_FLOAT: targetFormat = ma_format_f32; break; | |
| + case media_raw_audio_format::B_AUDIO_INT: targetFormat = ma_format_s32; break; | |
| + case media_raw_audio_format::B_AUDIO_SHORT: targetFormat = ma_format_s16; break; | |
| + case media_raw_audio_format::B_AUDIO_UCHAR: targetFormat = ma_format_u8; break; | |
| + default: targetFormat = ma_format_unknown; break; | |
| + } | |
| + | |
| + if (targetFormat == ma_format_unknown) { | |
| + memset(pBuffer, 0, size); | |
| + return; | |
| + } | |
| + | |
| + ma_uint32 bytesPerFrame = ma_get_bytes_per_frame(targetFormat, targetChannels); | |
| + if (bytesPerFrame > 0) { | |
| + ma_uint32 frameCount = (ma_uint32)(size / bytesPerFrame); | |
| + | |
| + /* | |
| + We must ensure that the device format matches targetFormat. | |
| + If not, we risk buffer overflow or garbage audio. | |
| + */ | |
| + if (pDevice->playback.format != targetFormat || pDevice->playback.channels != targetChannels) { | |
| + memset(pBuffer, 0, size); | |
| + } else { | |
| + ma_device__handle_data_callback(pDevice, pBuffer, NULL, frameCount); | |
| + } | |
| + } | |
| +} | |
| +#endif | |
| + | |
| +static ma_result ma_device_init__haiku(ma_device* pDevice, const ma_device_config* pConfig, ma_device_descriptor* pDescriptorPlayback, ma_device_descriptor* pDescriptorCapture) | |
| +{ | |
| + MA_ASSERT(pDevice != NULL); | |
| + MA_ASSERT(pConfig != NULL); | |
| + | |
| + (void)pDescriptorCapture; | |
| + | |
| +#ifdef __cplusplus | |
| + ma_uint32 targetSampleRate = pConfig->sampleRate; | |
| + if (targetSampleRate == 0) { | |
| + targetSampleRate = 44100; | |
| + } | |
| + | |
| + ma_uint32 targetChannels = pConfig->playback.channels; | |
| + if (targetChannels == 0) { | |
| + targetChannels = 2; | |
| + } | |
| + | |
| + ma_log_postf(ma_context_get_log(pDevice->pContext), MA_LOG_LEVEL_DEBUG, "[Haiku] Requesting sample rate %u, channels %u\n", targetSampleRate, targetChannels); | |
| + | |
| + media_raw_audio_format format; | |
| + MA_ZERO_OBJECT(&format); | |
| + format.frame_rate = (float)targetSampleRate; | |
| + format.channel_count = (ma_uint32)targetChannels; | |
| + | |
| + ma_uint32 bytesPerSample = 2; | |
| + if (pConfig->playback.format == ma_format_f32) { | |
| + format.format = media_raw_audio_format::B_AUDIO_FLOAT; | |
| + bytesPerSample = 4; | |
| + } else if (pConfig->playback.format == ma_format_s32) { | |
| + format.format = media_raw_audio_format::B_AUDIO_INT; | |
| + bytesPerSample = 4; | |
| + } else if (pConfig->playback.format == ma_format_u8) { | |
| + format.format = media_raw_audio_format::B_AUDIO_UCHAR; | |
| + bytesPerSample = 1; | |
| + } else { | |
| + format.format = media_raw_audio_format::B_AUDIO_SHORT; | |
| + bytesPerSample = 2; | |
| + } | |
| + | |
| + format.byte_order = B_MEDIA_HOST_ENDIAN; | |
| + | |
| + if (pConfig->periodSizeInFrames > 0) { | |
| + format.buffer_size = pConfig->periodSizeInFrames * bytesPerSample * targetChannels; | |
| + } else { | |
| + /* Default to 16k frames for maximal safety on virtual machines */ | |
| + format.buffer_size = 16384 * bytesPerSample * targetChannels; | |
| + } | |
| + | |
| + /* | |
| + Mask signals to prevent the audio thread from being interrupted by the OS. | |
| + This pattern is used by SDL's Haiku backend and is critical for stability. | |
| + */ | |
| + sigset_t omask, mask; | |
| + sigemptyset(&mask); | |
| + sigaddset(&mask, SIGHUP); | |
| + sigaddset(&mask, SIGINT); | |
| + sigaddset(&mask, SIGQUIT); | |
| + sigaddset(&mask, SIGPIPE); | |
| + sigaddset(&mask, SIGALRM); | |
| + sigaddset(&mask, SIGTERM); | |
| + sigaddset(&mask, SIGWINCH); | |
| + sigprocmask(SIG_BLOCK, &mask, &omask); | |
| + | |
| + BSoundPlayer* pPlayer = new BSoundPlayer(&format, "miniaudio", ma_haiku_callback, NULL, (void*)pDevice); | |
| + | |
| + // Restore signal mask | |
| + sigprocmask(SIG_SETMASK, &omask, NULL); | |
| + | |
| + if (pPlayer == NULL || pPlayer->InitCheck() != B_OK) { | |
| + if (pPlayer != NULL) { | |
| + delete pPlayer; | |
| + } | |
| + return MA_ERROR; | |
| + } | |
| + | |
| + pDevice->haiku.pPlayer = (void*)pPlayer; | |
| + | |
| + /* Haiku might have adjusted the format. Inform miniaudio. */ | |
| + const media_raw_audio_format& actualFormat = pPlayer->Format(); | |
| + | |
| + pDescriptorPlayback->channels = actualFormat.channel_count; | |
| + pDescriptorPlayback->sampleRate = (ma_uint32)actualFormat.frame_rate; | |
| + | |
| + switch (actualFormat.format) { | |
| + case media_raw_audio_format::B_AUDIO_FLOAT: pDescriptorPlayback->format = ma_format_f32; break; | |
| + case media_raw_audio_format::B_AUDIO_INT: pDescriptorPlayback->format = ma_format_s32; break; | |
| + case media_raw_audio_format::B_AUDIO_SHORT: pDescriptorPlayback->format = ma_format_s16; break; | |
| + case media_raw_audio_format::B_AUDIO_UCHAR: pDescriptorPlayback->format = ma_format_u8; break; | |
| + default: | |
| + if (pPlayer != NULL) { | |
| + delete pPlayer; | |
| + } | |
| + return MA_INVALID_ARGS; | |
| + } | |
| + | |
| + ma_uint32 actualBytesPerFrame = ma_get_bytes_per_frame(pDescriptorPlayback->format, pDescriptorPlayback->channels); | |
| + if (actualBytesPerFrame > 0) { | |
| + pDescriptorPlayback->periodSizeInFrames = actualFormat.buffer_size / actualBytesPerFrame; | |
| + } | |
| + | |
| + return MA_SUCCESS; | |
| +#else | |
| + (void)pDevice; | |
| + (void)pConfig; | |
| + (void)pDescriptorPlayback; | |
| + return MA_NOT_IMPLEMENTED; | |
| +#endif | |
| +} | |
| + | |
| +static ma_result ma_device_uninit__haiku(ma_device* pDevice) | |
| +{ | |
| + MA_ASSERT(pDevice != NULL); | |
| + | |
| +#ifdef __cplusplus | |
| + BSoundPlayer* pPlayer = (BSoundPlayer*)pDevice->haiku.pPlayer; | |
| + if (pPlayer != NULL) { | |
| + pPlayer->SetHasData(false); | |
| + pPlayer->Stop(); | |
| + | |
| + /* | |
| + Mask signals during deletion because BSoundPlayer's destructor joins the audio thread. | |
| + */ | |
| + sigset_t omask, mask; | |
| + sigemptyset(&mask); | |
| + sigaddset(&mask, SIGHUP); | |
| + sigaddset(&mask, SIGINT); | |
| + sigaddset(&mask, SIGQUIT); | |
| + sigaddset(&mask, SIGPIPE); | |
| + sigaddset(&mask, SIGALRM); | |
| + sigaddset(&mask, SIGTERM); | |
| + sigaddset(&mask, SIGWINCH); | |
| + sigprocmask(SIG_BLOCK, &mask, &omask); | |
| + | |
| + delete pPlayer; | |
| + | |
| + sigprocmask(SIG_SETMASK, &omask, NULL); | |
| + } | |
| + pDevice->haiku.pPlayer = NULL; | |
| + return MA_SUCCESS; | |
| +#else | |
| + (void)pDevice; | |
| + return MA_NOT_IMPLEMENTED; | |
| +#endif | |
| +} | |
| + | |
| +static ma_result ma_device_start__haiku(ma_device* pDevice) | |
| +{ | |
| + MA_ASSERT(pDevice != NULL); | |
| + | |
| +#ifdef __cplusplus | |
| + BSoundPlayer* pPlayer = (BSoundPlayer*)pDevice->haiku.pPlayer; | |
| + if (pPlayer != NULL) { | |
| + pPlayer->Start(); | |
| + pPlayer->SetHasData(true); | |
| + } | |
| + return MA_SUCCESS; | |
| +#else | |
| + (void)pDevice; | |
| + return MA_NOT_IMPLEMENTED; | |
| +#endif | |
| +} | |
| + | |
| +static ma_result ma_device_stop__haiku(ma_device* pDevice) | |
| +{ | |
| + MA_ASSERT(pDevice != NULL); | |
| + | |
| +#ifdef __cplusplus | |
| + BSoundPlayer* pPlayer = (BSoundPlayer*)pDevice->haiku.pPlayer; | |
| + if (pPlayer != NULL) { | |
| + pPlayer->SetHasData(false); | |
| + pPlayer->Stop(); | |
| + } | |
| + return MA_SUCCESS; | |
| +#else | |
| + (void)pDevice; | |
| + return MA_NOT_IMPLEMENTED; | |
| +#endif | |
| +} | |
| + | |
| +static ma_result ma_context_enumerate_devices__haiku(ma_context* pContext, ma_enum_devices_callback_proc callback, void* pUserData) | |
| +{ | |
| + ma_device_info info; | |
| + | |
| + MA_ASSERT(pContext != NULL); | |
| + MA_ASSERT(callback != NULL); | |
| + | |
| + MA_ZERO_OBJECT(&info); | |
| + ma_strncpy_s(info.name, sizeof(info.name), "Haiku Media Kit", MA_MAX_DEVICE_NAME_LENGTH); | |
| + | |
| + callback(pContext, ma_device_type_playback, &info, pUserData); | |
| + | |
| + return MA_SUCCESS; | |
| +} | |
| + | |
| +static ma_result ma_context_get_device_info__haiku(ma_context* pContext, ma_device_type deviceType, const ma_device_id* pID, ma_device_info* pInfo) | |
| +{ | |
| + MA_ASSERT(pContext != NULL); | |
| + MA_ASSERT(pInfo != NULL); | |
| + | |
| + (void)pID; | |
| + | |
| + if (deviceType == ma_device_type_capture) { | |
| + return MA_NO_DEVICE; | |
| + } | |
| + | |
| + MA_ZERO_OBJECT(pInfo); | |
| + ma_strncpy_s(pInfo->name, sizeof(pInfo->name), "Haiku Media Kit", MA_MAX_DEVICE_NAME_LENGTH); | |
| + pInfo->isDefault = MA_TRUE; | |
| + | |
| + return MA_SUCCESS; | |
| +} | |
| + | |
| +static ma_result ma_context_uninit__haiku(ma_context* pContext) | |
| +{ | |
| + MA_ASSERT(pContext != NULL); | |
| + (void)pContext; | |
| + return MA_SUCCESS; | |
| +} | |
| + | |
| +static ma_result ma_context_init__haiku(ma_context* pContext, const ma_context_config* pConfig, ma_backend_callbacks* pCallbacks) | |
| +{ | |
| + MA_ASSERT(pContext != NULL); | |
| + MA_ASSERT(pCallbacks != NULL); | |
| + | |
| + (void)pConfig; | |
| + | |
| + pCallbacks->onContextInit = ma_context_init__haiku; | |
| + pCallbacks->onContextUninit = ma_context_uninit__haiku; | |
| + pCallbacks->onContextEnumerateDevices = ma_context_enumerate_devices__haiku; | |
| + pCallbacks->onContextGetDeviceInfo = ma_context_get_device_info__haiku; | |
| + pCallbacks->onDeviceInit = ma_device_init__haiku; | |
| + pCallbacks->onDeviceUninit = ma_device_uninit__haiku; | |
| + pCallbacks->onDeviceStart = ma_device_start__haiku; | |
| + pCallbacks->onDeviceStop = ma_device_stop__haiku; | |
| + pCallbacks->onDeviceRead = NULL; | |
| + pCallbacks->onDeviceWrite = NULL; | |
| + pCallbacks->onDeviceDataLoop = NULL; | |
| + | |
| + return MA_SUCCESS; | |
| +} | |
| +#endif | |
| /****************************************************************************** | |
| PulseAudio Backend | |
| @@ -30050,7 +30390,7 @@ | |
| } | |
| g_StreamCounter += 1; | |
| - return ((ma_pa_stream_new_proc)pDevice->pContext->pulse.pa_stream_new)((ma_pa_context*)pDevice->pulse.pPulseContext, actualStreamName, ss, cmap); | |
| + return ((ma_pa_stream_new_proc)pDevice->pContext->pulse.pa_stream_new)((ma_pa_context*)pDevice->pContext->pulse.pPulseContext, actualStreamName, ss, cmap); | |
| } | |
| @@ -30292,7 +30632,7 @@ | |
| int error = 0; | |
| const char* devPlayback = NULL; | |
| const char* devCapture = NULL; | |
| - ma_format format = ma_format_unknown; | |
| + ma_format targetFormat = ma_format_s16; | |
| ma_uint32 channels = 0; | |
| ma_uint32 sampleRate = 0; | |
| ma_pa_sink_info sinkInfo; | |
| @@ -36735,7 +37075,11 @@ | |
| #include <sys/ioctl.h> | |
| #include <unistd.h> | |
| #include <fcntl.h> | |
| +#if defined(__HAIKU__) | |
| +#include <private/audio/soundcard.h> | |
| +#else | |
| #include <sys/soundcard.h> | |
| +#endif | |
| #ifndef SNDCTL_DSP_HALT | |
| #define SNDCTL_DSP_HALT SNDCTL_DSP_RESET | |
| @@ -37354,10 +37698,7 @@ | |
| return MA_SUCCESS; | |
| } | |
| -#endif /* OSS */ | |
| - | |
| - | |
| - | |
| +#endif | |
| /****************************************************************************** | |
| @@ -41311,6 +41652,12 @@ | |
| case ma_backend_audio4: | |
| { | |
| pContext->callbacks.onContextInit = ma_context_init__audio4; | |
| + } break; | |
| + #endif | |
| + #ifdef MA_HAS_HAIKU | |
| + case ma_backend_haiku: | |
| + { | |
| + pContext->callbacks.onContextInit = ma_context_init__haiku; | |
| } break; | |
| #endif | |
| #ifdef MA_HAS_OSS |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| SUMMARY="Simple and Fast Multimedia Library for Haiku" | |
| DESCRIPTION="SFML is a free multimedia C++ API that provides you low and high \ | |
| level access to graphics, input, audio, etc." | |
| HOMEPAGE="https://www.sfml-dev.org/" | |
| COPYRIGHT="2007-2024 Laurent Gomila" | |
| LICENSE="Zlib" | |
| REVISION="1" | |
| SOURCE_URI="https://github.com/SFML/SFML/archive/3.0.2.tar.gz" | |
| CHECKSUM_SHA256="4cf7da2af6ad71c77f88414fd53d6110f0011b9ba7144e554b4138e6475739c9" | |
| SOURCE_DIR="SFML-3.0.2" | |
| PATCHES="sfml-only-haiku.patch sfml-miniaudio-haiku.patch" | |
| ARCHITECTURES="all !x86_gcc2" | |
| SECONDARY_ARCHITECTURES="x86" | |
| PROVIDES=" | |
| sfml$secondaryArchSuffix = $portVersion | |
| lib:libsfml_audio$secondaryArchSuffix = $portVersion | |
| lib:libsfml_graphics$secondaryArchSuffix = $portVersion | |
| lib:libsfml_network$secondaryArchSuffix = $portVersion | |
| lib:libsfml_system$secondaryArchSuffix = $portVersion | |
| lib:libsfml_window$secondaryArchSuffix = $portVersion | |
| " | |
| REQUIRES=" | |
| haiku$secondaryArchSuffix | |
| lib:libFLAC$secondaryArchSuffix | |
| lib:libfreetype$secondaryArchSuffix | |
| lib:libGL$secondaryArchSuffix | |
| lib:libogg$secondaryArchSuffix | |
| lib:libvorbis$secondaryArchSuffix | |
| " | |
| PROVIDES_devel=" | |
| sfml${secondaryArchSuffix}_devel = $portVersion | |
| devel:libsfml_audio$secondaryArchSuffix = $portVersion | |
| devel:libsfml_graphics$secondaryArchSuffix = $portVersion | |
| devel:libsfml_network$secondaryArchSuffix = $portVersion | |
| devel:libsfml_system$secondaryArchSuffix = $portVersion | |
| devel:libsfml_window$secondaryArchSuffix = $portVersion | |
| " | |
| REQUIRES_devel=" | |
| sfml$secondaryArchSuffix == $portVersion | |
| " | |
| BUILD_REQUIRES=" | |
| haiku${secondaryArchSuffix}_devel | |
| devel:libFLAC$secondaryArchSuffix | |
| devel:libfreetype$secondaryArchSuffix | |
| devel:libGL$secondaryArchSuffix | |
| devel:libogg$secondaryArchSuffix | |
| devel:libvorbis$secondaryArchSuffix | |
| " | |
| BUILD_PREREQUIRES=" | |
| cmd:cmake | |
| cmd:gcc$secondaryArchSuffix | |
| cmd:make | |
| " | |
| BUILD() | |
| { | |
| cmake -Bbuild -S. -DCMAKE_BUILD_TYPE=Release \ | |
| -DCMAKE_INSTALL_PREFIX=$prefix \ | |
| -DSFML_BUILD_EXAMPLES=ON | |
| make -C build $jobArgs | |
| } | |
| INSTALL() | |
| { | |
| make -C build install | |
| prepareInstalledDevelLibs \ | |
| libsfml-audio \ | |
| libsfml-graphics \ | |
| libsfml-network \ | |
| libsfml-system \ | |
| libsfml-window | |
| packageEntries devel \ | |
| $developDir | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/CMakeLists.txt b/CMakeLists.txt | |
| index f013d24a..adc2e9f4 100644 | |
| --- a/CMakeLists.txt | |
| +++ b/CMakeLists.txt | |
| @@ -98,6 +98,8 @@ elseif(SFML_OS_MACOS) | |
| set(DEFAULT_INSTALL_MISC_DIR /usr/local/share/SFML) | |
| elseif(SFML_OS_ANDROID) | |
| set(DEFAULT_INSTALL_MISC_DIR ${CMAKE_ANDROID_NDK}/sources/third_party/sfml) | |
| +elseif(SFML_OS_HAIKU) | |
| + set(DEFAULT_INSTALL_MISC_DIR share/SFML) | |
| endif() | |
| # force building sfml-window, if sfml-graphics module is built | |
| diff --git a/cmake/Config.cmake b/cmake/Config.cmake | |
| index 0d3153a7..ab262499 100644 | |
| --- a/cmake/Config.cmake | |
| +++ b/cmake/Config.cmake | |
| @@ -61,6 +61,13 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Android") | |
| # use the OpenGL ES implementation on Android | |
| set(OPENGL_ES 1) | |
| +elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Haiku") | |
| + set(SFML_OS_HAIKU 1) | |
| + set(SFML_OS_UNIX 1) | |
| + | |
| + # don't use the OpenGL ES implementation on Haiku | |
| + set(OPENGL_ES 0) | |
| + | |
| # comparing CMAKE_SYSTEM_NAME with "CYGWIN" generates a false warning depending on the CMake version | |
| # let's avoid it so the actual error is more visible | |
| elseif(${CYGWIN}) | |
| diff --git a/examples/event_handling/EventHandling.cpp b/examples/event_handling/EventHandling.cpp | |
| index 577dbb64..ada48a4e 100644 | |
| --- a/examples/event_handling/EventHandling.cpp | |
| +++ b/examples/event_handling/EventHandling.cpp | |
| @@ -331,8 +331,16 @@ private: | |
| /// \return Application exit code | |
| /// | |
| //////////////////////////////////////////////////////////// | |
| +#ifdef __HAIKU__ | |
| +#include <Application.h> | |
| +#endif | |
| + | |
| int main() | |
| { | |
| +#ifdef __HAIKU__ | |
| + BApplication app("application/x-vnd.sfml-event_handling"); | |
| +#endif | |
| + | |
| Application application; | |
| application.run(); | |
| } | |
| diff --git a/examples/island/Island.cpp b/examples/island/Island.cpp | |
| index 628c17c5..372da3d2 100644 | |
| --- a/examples/island/Island.cpp | |
| +++ b/examples/island/Island.cpp | |
| @@ -424,8 +424,16 @@ void generateTerrain(sf::Vertex* buffer) | |
| /// \return Application exit code | |
| /// | |
| //////////////////////////////////////////////////////////// | |
| +#ifdef __HAIKU__ | |
| +#include <Application.h> | |
| +#endif | |
| + | |
| int main() | |
| { | |
| +#ifdef __HAIKU__ | |
| + BApplication app("application/x-vnd.sfml-island"); | |
| +#endif | |
| + | |
| // Create the window of the application | |
| sf::RenderWindow window(sf::VideoMode(windowSize), "SFML Island", sf::Style::Titlebar | sf::Style::Close); | |
| window.setVerticalSyncEnabled(true); | |
| diff --git a/examples/joystick/Joystick.cpp b/examples/joystick/Joystick.cpp | |
| index bca3396d..9236b2b4 100644 | |
| --- a/examples/joystick/Joystick.cpp | |
| +++ b/examples/joystick/Joystick.cpp | |
| @@ -87,8 +87,16 @@ void updateValues(unsigned int index) | |
| /// \return Application exit code | |
| /// | |
| //////////////////////////////////////////////////////////// | |
| +#ifdef __HAIKU__ | |
| +#include <Application.h> | |
| +#endif | |
| + | |
| int main() | |
| { | |
| +#ifdef __HAIKU__ | |
| + BApplication app("application/x-vnd.sfml-joystick"); | |
| +#endif | |
| + | |
| // Create the window of the application | |
| sf::RenderWindow window(sf::VideoMode({400, 775}), "Joystick", sf::Style::Close); | |
| window.setVerticalSyncEnabled(true); | |
| diff --git a/examples/keyboard/Keyboard.cpp b/examples/keyboard/Keyboard.cpp | |
| index a1155e60..3f7fa098 100644 | |
| --- a/examples/keyboard/Keyboard.cpp | |
| +++ b/examples/keyboard/Keyboard.cpp | |
| @@ -749,8 +749,16 @@ sf::String textEventDescription(const sf::Event::TextEntered& textEntered) | |
| /// \return Application exit code | |
| /// | |
| //////////////////////////////////////////////////////////// | |
| +#ifdef __HAIKU__ | |
| +#include <Application.h> | |
| +#endif | |
| + | |
| int main() | |
| { | |
| +#ifdef __HAIKU__ | |
| + BApplication app("application/x-vnd.sfml-keyboard"); | |
| +#endif | |
| + | |
| // Create the main window | |
| sf::RenderWindow window(sf::VideoMode({1280, 720}), "Keyboard", sf::Style::Titlebar | sf::Style::Close); | |
| window.setFramerateLimit(25); | |
| diff --git a/examples/opengl/OpenGL.cpp b/examples/opengl/OpenGL.cpp | |
| index 538d19d1..fafb3789 100644 | |
| --- a/examples/opengl/OpenGL.cpp | |
| +++ b/examples/opengl/OpenGL.cpp | |
| @@ -38,8 +38,16 @@ std::filesystem::path resourcesDir() | |
| /// \return Application exit code | |
| /// | |
| //////////////////////////////////////////////////////////// | |
| +#ifdef __HAIKU__ | |
| +#include <Application.h> | |
| +#endif | |
| + | |
| int main() | |
| { | |
| +#ifdef __HAIKU__ | |
| + BApplication app("application/x-vnd.sfml-opengl"); | |
| +#endif | |
| + | |
| bool exit = false; | |
| bool sRgb = false; | |
| diff --git a/examples/shader/Shader.cpp b/examples/shader/Shader.cpp | |
| index 14761218..41f5016f 100644 | |
| --- a/examples/shader/Shader.cpp | |
| +++ b/examples/shader/Shader.cpp | |
| @@ -375,8 +375,16 @@ std::optional<Geometry> tryLoadGeometry() | |
| /// \return Application exit code | |
| /// | |
| //////////////////////////////////////////////////////////// | |
| +#ifdef __HAIKU__ | |
| +#include <Application.h> | |
| +#endif | |
| + | |
| int main() | |
| { | |
| +#ifdef __HAIKU__ | |
| + BApplication app("application/x-vnd.sfml-shader"); | |
| +#endif | |
| + | |
| // Exit early if shaders are not available | |
| if (!sf::Shader::isAvailable()) | |
| { | |
| diff --git a/examples/stencil/Stencil.cpp b/examples/stencil/Stencil.cpp | |
| index 91917034..cf5e956d 100644 | |
| --- a/examples/stencil/Stencil.cpp | |
| +++ b/examples/stencil/Stencil.cpp | |
| @@ -12,8 +12,16 @@ | |
| /// \return Application exit code | |
| /// | |
| //////////////////////////////////////////////////////////// | |
| +#ifdef __HAIKU__ | |
| +#include <Application.h> | |
| +#endif | |
| + | |
| int main() | |
| { | |
| +#ifdef __HAIKU__ | |
| + BApplication app("application/x-vnd.sfml-stencil"); | |
| +#endif | |
| + | |
| // Create the window of the application with a stencil buffer | |
| sf::RenderWindow window(sf::VideoMode({600, 600}), | |
| "SFML Stencil", | |
| diff --git a/examples/tennis/Tennis.cpp b/examples/tennis/Tennis.cpp | |
| index a808597a..08187f32 100644 | |
| --- a/examples/tennis/Tennis.cpp | |
| +++ b/examples/tennis/Tennis.cpp | |
| @@ -34,8 +34,16 @@ std::filesystem::path resourcesDir() | |
| /// \return Application exit code | |
| /// | |
| //////////////////////////////////////////////////////////// | |
| +#ifdef __HAIKU__ | |
| +#include <Application.h> | |
| +#endif | |
| + | |
| int main() | |
| { | |
| +#ifdef __HAIKU__ | |
| + BApplication app("application/x-vnd.sfml-tennis"); | |
| +#endif | |
| + | |
| std::random_device rd; | |
| std::mt19937 rng(rd()); | |
| diff --git a/examples/vulkan/Vulkan.cpp b/examples/vulkan/Vulkan.cpp | |
| index 100ae283..66210734 100644 | |
| --- a/examples/vulkan/Vulkan.cpp | |
| +++ b/examples/vulkan/Vulkan.cpp | |
| @@ -2624,8 +2624,16 @@ private: | |
| /// \return Application exit code | |
| /// | |
| //////////////////////////////////////////////////////////// | |
| +#ifdef __HAIKU__ | |
| +#include <Application.h> | |
| +#endif | |
| + | |
| int main() | |
| { | |
| +#ifdef __HAIKU__ | |
| + BApplication app("application/x-vnd.sfml-vulkan"); | |
| +#endif | |
| + | |
| VulkanExample example; | |
| example.run(); | |
| diff --git a/examples/window/Window.cpp b/examples/window/Window.cpp | |
| index 9f46a9af..e53fd4d6 100644 | |
| --- a/examples/window/Window.cpp | |
| +++ b/examples/window/Window.cpp | |
| @@ -23,8 +23,15 @@ | |
| /// \return Application exit code | |
| /// | |
| //////////////////////////////////////////////////////////// | |
| +#ifdef __HAIKU__ | |
| +#include <Application.h> | |
| +#endif | |
| + | |
| int main() | |
| { | |
| +#ifdef __HAIKU__ | |
| + BApplication app("application/x-vnd.sfml-window"); | |
| +#endif | |
| // Request a 24-bits depth buffer when creating the window | |
| sf::ContextSettings contextSettings; | |
| contextSettings.depthBits = 24; | |
| diff --git a/include/SFML/Config.hpp b/include/SFML/Config.hpp | |
| index 36a8b1a3..81ebb877 100644 | |
| --- a/include/SFML/Config.hpp | |
| +++ b/include/SFML/Config.hpp | |
| @@ -68,6 +68,11 @@ | |
| #endif | |
| +#elif defined(__HAIKU__) | |
| + | |
| +// Haiku | |
| +#define SFML_SYSTEM_HAIKU | |
| + | |
| #elif defined(__unix__) | |
| // UNIX system, see which one it is | |
| diff --git a/include/SFML/Window/WindowHandle.hpp b/include/SFML/Window/WindowHandle.hpp | |
| index c15ce07b..3fbd30d1 100644 | |
| --- a/include/SFML/Window/WindowHandle.hpp | |
| +++ b/include/SFML/Window/WindowHandle.hpp | |
| @@ -57,7 +57,7 @@ using WindowHandle = void*; | |
| // Window handle is UIWindow (void*) on iOS - UIKit | |
| using WindowHandle = void*; | |
| -#elif defined(SFML_SYSTEM_ANDROID) | |
| +#elif defined(SFML_SYSTEM_ANDROID) || defined(SFML_SYSTEM_HAIKU) | |
| // Window handle is ANativeWindow* (void*) on Android | |
| using WindowHandle = void*; | |
| diff --git a/src/SFML/Audio/CMakeLists.txt b/src/SFML/Audio/CMakeLists.txt | |
| index 7567205c..aea78269 100644 | |
| --- a/src/SFML/Audio/CMakeLists.txt | |
| +++ b/src/SFML/Audio/CMakeLists.txt | |
| @@ -198,4 +198,6 @@ endif() | |
| if(SFML_OS_LINUX) | |
| target_link_libraries(sfml-audio PRIVATE dl) | |
| +elseif(SFML_OS_HAIKU) | |
| + target_link_libraries(sfml-audio PRIVATE media) | |
| endif() | |
| diff --git a/src/SFML/Network/CMakeLists.txt b/src/SFML/Network/CMakeLists.txt | |
| index 872c3a47..143fdf33 100644 | |
| --- a/src/SFML/Network/CMakeLists.txt | |
| +++ b/src/SFML/Network/CMakeLists.txt | |
| @@ -47,4 +47,6 @@ sfml_add_library(Network | |
| target_link_libraries(sfml-network PUBLIC SFML::System) | |
| if(SFML_OS_WINDOWS) | |
| target_link_libraries(sfml-network PRIVATE ws2_32) | |
| +elseif(SFML_OS_HAIKU) | |
| + target_link_libraries(sfml-network PRIVATE network) | |
| endif() | |
| diff --git a/src/SFML/System/CMakeLists.txt b/src/SFML/System/CMakeLists.txt | |
| index 3b7543a4..590060fc 100644 | |
| --- a/src/SFML/System/CMakeLists.txt | |
| +++ b/src/SFML/System/CMakeLists.txt | |
| @@ -92,4 +92,6 @@ elseif(SFML_OS_WINDOWS) | |
| target_link_libraries(sfml-system PRIVATE winmm) | |
| elseif(SFML_OS_ANDROID) | |
| target_link_libraries(sfml-system PRIVATE android log) | |
| +elseif(SFML_OS_HAIKU) | |
| + target_link_libraries(sfml-system PRIVATE root) | |
| endif() | |
| diff --git a/src/SFML/Window/CMakeLists.txt b/src/SFML/Window/CMakeLists.txt | |
| index ae9d90ec..8b5508fe 100644 | |
| --- a/src/SFML/Window/CMakeLists.txt | |
| +++ b/src/SFML/Window/CMakeLists.txt | |
| @@ -263,6 +263,26 @@ elseif(SFML_OS_ANDROID) | |
| ${SRCROOT}/Android/SensorImpl.cpp | |
| ) | |
| source_group("android" FILES ${PLATFORM_SRC}) | |
| +elseif(SFML_OS_HAIKU) | |
| + set(PLATFORM_SRC | |
| + ${SRCROOT}/Haiku/WindowImplHaiku.hpp | |
| + ${SRCROOT}/Haiku/WindowImplHaiku.cpp | |
| + ${SRCROOT}/Haiku/GlContext.hpp | |
| + ${SRCROOT}/Haiku/GlContext.cpp | |
| + ${SRCROOT}/Haiku/Utils.hpp | |
| + ${SRCROOT}/Haiku/Utils.cpp | |
| + ${SRCROOT}/Haiku/CursorImpl.hpp | |
| + ${SRCROOT}/Haiku/CursorImpl.cpp | |
| + ${SRCROOT}/Haiku/ClipboardImpl.hpp | |
| + ${SRCROOT}/Haiku/ClipboardImpl.cpp | |
| + ${SRCROOT}/Haiku/InputImpl.cpp | |
| + ${SRCROOT}/Haiku/JoystickImpl.hpp | |
| + ${SRCROOT}/Haiku/JoystickImpl.cpp | |
| + ${SRCROOT}/Haiku/SensorImpl.hpp | |
| + ${SRCROOT}/Haiku/SensorImpl.cpp | |
| + ${SRCROOT}/Haiku/VideoModeImpl.cpp | |
| + ) | |
| + source_group("haiku" FILES ${PLATFORM_SRC}) | |
| endif() | |
| # define the sfml-window target | |
| @@ -333,6 +353,8 @@ elseif(SFML_OS_IOS) | |
| target_link_libraries(sfml-window PUBLIC "-framework Foundation" "-framework UIKit" "-framework CoreGraphics" "-framework QuartzCore" "-framework CoreMotion") | |
| elseif(SFML_OS_ANDROID) | |
| target_link_libraries(sfml-window PRIVATE android) | |
| +elseif(SFML_OS_HAIKU) | |
| + target_link_libraries(sfml-window PRIVATE be game GL device) | |
| endif() | |
| # on some platforms (e.g. Raspberry Pi 3 armhf), GCC requires linking libatomic to use <atomic> features | |
| diff --git a/src/SFML/Window/ClipboardImpl.hpp b/src/SFML/Window/ClipboardImpl.hpp | |
| index b0ed7339..c1fa2e0f 100644 | |
| --- a/src/SFML/Window/ClipboardImpl.hpp | |
| +++ b/src/SFML/Window/ClipboardImpl.hpp | |
| @@ -44,4 +44,6 @@ | |
| #include <SFML/Window/iOS/ClipboardImpl.hpp> | |
| #elif defined(SFML_SYSTEM_ANDROID) | |
| #include <SFML/Window/Android/ClipboardImpl.hpp> | |
| +#elif defined(SFML_SYSTEM_HAIKU) | |
| +#include <SFML/Window/Haiku/ClipboardImpl.hpp> | |
| #endif | |
| diff --git a/src/SFML/Window/CursorImpl.hpp b/src/SFML/Window/CursorImpl.hpp | |
| index e6a87756..9b195cd6 100644 | |
| --- a/src/SFML/Window/CursorImpl.hpp | |
| +++ b/src/SFML/Window/CursorImpl.hpp | |
| @@ -44,4 +44,6 @@ | |
| #include <SFML/Window/iOS/CursorImpl.hpp> | |
| #elif defined(SFML_SYSTEM_ANDROID) | |
| #include <SFML/Window/Android/CursorImpl.hpp> | |
| +#elif defined(SFML_SYSTEM_HAIKU) | |
| +#include <SFML/Window/Haiku/CursorImpl.hpp> | |
| #endif | |
| diff --git a/src/SFML/Window/GlContext.cpp b/src/SFML/Window/GlContext.cpp | |
| index 7a9c5cdd..c503deb0 100644 | |
| --- a/src/SFML/Window/GlContext.cpp | |
| +++ b/src/SFML/Window/GlContext.cpp | |
| @@ -100,6 +100,11 @@ using ContextType = sf::priv::EaglContext; | |
| #include <SFML/Window/EglContext.hpp> | |
| using ContextType = sf::priv::EglContext; | |
| +#elif defined(SFML_SYSTEM_HAIKU) | |
| + | |
| +#include <SFML/Window/Haiku/GlContext.hpp> | |
| +using ContextType = sf::priv::HaikuContext; | |
| + | |
| #endif | |
| #if defined(SFML_SYSTEM_WINDOWS) | |
| @@ -490,7 +495,8 @@ void GlContext::unregisterUnsharedGlObject(std::shared_ptr<void> object) | |
| // in unshared objects should be the only one existing | |
| const auto iter = std::find_if(unsharedGlObjects->begin(), | |
| unsharedGlObjects->end(), | |
| - [&object](const Impl::UnsharedGlObject& obj) { | |
| + [&object](const Impl::UnsharedGlObject& obj) | |
| + { | |
| return (obj.object == object) && | |
| (obj.contextId == GlContextImpl::CurrentContext::get().id); | |
| }); | |
| diff --git a/src/SFML/Window/Haiku/ClipboardImpl.cpp b/src/SFML/Window/Haiku/ClipboardImpl.cpp | |
| new file mode 100644 | |
| index 00000000..cbce1359 | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/ClipboardImpl.cpp | |
| @@ -0,0 +1,77 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Haiku/ClipboardImpl.hpp> | |
| + | |
| +#include <Application.h> | |
| + | |
| +#include <Clipboard.h> | |
| +#include <cstring> | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +String ClipboardImpl::getString() | |
| +{ | |
| + if (be_clipboard->Lock()) | |
| + { | |
| + BMessage* clip = be_clipboard->Data(); | |
| + const char* text = NULL; | |
| + ssize_t textLen = 0; | |
| + | |
| + if (clip->FindData("text/plain", B_MIME_TYPE, (const void**)&text, &textLen) == B_OK) | |
| + { | |
| + be_clipboard->Unlock(); | |
| + return String::fromUtf8(text, text + textLen); | |
| + } | |
| + be_clipboard->Unlock(); | |
| + } | |
| + return ""; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void ClipboardImpl::setString(const String& text) | |
| +{ | |
| + if (be_clipboard->Lock()) | |
| + { | |
| + be_clipboard->Clear(); | |
| + BMessage* clip = be_clipboard->Data(); | |
| + | |
| + std::string utf8 = text.toUtf8(); | |
| + clip->AddData("text/plain", B_MIME_TYPE, utf8.c_str(), utf8.length()); | |
| + | |
| + be_clipboard->Commit(); | |
| + be_clipboard->Unlock(); | |
| + } | |
| +} | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/ClipboardImpl.hpp b/src/SFML/Window/Haiku/ClipboardImpl.hpp | |
| new file mode 100644 | |
| index 00000000..04e26f92 | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/ClipboardImpl.hpp | |
| @@ -0,0 +1,62 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +#pragma once | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/System/String.hpp> | |
| + | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +/// \brief Haiku implementation of clipboard | |
| +/// | |
| +//////////////////////////////////////////////////////////// | |
| +class ClipboardImpl | |
| +{ | |
| +public: | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Get the content of the clipboard as string data | |
| + /// | |
| + /// \return Clipboard contents as a string | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + static String getString(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Set the content of the clipboard as string data | |
| + /// | |
| + /// \param text Clipboard contents | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + static void setString(const String& text); | |
| +}; | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/CursorImpl.cpp b/src/SFML/Window/Haiku/CursorImpl.cpp | |
| new file mode 100644 | |
| index 00000000..6f0a62ef | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/CursorImpl.cpp | |
| @@ -0,0 +1,167 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Haiku/CursorImpl.hpp> | |
| + | |
| +#include <SFML/System/Err.hpp> | |
| + | |
| +#include <Bitmap.h> | |
| + | |
| +#include <Cursor.h> | |
| +#include <cstring> | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +CursorImpl::CursorImpl() : m_cursor(NULL) | |
| +{ | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +CursorImpl::~CursorImpl() | |
| +{ | |
| + delete m_cursor; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +bool CursorImpl::loadFromPixels(const std::uint8_t* pixels, Vector2u size, Vector2u hotspot) | |
| +{ | |
| + // BCursor expects a BBitmap. | |
| + // Create a BBitmap from pixels (RGBA). | |
| + // BBitmap accepts B_RGBA32. | |
| + | |
| + // Note: older Haiku/BeOS versions used specific cursor format. | |
| + // Modern Haiku supports creating cursor from bitmap. | |
| + | |
| + BRect rect(0, 0, (float)size.x - 1, (float)size.y - 1); | |
| + BBitmap* bitmap = new BBitmap(rect, B_RGBA32); | |
| + | |
| + if (bitmap->InitCheck() != B_OK) | |
| + { | |
| + delete bitmap; | |
| + return false; | |
| + } | |
| + | |
| + // Copy pixels. SFML uses RGBA. Haiku uses B_RGBA32 (BGRA usually on little endian, but let's check). | |
| + // B_RGBA32 structure: B, G, R, A. | |
| + // SFML: R, G, B, A. | |
| + | |
| + std::uint8_t* bits = (std::uint8_t*)bitmap->Bits(); | |
| + int32 bpr = bitmap->BytesPerRow(); | |
| + | |
| + for (unsigned int y = 0; y < size.y; ++y) | |
| + { | |
| + for (unsigned int x = 0; x < size.x; ++x) | |
| + { | |
| + const std::uint8_t* src = pixels + (x + y * size.x) * 4; | |
| + std::uint8_t* dst = bits + y * bpr + x * 4; | |
| + | |
| + dst[0] = src[2]; // B | |
| + dst[1] = src[1]; // G | |
| + dst[2] = src[0]; // R | |
| + dst[3] = src[3]; // A | |
| + } | |
| + } | |
| + | |
| + delete m_cursor; | |
| + // BCursor(const BBitmap* bitmap, BPoint hotspot) | |
| + m_cursor = new BCursor(bitmap, BPoint((float)hotspot.x, (float)hotspot.y)); | |
| + | |
| + delete bitmap; // BCursor copies the data? Yes, usually. | |
| + | |
| + return true; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +bool CursorImpl::loadFromSystem(Cursor::Type type) | |
| +{ | |
| + BCursorID id = B_CURSOR_ID_SYSTEM_DEFAULT; | |
| + | |
| + switch (type) | |
| + { | |
| + case Cursor::Type::Arrow: | |
| + id = B_CURSOR_ID_SYSTEM_DEFAULT; | |
| + break; | |
| + case Cursor::Type::ArrowWait: | |
| + id = B_CURSOR_ID_PROGRESS; | |
| + break; | |
| + case Cursor::Type::Wait: | |
| + id = B_CURSOR_ID_PROGRESS; | |
| + break; // Or B_CURSOR_ID_WAIT? (check headers) | |
| + case Cursor::Type::Text: | |
| + id = B_CURSOR_ID_I_BEAM; | |
| + break; | |
| + case Cursor::Type::Hand: | |
| + id = B_CURSOR_ID_FOLLOW_LINK; | |
| + break; // Context menu? Hand usually means link. | |
| + case Cursor::Type::SizeHorizontal: | |
| + id = B_CURSOR_ID_RESIZE_EAST_WEST; | |
| + break; | |
| + case Cursor::Type::SizeVertical: | |
| + id = B_CURSOR_ID_RESIZE_NORTH_SOUTH; | |
| + break; | |
| + case Cursor::Type::SizeTopLeftBottomRight: | |
| + id = B_CURSOR_ID_RESIZE_NORTH_WEST_SOUTH_EAST; | |
| + break; | |
| + case Cursor::Type::SizeBottomLeftTopRight: | |
| + id = B_CURSOR_ID_RESIZE_NORTH_EAST_SOUTH_WEST; | |
| + break; | |
| + case Cursor::Type::SizeAll: | |
| + id = B_CURSOR_ID_MOVE; | |
| + break; | |
| + case Cursor::Type::Cross: | |
| + id = B_CURSOR_ID_CROSS_HAIR; | |
| + break; | |
| + case Cursor::Type::Help: | |
| + id = B_CURSOR_ID_HELP; | |
| + break; | |
| + case Cursor::Type::NotAllowed: | |
| + id = B_CURSOR_ID_NOT_ALLOWED; | |
| + break; | |
| + } | |
| + | |
| + delete m_cursor; | |
| + m_cursor = new BCursor(id); | |
| + | |
| + return true; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +const BCursor* CursorImpl::getCursor() const | |
| +{ | |
| + return m_cursor; | |
| +} | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/CursorImpl.hpp b/src/SFML/Window/Haiku/CursorImpl.hpp | |
| new file mode 100644 | |
| index 00000000..c0f91f41 | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/CursorImpl.hpp | |
| @@ -0,0 +1,101 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +#pragma once | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Cursor.hpp> | |
| +#include <SFML/Window/CursorImpl.hpp> | |
| + | |
| +#include <SFML/System/NonCopyable.hpp> | |
| +#include <SFML/System/Vector2.hpp> | |
| + | |
| +#include <InterfaceDefs.h> | |
| + | |
| +class BCursor; | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +/// \brief Haiku implementation of cursor | |
| +/// | |
| +//////////////////////////////////////////////////////////// | |
| +class CursorImpl : NonCopyable | |
| +{ | |
| +public: | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Default constructor | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + CursorImpl(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Destructor | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + ~CursorImpl(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Create a cursor with the provided image | |
| + /// | |
| + /// \param pixels Array of pixels of the image | |
| + /// \param size Width and height of the image | |
| + /// \param hotspot (x,y) location of the hotspot | |
| + /// | |
| + /// \return true if the cursor was successfully loaded; false otherwise | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + bool loadFromPixels(const std::uint8_t* pixels, Vector2u size, Vector2u hotspot); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Create a native system cursor | |
| + /// | |
| + /// \param type System cursor type | |
| + /// | |
| + /// \return true if the cursor was successfully loaded; false otherwise | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + bool loadFromSystem(Cursor::Type type); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Get the underlying Haiku cursor | |
| + /// | |
| + /// \return Pointer to the BCursor | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + const BCursor* getCursor() const; | |
| + | |
| +private: | |
| + //////////////////////////////////////////////////////////// | |
| + // Member data | |
| + //////////////////////////////////////////////////////////// | |
| + BCursor* m_cursor; //!< Haiku cursor | |
| +}; | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/GlContext.cpp b/src/SFML/Window/Haiku/GlContext.cpp | |
| new file mode 100644 | |
| index 00000000..3e2a581d | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/GlContext.cpp | |
| @@ -0,0 +1,258 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Haiku/GlContext.hpp> | |
| +#include <SFML/Window/Haiku/WindowImplHaiku.hpp> | |
| + | |
| +#include <SFML/System/Err.hpp> | |
| + | |
| +#include <GLView.h> | |
| + | |
| +#include <Window.h> | |
| +#include <dlfcn.h> | |
| +#include <mutex> | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +namespace | |
| +{ | |
| +void ensureGlInit() | |
| +{ | |
| + // Ensure GL lib is loaded explicitly? | |
| + // Usually linked. | |
| +} | |
| +} // namespace | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +HaikuContext::HaikuContext(const ContextSettings& settings) : m_view(NULL) | |
| +{ | |
| + // Create a dummy window for the context | |
| + // We can't have a view without a window in BGLView (mostly). | |
| + // Or we can, but it won't be valid for drawing until attached. | |
| + // SFML assumes context can be active. | |
| + | |
| + // Create a hidden window | |
| + createContext(NULL, 32); | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +HaikuContext::HaikuContext(const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel) : | |
| +m_view(NULL) | |
| +{ | |
| + createContext(owner, bitsPerPixel); | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +HaikuContext::HaikuContext(const ContextSettings& settings, const GlContext* shared) : m_view(NULL) | |
| +{ | |
| + // Sharing not easily supported in BGLView legacy API without specific options. | |
| + // BGLView constructor has Options... | |
| + // But we normally just create a context. | |
| + // If shared is provided, we might need to assume it works via shared resources globally or specific BGLView capability. | |
| + // Standard BGLView doesn't expose "share with" argument explicitly in constructor. | |
| + // We'll ignore sharing for now or check if Haiku GL supports it automatically. | |
| + // Note: Mesa usually shares lists if in same address space. | |
| + | |
| + createContext(NULL, 32); | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +HaikuContext::~HaikuContext() | |
| +{ | |
| + if (m_view) | |
| + { | |
| + // View must be removed from window? | |
| + BWindow* win = m_view->Window(); | |
| + if (win) | |
| + { | |
| + win->Lock(); | |
| + m_view->RemoveSelf(); | |
| + delete m_view; // Deleting view inside Lock? Allowed. | |
| + win->Unlock(); | |
| + | |
| + // If we created a dummy window, we should destroy it. | |
| + // But how do we know if we created a dummy window? | |
| + // GlContext::createContext needs to store that. | |
| + // But WindowImplHaiku manages its own window. | |
| + // If we are ownerless, we need a dummy window. | |
| + // Let's store "m_window" if we own it. | |
| + // But GlContext class doesn't have m_window member in generic interface? | |
| + // We can add it to our private class if needed, or check if owner was null. | |
| + // Actually, we can attach the dummy window to m_view->Window() and see if its name is "SFML_Dummy". | |
| + | |
| + if (win && strcmp(win->Title(), "SFML_Dummy") == 0) | |
| + { | |
| + win->Lock(); | |
| + win->Quit(); | |
| + } | |
| + } | |
| + } | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +GlFunctionPointer HaikuContext::getFunction(const char* name) | |
| +{ | |
| + static void* handle = NULL; | |
| + static std::mutex mutex; | |
| + | |
| + std::lock_guard<std::mutex> lock(mutex); | |
| + if (!handle) | |
| + { | |
| + handle = dlopen("libGL.so", RTLD_LAZY | RTLD_GLOBAL); | |
| + } | |
| + | |
| + if (handle) | |
| + { | |
| + return (GlFunctionPointer)dlsym(handle, name); | |
| + } | |
| + | |
| + return 0; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +bool HaikuContext::makeCurrent(bool current) | |
| +{ | |
| + if (m_view) | |
| + { | |
| + if (current) | |
| + { | |
| + m_view->LockGL(); | |
| + // Also need BWindow lock? | |
| + // BGLView::LockGL() locks the window if needed? | |
| + // Docs say: "Blocks until the view's window is locked and the context is current." | |
| + // So yes. | |
| + } | |
| + else | |
| + { | |
| + m_view->UnlockGL(); | |
| + } | |
| + return true; | |
| + } | |
| + return false; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void HaikuContext::display() | |
| +{ | |
| + if (m_view) | |
| + { | |
| + m_view->SwapBuffers(); | |
| + } | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void HaikuContext::setVerticalSyncEnabled(bool enabled) | |
| +{ | |
| + // BGLView doesn't offer direct VSync control via API without extensions. | |
| + // Try WGL_EXT_swap_control equivalent? | |
| + // Use glCheck? | |
| + // Or BGLView::SetVerticalSync? (doesn't exist). | |
| + // Haiku R1/Beta might support GL_swap_control via extension. | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void HaikuContext::createContext(const WindowImpl* owner, unsigned int bitsPerPixel) | |
| +{ | |
| + // Flags | |
| + ulong flags = BGL_RGB | BGL_DOUBLE | BGL_DEPTH; | |
| + // Stencil? BGL_STENCIL | |
| + if (m_settings.stencilBits > 0) | |
| + flags |= BGL_STENCIL; | |
| + if (m_settings.antiAliasingLevel > 0) | |
| + { | |
| + // BGLView doesn't have explicit AA flag in legacy API. | |
| + // MSAA might be requested differently. | |
| + } | |
| + | |
| + // Rect | |
| + BRect frame(0, 0, 100, 100); | |
| + BWindow* win = NULL; | |
| + | |
| + if (owner) | |
| + { | |
| + // Attach to owner window | |
| + // But owner window already has a view? | |
| + // WindowImplHaiku creates a SFView. | |
| + // We can create a BGLView as child of that view or properly integrated? | |
| + // Actually, for OpenGL, the BGLView *should be* the view handling the drawing. | |
| + // WindowImplHaiku created a SFView (BView). | |
| + // We probably want to replace it or add BGLView on top? | |
| + // Or make WindowImplHaiku create BGLView if needed? | |
| + // But WindowImpl creates window before Context. | |
| + | |
| + // Solution: Add BGLView to the Window. | |
| + WindowHandle handle = owner->getNativeHandle(); | |
| + win = (BWindow*)handle; | |
| + if (win) | |
| + { | |
| + if (win->Lock()) | |
| + { | |
| + frame = win->Bounds(); | |
| + // Create View | |
| + m_view = new BGLView(frame, "SFML_GL", B_FOLLOW_ALL_SIDES, 0, flags); | |
| + win->AddChild(m_view); // Add to window (on top of existing view?) | |
| + // If we have SFView, it handles inputs. BGLView handles drawing. | |
| + // BGLView might steal input? | |
| + // We should ensure m_view is behind? Or simple: | |
| + // BGLView is just for GL context. | |
| + win->Unlock(); | |
| + } | |
| + } | |
| + } | |
| + else | |
| + { | |
| + // Dummy window | |
| + win = new BWindow(frame, "SFML_Dummy", B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_MOVABLE); | |
| + m_view = new BGLView(frame, "SFML_GL", B_FOLLOW_ALL_SIDES, 0, flags); | |
| + win->AddChild(m_view); | |
| + // Don't show the window | |
| + } | |
| + | |
| + if (m_view) | |
| + { | |
| + // Update settings | |
| + m_settings.majorVersion = 1; // Default | |
| + m_settings.minorVersion = 1; | |
| + // Query actual values if possible? | |
| + } | |
| +} | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/GlContext.hpp b/src/SFML/Window/Haiku/GlContext.hpp | |
| new file mode 100644 | |
| index 00000000..b77165e1 | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/GlContext.hpp | |
| @@ -0,0 +1,133 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +#pragma once | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/ContextSettings.hpp> | |
| +#include <SFML/Window/GlContext.hpp> | |
| +#include <SFML/Window/Haiku/WindowImplHaiku.hpp> | |
| +#include <SFML/Window/WindowImpl.hpp> | |
| + | |
| +class BGLView; | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +/// \brief Haiku implementation of OpenGL Context | |
| +/// | |
| +//////////////////////////////////////////////////////////// | |
| +class HaikuContext : public sf::priv::GlContext | |
| +{ | |
| +public: | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Create a new context, not associated to a window | |
| + /// | |
| + /// \param settings Creation settings | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + HaikuContext(const ContextSettings& settings); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Create a new context attached to a window | |
| + /// | |
| + /// \param settings Creation settings | |
| + /// \param owner Pointer to the owner window | |
| + /// \param bitsPerPixel Bits per pixel | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + HaikuContext(const ContextSettings& settings, const WindowImpl* owner, unsigned int bitsPerPixel); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Create a new context that shares its settings with another | |
| + /// | |
| + /// \param settings Creation settings | |
| + /// \param shared Context to share the settings with | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + HaikuContext(const ContextSettings& settings, const GlContext* shared); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Destructor | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + ~HaikuContext(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Get the address of an OpenGL function | |
| + /// | |
| + /// \param name Name of the function to get the address of | |
| + /// | |
| + /// \return Address of the OpenGL function, 0 on failure | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + static GlFunctionPointer getFunction(const char* name); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Activate or deactivate the context as the current target | |
| + /// for rendering | |
| + /// | |
| + /// \param current True to activate, false to deactivate | |
| + /// | |
| + /// \return True on success, false on failure | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + bool makeCurrent(bool current) override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Display what has been rendered to the context so far | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void display() override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Enable or disable vertical synchronization | |
| + /// | |
| + /// \param enabled: True to enable v-sync, false to disable | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void setVerticalSyncEnabled(bool enabled) override; | |
| + | |
| +private: | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Create the context | |
| + /// | |
| + /// \param owner Window to attach the context to | |
| + /// \param bitsPerPixel BPP | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void createContext(const WindowImpl* owner, unsigned int bitsPerPixel); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + // Member data | |
| + //////////////////////////////////////////////////////////// | |
| + BGLView* m_view; //!< The BGLView | |
| +}; | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/InputImpl.cpp b/src/SFML/Window/Haiku/InputImpl.cpp | |
| new file mode 100644 | |
| index 00000000..928f5137 | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/InputImpl.cpp | |
| @@ -0,0 +1,165 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Haiku/Utils.hpp> | |
| +#include <SFML/Window/InputImpl.hpp> | |
| +#include <SFML/Window/WindowBase.hpp> | |
| +#include <SFML/Window/WindowImpl.hpp> | |
| + | |
| +#include <SFML/System/String.hpp> | |
| +#include <SFML/System/Vector2.hpp> | |
| + | |
| +#include <InterfaceDefs.h> | |
| +#include <Screen.h> | |
| +#include <View.h> | |
| +#include <Window.h> | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +namespace InputImpl | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +bool isKeyPressed(Keyboard::Key key) | |
| +{ | |
| + key_info info; | |
| + if (get_key_info(&info) == B_OK) | |
| + { | |
| + std::uint32_t haikuKey = keyToHaiku(key); | |
| + if (haikuKey != 0) | |
| + { | |
| + return (info.key_states[haikuKey / 8] & (1 << (7 - (haikuKey % 8)))) != 0; | |
| + } | |
| + } | |
| + return false; | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +bool isKeyPressed(Keyboard::Scancode code) | |
| +{ | |
| + // Scancode support requires delocalizing or specific Haiku mapping | |
| + return isKeyPressed(localize(code)); | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +Keyboard::Key localize(Keyboard::Scancode code) | |
| +{ | |
| + // Stub | |
| + return Keyboard::Key::Unknown; | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +Keyboard::Scancode delocalize(Keyboard::Key key) | |
| +{ | |
| + // Stub | |
| + return Keyboard::Scancode::Unknown; | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +String getDescription(Keyboard::Scancode code) | |
| +{ | |
| + return ""; | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +bool isMouseButtonPressed(Mouse::Button button) | |
| +{ | |
| + return false; // TODO: Implement global mouse check | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +Vector2i getMousePosition() | |
| +{ | |
| + return Vector2i(0, 0); | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +Vector2i getMousePosition(const WindowBase& relativeTo) | |
| +{ | |
| + // WindowBase handle is a BWindow pointer | |
| + BWindow* win = reinterpret_cast<BWindow*>(relativeTo.getNativeHandle()); | |
| + if (win && win->Lock()) | |
| + { | |
| + BPoint p; | |
| + uint32 b; | |
| + BView* view = win->ChildAt(0); | |
| + if (view) | |
| + { | |
| + view->GetMouse(&p, &b, false); | |
| + win->Unlock(); | |
| + return Vector2i(static_cast<int>(p.x), static_cast<int>(p.y)); | |
| + } | |
| + win->Unlock(); | |
| + } | |
| + return Vector2i(0, 0); | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void setMousePosition(Vector2i position) | |
| +{ | |
| + set_mouse_position(static_cast<int32>(position.x), static_cast<int32>(position.y)); | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void setMousePosition(Vector2i position, const WindowBase& relativeTo) | |
| +{ | |
| + BWindow* win = reinterpret_cast<BWindow*>(relativeTo.getNativeHandle()); | |
| + if (win && win->Lock()) | |
| + { | |
| + BPoint winPos = win->Frame().LeftTop(); | |
| + win->Unlock(); | |
| + set_mouse_position(static_cast<int32>(winPos.x + position.x), static_cast<int32>(winPos.y + position.y)); | |
| + } | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +bool isTouchDown(unsigned int finger) | |
| +{ | |
| + return false; | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +Vector2i getTouchPosition(unsigned int finger) | |
| +{ | |
| + return Vector2i(0, 0); | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +Vector2i getTouchPosition(unsigned int finger, const WindowBase& relativeTo) | |
| +{ | |
| + return Vector2i(0, 0); | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void setVirtualKeyboardVisible(bool visible) | |
| +{ | |
| +} | |
| + | |
| +} // namespace InputImpl | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/JoystickImpl.cpp b/src/SFML/Window/Haiku/JoystickImpl.cpp | |
| new file mode 100644 | |
| index 00000000..4ea5159e | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/JoystickImpl.cpp | |
| @@ -0,0 +1,166 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Haiku/JoystickImpl.hpp> | |
| + | |
| +#include <SFML/System/Err.hpp> | |
| + | |
| +#include <Storage/Directory.h> | |
| +#include <Storage/Entry.h> | |
| +#include <Storage/Path.h> | |
| + | |
| +#include <cstring> | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +void JoystickImpl::initialize() | |
| +{ | |
| + // Nothing to do | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void JoystickImpl::cleanup() | |
| +{ | |
| + // Nothing to do | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +bool JoystickImpl::isConnected(unsigned int index) | |
| +{ | |
| + // Use BJoystick to check presence | |
| + BJoystick joystick; | |
| + char name[B_OS_NAME_LENGTH]; | |
| + | |
| + // We need to iterate over devices to find the index-th one. | |
| + // Haiku joysticks are usually under /dev/joystick/usb/0, etc. | |
| + // BJoystick::CountDevices() returns the number of devices. | |
| + | |
| + int count = joystick.CountDevices(); | |
| + if (index < (unsigned int)count) | |
| + { | |
| + return true; | |
| + } | |
| + return false; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +bool JoystickImpl::open(unsigned int index) | |
| +{ | |
| + int count = m_joystick.CountDevices(); | |
| + if (index >= (unsigned int)count) | |
| + return false; | |
| + | |
| + // Get the name of the device at index | |
| + if (m_joystick.GetDeviceName(index, m_name) == B_OK) | |
| + { | |
| + if (m_joystick.Open(m_name) == B_OK) | |
| + { | |
| + m_index = index; | |
| + return true; | |
| + } | |
| + } | |
| + | |
| + return false; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void JoystickImpl::close() | |
| +{ | |
| + m_joystick.Close(); | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +JoystickCaps JoystickImpl::getCapabilities() const | |
| +{ | |
| + JoystickCaps caps; | |
| + | |
| + caps.buttonCount = static_cast<unsigned int>(m_joystick.CountButtons()); | |
| + if (caps.buttonCount > Joystick::ButtonCount) | |
| + caps.buttonCount = Joystick::ButtonCount; | |
| + | |
| + int axisCount = m_joystick.CountAxes(); | |
| + for (int i = 0; i < axisCount && i < static_cast<int>(Joystick::AxisCount); ++i) | |
| + { | |
| + caps.axes[static_cast<Joystick::Axis>(i)] = true; | |
| + } | |
| + | |
| + return caps; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +Joystick::Identification JoystickImpl::getIdentification() const | |
| +{ | |
| + Joystick::Identification id; | |
| + id.name = String(m_name); | |
| + | |
| + id.vendorId = 0; | |
| + id.productId = 0; | |
| + | |
| + return id; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +JoystickState JoystickImpl::update() | |
| +{ | |
| + JoystickState state; | |
| + state.connected = true; | |
| + | |
| + if (m_joystick.Update() == B_OK) | |
| + { | |
| + // Axes | |
| + int axisCount = m_joystick.CountAxes(); | |
| + for (int i = 0; i < axisCount && i < static_cast<int>(Joystick::AxisCount); ++i) | |
| + { | |
| + // Haiku returns -32768 to 32767 | |
| + // SFML expects -100 to 100 | |
| + int16 raw = m_joystick.axis_values[i]; | |
| + state.axes[static_cast<Joystick::Axis>(i)] = static_cast<float>(raw) * 100.f / 32767.f; | |
| + } | |
| + | |
| + // Buttons | |
| + uint32 buttons = m_joystick.button_values; | |
| + for (int i = 0; i < static_cast<int>(Joystick::ButtonCount); ++i) | |
| + { | |
| + state.buttons[i] = (buttons & (1 << i)) != 0; | |
| + } | |
| + } | |
| + | |
| + return state; | |
| +} | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/JoystickImpl.hpp b/src/SFML/Window/Haiku/JoystickImpl.hpp | |
| new file mode 100644 | |
| index 00000000..6d5ea338 | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/JoystickImpl.hpp | |
| @@ -0,0 +1,120 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +#pragma once | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Joystick.hpp> | |
| +#include <SFML/Window/JoystickImpl.hpp> | |
| + | |
| +#include <SFML/System/String.hpp> | |
| + | |
| +#include <Device/Joystick.h> | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +/// \brief Haiku implementation of joysticks | |
| +/// | |
| +//////////////////////////////////////////////////////////// | |
| +class JoystickImpl | |
| +{ | |
| +public: | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Perform the global initialization of the joystick module | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + static void initialize(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Perform the global cleanup of the joystick module | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + static void cleanup(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Check if a joystick is currently connected | |
| + /// | |
| + /// \param index Index of the joystick to check | |
| + /// | |
| + /// \return True if the joystick is connected, false otherwise | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + static bool isConnected(unsigned int index); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Open the joystick | |
| + /// | |
| + /// \param index Index of the joystick to open | |
| + /// | |
| + /// \return True on success, false on failure | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + bool open(unsigned int index); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Close the joystick | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void close(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Get the joystick capabilities | |
| + /// | |
| + /// \return Joystick capabilities | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + JoystickCaps getCapabilities() const; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Get the joystick identification | |
| + /// | |
| + /// \return Joystick identification | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + Joystick::Identification getIdentification() const; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Update the joystick and get its new state | |
| + /// | |
| + /// \return Joystick state | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + JoystickState update(); | |
| + | |
| +private: | |
| + //////////////////////////////////////////////////////////// | |
| + // Member data | |
| + //////////////////////////////////////////////////////////// | |
| + BJoystick m_joystick; //!< Haiku joystick object | |
| + char m_name[B_OS_NAME_LENGTH]; //!< Joystick name | |
| + int m_index; //!< Index of the joystick | |
| +}; | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/SensorImpl.cpp b/src/SFML/Window/Haiku/SensorImpl.cpp | |
| new file mode 100644 | |
| index 00000000..f8cf6b7e | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/SensorImpl.cpp | |
| @@ -0,0 +1,85 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Haiku/SensorImpl.hpp> | |
| + | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +void SensorImpl::initialize() | |
| +{ | |
| + // Nothing to do | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void SensorImpl::cleanup() | |
| +{ | |
| + // Nothing to do | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +bool SensorImpl::isAvailable(Sensor::Type) | |
| +{ | |
| + // No standard sensor support on Haiku | |
| + return false; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +bool SensorImpl::open(Sensor::Type) | |
| +{ | |
| + return false; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void SensorImpl::close() | |
| +{ | |
| + // Nothing to do | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +Vector3f SensorImpl::update() | |
| +{ | |
| + return Vector3f(0, 0, 0); | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void SensorImpl::setEnabled(bool) | |
| +{ | |
| + // Nothing to do | |
| +} | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/SensorImpl.hpp b/src/SFML/Window/Haiku/SensorImpl.hpp | |
| new file mode 100644 | |
| index 00000000..d4f1f7c2 | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/SensorImpl.hpp | |
| @@ -0,0 +1,101 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +#pragma once | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Sensor.hpp> | |
| +#include <SFML/Window/SensorImpl.hpp> | |
| + | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +/// \brief Haiku implementation of sensors | |
| +/// | |
| +//////////////////////////////////////////////////////////// | |
| +class SensorImpl | |
| +{ | |
| +public: | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Perform the global initialization of the sensor module | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + static void initialize(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Perform the global cleanup of the sensor module | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + static void cleanup(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Check if a sensor is available | |
| + /// | |
| + /// \param sensor Sensor to check | |
| + /// | |
| + /// \return True if the sensor is available, false otherwise | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + static bool isAvailable(Sensor::Type sensor); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Open the sensor | |
| + /// | |
| + /// \param sensor Sensor to open | |
| + /// | |
| + /// \return True on success, false on failure | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + bool open(Sensor::Type sensor); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Close the sensor | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void close(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Update the sensor and get its new value | |
| + /// | |
| + /// \return Sensor value | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + Vector3f update(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Enable or disable the sensor | |
| + /// | |
| + /// \param enabled True to enable, false to disable | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void setEnabled(bool enabled); | |
| +}; | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/Utils.cpp b/src/SFML/Window/Haiku/Utils.cpp | |
| new file mode 100644 | |
| index 00000000..6b71c49d | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/Utils.cpp | |
| @@ -0,0 +1,416 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Haiku/Utils.hpp> | |
| + | |
| +#include <InterfaceDefs.h> | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +Keyboard::Key keyToSf(std::uint32_t key) | |
| +{ | |
| + // Key codes from Haiku's InterfaceDefs.h | |
| + switch (key) | |
| + { | |
| + case B_ESCAPE: | |
| + return Keyboard::Key::Escape; | |
| + case B_F1_KEY: | |
| + return Keyboard::Key::F1; | |
| + case B_F2_KEY: | |
| + return Keyboard::Key::F2; | |
| + case B_F3_KEY: | |
| + return Keyboard::Key::F3; | |
| + case B_F4_KEY: | |
| + return Keyboard::Key::F4; | |
| + case B_F5_KEY: | |
| + return Keyboard::Key::F5; | |
| + case B_F6_KEY: | |
| + return Keyboard::Key::F6; | |
| + case B_F7_KEY: | |
| + return Keyboard::Key::F7; | |
| + case B_F8_KEY: | |
| + return Keyboard::Key::F8; | |
| + case B_F9_KEY: | |
| + return Keyboard::Key::F9; | |
| + case B_F10_KEY: | |
| + return Keyboard::Key::F10; | |
| + case B_F11_KEY: | |
| + return Keyboard::Key::F11; | |
| + case B_F12_KEY: | |
| + return Keyboard::Key::F12; | |
| + case 0x11: | |
| + return Keyboard::Key::Grave; // Tilde | |
| + case 0x12: | |
| + return Keyboard::Key::Num1; | |
| + case 0x13: | |
| + return Keyboard::Key::Num2; | |
| + case 0x14: | |
| + return Keyboard::Key::Num3; | |
| + case 0x15: | |
| + return Keyboard::Key::Num4; | |
| + case 0x16: | |
| + return Keyboard::Key::Num5; | |
| + case 0x17: | |
| + return Keyboard::Key::Num6; | |
| + case 0x18: | |
| + return Keyboard::Key::Num7; | |
| + case 0x19: | |
| + return Keyboard::Key::Num8; | |
| + case 0x1a: | |
| + return Keyboard::Key::Num9; | |
| + case 0x1b: | |
| + return Keyboard::Key::Num0; | |
| + case 0x1c: | |
| + return Keyboard::Key::Hyphen; | |
| + case 0x1d: | |
| + return Keyboard::Key::Equal; | |
| + case 0x1e: | |
| + return Keyboard::Key::Backspace; | |
| + case 0x26: | |
| + return Keyboard::Key::Tab; | |
| + case 0x27: | |
| + return Keyboard::Key::Q; | |
| + case 0x28: | |
| + return Keyboard::Key::W; | |
| + case 0x29: | |
| + return Keyboard::Key::E; | |
| + case 0x2a: | |
| + return Keyboard::Key::R; | |
| + case 0x2b: | |
| + return Keyboard::Key::T; | |
| + case 0x2c: | |
| + return Keyboard::Key::Y; | |
| + case 0x2d: | |
| + return Keyboard::Key::U; | |
| + case 0x2e: | |
| + return Keyboard::Key::I; | |
| + case 0x2f: | |
| + return Keyboard::Key::O; | |
| + case 0x30: | |
| + return Keyboard::Key::P; | |
| + case 0x31: | |
| + return Keyboard::Key::LBracket; | |
| + case 0x32: | |
| + return Keyboard::Key::RBracket; | |
| + case 0x33: | |
| + return Keyboard::Key::Backslash; | |
| + case 0x3b: | |
| + return Keyboard::Key::CapsLock; | |
| + case 0x3c: | |
| + return Keyboard::Key::A; | |
| + case 0x3d: | |
| + return Keyboard::Key::S; | |
| + case 0x3e: | |
| + return Keyboard::Key::D; | |
| + case 0x3f: | |
| + return Keyboard::Key::F; | |
| + case 0x40: | |
| + return Keyboard::Key::G; | |
| + case 0x41: | |
| + return Keyboard::Key::H; | |
| + case 0x42: | |
| + return Keyboard::Key::J; | |
| + case 0x43: | |
| + return Keyboard::Key::K; | |
| + case 0x44: | |
| + return Keyboard::Key::L; | |
| + case 0x45: | |
| + return Keyboard::Key::Semicolon; | |
| + case 0x46: | |
| + return Keyboard::Key::Apostrophe; | |
| + case 0x47: | |
| + return Keyboard::Key::Enter; | |
| + case 0x4b: | |
| + return Keyboard::Key::LShift; | |
| + case 0x4c: | |
| + return Keyboard::Key::Z; | |
| + case 0x4d: | |
| + return Keyboard::Key::X; | |
| + case 0x4e: | |
| + return Keyboard::Key::C; | |
| + case 0x4f: | |
| + return Keyboard::Key::V; | |
| + case 0x50: | |
| + return Keyboard::Key::B; | |
| + case 0x51: | |
| + return Keyboard::Key::N; | |
| + case 0x52: | |
| + return Keyboard::Key::M; | |
| + case 0x53: | |
| + return Keyboard::Key::Comma; | |
| + case 0x54: | |
| + return Keyboard::Key::Period; | |
| + case 0x55: | |
| + return Keyboard::Key::Slash; | |
| + case 0x56: | |
| + return Keyboard::Key::RShift; | |
| + case 0x5c: | |
| + return Keyboard::Key::LControl; | |
| + case 0x66: | |
| + return Keyboard::Key::LSystem; // Command/Option | |
| + case 0x5d: | |
| + return Keyboard::Key::LAlt; | |
| + case 0x5e: | |
| + return Keyboard::Key::Space; | |
| + case 0x5f: | |
| + return Keyboard::Key::RAlt; | |
| + case 0x67: | |
| + return Keyboard::Key::RSystem; // Command/Option | |
| + // case 0x60: return Keyboard::Key::RControl; // No specific RControl in keymap usually, handled as Control | |
| + case B_PRINT_KEY: | |
| + return Keyboard::Key::PrintScreen; | |
| + case B_SCROLL_KEY: | |
| + return Keyboard::Key::ScrollLock; | |
| + case B_PAUSE_KEY: | |
| + return Keyboard::Key::Pause; | |
| + case B_INSERT: | |
| + return Keyboard::Key::Insert; | |
| + case B_HOME: | |
| + return Keyboard::Key::Home; | |
| + case B_PAGE_UP: | |
| + return Keyboard::Key::PageUp; | |
| + case 0x34: | |
| + return Keyboard::Key::Delete; | |
| + case B_END: | |
| + return Keyboard::Key::End; | |
| + case B_PAGE_DOWN: | |
| + return Keyboard::Key::PageDown; | |
| + case B_UP_ARROW: | |
| + return Keyboard::Key::Up; | |
| + case B_LEFT_ARROW: | |
| + return Keyboard::Key::Left; | |
| + case B_DOWN_ARROW: | |
| + return Keyboard::Key::Down; | |
| + case B_RIGHT_ARROW: | |
| + return Keyboard::Key::Right; | |
| + case 0x37: | |
| + return Keyboard::Key::NumpadDivide; | |
| + case 0x38: | |
| + return Keyboard::Key::NumpadMultiply; | |
| + case 0x39: | |
| + return Keyboard::Key::NumpadMinus; | |
| + case 0x25: | |
| + return Keyboard::Key::NumpadPlus; | |
| + case 0x64: | |
| + return Keyboard::Key::NumpadEnter; | |
| + case 0x65: | |
| + return Keyboard::Key::NumpadDecimal; // Period | |
| + case 0x3a: | |
| + return Keyboard::Key::Numpad1; // BeOS numeric keypad? | |
| + case 0x58: | |
| + return Keyboard::Key::Numpad0; | |
| + // ... incomplete numpad map, using best guess standards for PC keyboards on Haiku | |
| + default: | |
| + return Keyboard::Key::Unknown; | |
| + } | |
| +} | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +std::uint32_t keyToHaiku(Keyboard::Key key) | |
| +{ | |
| + switch (key) | |
| + { | |
| + case Keyboard::Key::Escape: | |
| + return B_ESCAPE; | |
| + case Keyboard::Key::F1: | |
| + return B_F1_KEY; | |
| + case Keyboard::Key::F2: | |
| + return B_F2_KEY; | |
| + case Keyboard::Key::F3: | |
| + return B_F3_KEY; | |
| + case Keyboard::Key::F4: | |
| + return B_F4_KEY; | |
| + case Keyboard::Key::F5: | |
| + return B_F5_KEY; | |
| + case Keyboard::Key::F6: | |
| + return B_F6_KEY; | |
| + case Keyboard::Key::F7: | |
| + return B_F7_KEY; | |
| + case Keyboard::Key::F8: | |
| + return B_F8_KEY; | |
| + case Keyboard::Key::F9: | |
| + return B_F9_KEY; | |
| + case Keyboard::Key::F10: | |
| + return B_F10_KEY; | |
| + case Keyboard::Key::F11: | |
| + return B_F11_KEY; | |
| + case Keyboard::Key::F12: | |
| + return B_F12_KEY; | |
| + case Keyboard::Key::Grave: | |
| + return 0x11; | |
| + case Keyboard::Key::Num1: | |
| + return 0x12; | |
| + case Keyboard::Key::Num2: | |
| + return 0x13; | |
| + case Keyboard::Key::Num3: | |
| + return 0x14; | |
| + case Keyboard::Key::Num4: | |
| + return 0x15; | |
| + case Keyboard::Key::Num5: | |
| + return 0x16; | |
| + case Keyboard::Key::Num6: | |
| + return 0x17; | |
| + case Keyboard::Key::Num7: | |
| + return 0x18; | |
| + case Keyboard::Key::Num8: | |
| + return 0x19; | |
| + case Keyboard::Key::Num9: | |
| + return 0x1a; | |
| + case Keyboard::Key::Num0: | |
| + return 0x1b; | |
| + case Keyboard::Key::Hyphen: | |
| + return 0x1c; | |
| + case Keyboard::Key::Equal: | |
| + return 0x1d; | |
| + case Keyboard::Key::Backspace: | |
| + return 0x1e; | |
| + case Keyboard::Key::Tab: | |
| + return 0x26; | |
| + case Keyboard::Key::Q: | |
| + return 0x27; | |
| + case Keyboard::Key::W: | |
| + return 0x28; | |
| + case Keyboard::Key::E: | |
| + return 0x29; | |
| + case Keyboard::Key::R: | |
| + return 0x2a; | |
| + case Keyboard::Key::T: | |
| + return 0x2b; | |
| + case Keyboard::Key::Y: | |
| + return 0x2c; | |
| + case Keyboard::Key::U: | |
| + return 0x2d; | |
| + case Keyboard::Key::I: | |
| + return 0x2e; | |
| + case Keyboard::Key::O: | |
| + return 0x2f; | |
| + case Keyboard::Key::P: | |
| + return 0x30; | |
| + case Keyboard::Key::LBracket: | |
| + return 0x31; | |
| + case Keyboard::Key::RBracket: | |
| + return 0x32; | |
| + case Keyboard::Key::Backslash: | |
| + return 0x33; | |
| + case Keyboard::Key::CapsLock: | |
| + return 0x3b; | |
| + case Keyboard::Key::A: | |
| + return 0x3c; | |
| + case Keyboard::Key::S: | |
| + return 0x3d; | |
| + case Keyboard::Key::D: | |
| + return 0x3e; | |
| + case Keyboard::Key::F: | |
| + return 0x3f; | |
| + case Keyboard::Key::G: | |
| + return 0x40; | |
| + case Keyboard::Key::H: | |
| + return 0x41; | |
| + case Keyboard::Key::J: | |
| + return 0x42; | |
| + case Keyboard::Key::K: | |
| + return 0x43; | |
| + case Keyboard::Key::L: | |
| + return 0x44; | |
| + case Keyboard::Key::Semicolon: | |
| + return 0x45; | |
| + case Keyboard::Key::Apostrophe: | |
| + return 0x46; | |
| + case Keyboard::Key::Enter: | |
| + return 0x47; | |
| + case Keyboard::Key::LShift: | |
| + return 0x4b; | |
| + case Keyboard::Key::Z: | |
| + return 0x4c; | |
| + case Keyboard::Key::X: | |
| + return 0x4d; | |
| + case Keyboard::Key::C: | |
| + return 0x4e; | |
| + case Keyboard::Key::V: | |
| + return 0x4f; | |
| + case Keyboard::Key::B: | |
| + return 0x50; | |
| + case Keyboard::Key::N: | |
| + return 0x51; | |
| + case Keyboard::Key::M: | |
| + return 0x52; | |
| + case Keyboard::Key::Comma: | |
| + return 0x53; | |
| + case Keyboard::Key::Period: | |
| + return 0x54; | |
| + case Keyboard::Key::Slash: | |
| + return 0x55; | |
| + case Keyboard::Key::RShift: | |
| + return 0x56; | |
| + case Keyboard::Key::LControl: | |
| + return 0x5c; | |
| + case Keyboard::Key::LSystem: | |
| + return 0x66; | |
| + case Keyboard::Key::LAlt: | |
| + return 0x5d; | |
| + case Keyboard::Key::Space: | |
| + return 0x5e; | |
| + case Keyboard::Key::RAlt: | |
| + return 0x5f; | |
| + case Keyboard::Key::RSystem: | |
| + return 0x67; | |
| + case Keyboard::Key::PrintScreen: | |
| + return B_PRINT_KEY; | |
| + case Keyboard::Key::ScrollLock: | |
| + return B_SCROLL_KEY; | |
| + case Keyboard::Key::Pause: | |
| + return B_PAUSE_KEY; | |
| + case Keyboard::Key::Insert: | |
| + return B_INSERT; | |
| + case Keyboard::Key::Home: | |
| + return B_HOME; | |
| + case Keyboard::Key::PageUp: | |
| + return B_PAGE_UP; | |
| + case Keyboard::Key::Delete: | |
| + return 0x34; | |
| + case Keyboard::Key::End: | |
| + return B_END; | |
| + case Keyboard::Key::PageDown: | |
| + return B_PAGE_DOWN; | |
| + case Keyboard::Key::Up: | |
| + return B_UP_ARROW; | |
| + case Keyboard::Key::Left: | |
| + return B_LEFT_ARROW; | |
| + case Keyboard::Key::Down: | |
| + return B_DOWN_ARROW; | |
| + case Keyboard::Key::Right: | |
| + return B_RIGHT_ARROW; | |
| + default: | |
| + return 0; | |
| + } | |
| +} | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/Utils.hpp b/src/SFML/Window/Haiku/Utils.hpp | |
| new file mode 100644 | |
| index 00000000..12e7db08 | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/Utils.hpp | |
| @@ -0,0 +1,59 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +#pragma once | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Keyboard.hpp> | |
| + | |
| +#include <cstdint> | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +/// \brief Convert a Haiku key code to a SFML key code | |
| +/// | |
| +/// \param key Haiku key code | |
| +/// | |
| +/// \return SFML key code | |
| +/// | |
| +//////////////////////////////////////////////////////////// | |
| +Keyboard::Key keyToSf(std::uint32_t key); | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +/// \brief Convert a SFML key code to a Haiku key code | |
| +/// | |
| +/// \param key SFML key code | |
| +/// | |
| +/// \return Haiku key code | |
| +/// | |
| +//////////////////////////////////////////////////////////// | |
| +std::uint32_t keyToHaiku(Keyboard::Key key); | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/VideoModeImpl.cpp b/src/SFML/Window/Haiku/VideoModeImpl.cpp | |
| new file mode 100644 | |
| index 00000000..3bdea9e9 | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/VideoModeImpl.cpp | |
| @@ -0,0 +1,171 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/VideoModeImpl.hpp> | |
| + | |
| +#include <SFML/System/Err.hpp> | |
| + | |
| +#include <Screen.h> | |
| + | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +std::vector<VideoMode> VideoModeImpl::getFullscreenModes() | |
| +{ | |
| + std::vector<VideoMode> modes; | |
| + | |
| + BScreen screen; | |
| + if (!screen.IsValid()) | |
| + { | |
| + err() << "Failed to retrieve fullscreen modes: Invalid BScreen" << std::endl; | |
| + return modes; | |
| + } | |
| + | |
| + display_mode mode; | |
| + // Iterate over all modes | |
| + // GetModeList(display_mode* list, uint32 count) | |
| + | |
| + // Easier way: | |
| + // count_modes, get_mode_list not available in BScreen class directly? | |
| + // It is `BScreen::GetModeList(display_mode**, uint32*)`. | |
| + | |
| + display_mode* modeList = NULL; | |
| + uint32 count = 0; | |
| + | |
| + if (screen.GetModeList(&modeList, &count) == B_OK) | |
| + { | |
| + for (uint32 i = 0; i < count; ++i) | |
| + { | |
| + // Convert to VideoMode | |
| + // Logic to check bits per pixel? | |
| + // B_RGB32, B_RGB16, etc. | |
| + | |
| + unsigned int bpp = 0; | |
| + switch (modeList[i].space) | |
| + { | |
| + case B_RGB32: | |
| + bpp = 32; | |
| + break; | |
| + case B_RGBA32: | |
| + bpp = 32; | |
| + break; | |
| + case B_RGB24: | |
| + bpp = 24; | |
| + break; | |
| + case B_RGB15: | |
| + bpp = 15; | |
| + break; // 15 or 16? usually 15 + 1 alpha bit or just 15 | |
| + case B_RGBA15: | |
| + bpp = 16; | |
| + break; | |
| + case B_RGB16: | |
| + bpp = 16; | |
| + break; | |
| + case B_CMAP8: | |
| + bpp = 8; | |
| + break; | |
| + default: | |
| + break; | |
| + } | |
| + | |
| + if (bpp > 0) | |
| + { | |
| + VideoMode vm({static_cast<unsigned int>(modeList[i].virtual_width), | |
| + static_cast<unsigned int>(modeList[i].virtual_height)}, | |
| + bpp); | |
| + // Check for duplicates | |
| + bool found = false; | |
| + for (const auto& existing : modes) | |
| + { | |
| + if (existing == vm) | |
| + { | |
| + found = true; | |
| + break; | |
| + } | |
| + } | |
| + | |
| + if (!found) | |
| + modes.push_back(vm); | |
| + } | |
| + } | |
| + | |
| + free(modeList); // Haiku BScreen::GetModeList allocates with malloc | |
| + } | |
| + | |
| + return modes; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +VideoMode VideoModeImpl::getDesktopMode() | |
| +{ | |
| + BScreen screen; | |
| + if (screen.IsValid()) | |
| + { | |
| + display_mode mode; | |
| + if (screen.GetMode(&mode) == B_OK) | |
| + { | |
| + unsigned int bpp = 0; | |
| + switch (mode.space) | |
| + { | |
| + case B_RGB32: | |
| + bpp = 32; | |
| + break; | |
| + case B_RGBA32: | |
| + bpp = 32; | |
| + break; | |
| + case B_RGB24: | |
| + bpp = 24; | |
| + break; | |
| + case B_RGB15: | |
| + bpp = 15; | |
| + break; | |
| + case B_RGBA15: | |
| + bpp = 16; | |
| + break; | |
| + case B_RGB16: | |
| + bpp = 16; | |
| + break; | |
| + case B_CMAP8: | |
| + bpp = 8; | |
| + break; | |
| + default: | |
| + break; | |
| + } | |
| + return VideoMode({static_cast<unsigned int>(mode.virtual_width), static_cast<unsigned int>(mode.virtual_height)}, | |
| + bpp); | |
| + } | |
| + } | |
| + | |
| + return VideoMode({0, 0}, 0); | |
| +} | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/WindowImplHaiku.cpp b/src/SFML/Window/Haiku/WindowImplHaiku.cpp | |
| new file mode 100644 | |
| index 00000000..ac333806 | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/WindowImplHaiku.cpp | |
| @@ -0,0 +1,689 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Event.hpp> | |
| +#include <SFML/Window/Haiku/Utils.hpp> | |
| +#include <SFML/Window/Haiku/WindowImplHaiku.hpp> | |
| + | |
| +#include <SFML/System/Err.hpp> | |
| + | |
| +#include <Application.h> | |
| +#include <Bitmap.h> | |
| +#include <DirectWindow.h> | |
| +#include <Message.h> | |
| +#include <Screen.h> | |
| +#include <View.h> | |
| +#include <Window.h> | |
| +#include <mutex> | |
| +#include <queue> | |
| + | |
| +#include <cstring> | |
| + | |
| +// Define a custom BWindow subclass to handle events | |
| +class SFWindow : public BDirectWindow | |
| +{ | |
| +public: | |
| + SFWindow(BRect frame, const char* title, uint32 flags) : | |
| + BDirectWindow(frame, title, B_TITLED_WINDOW, flags), | |
| + m_sfmlWindow(NULL) | |
| + { | |
| + } | |
| + | |
| + void SetSFMLWindow(sf::priv::WindowImplHaiku* window) | |
| + { | |
| + m_sfmlWindow = window; | |
| + } | |
| + | |
| + // Event handling | |
| + bool QuitRequested() override | |
| + { | |
| + if (m_sfmlWindow) | |
| + { | |
| + sf::Event event; | |
| + event.type = sf::Event::Closed; | |
| + PushEvent(event); | |
| + return false; // Don't close automatically, let SFML handle it | |
| + // Actually, SFML expects the window to close when requested or when user manages it. | |
| + // BWindow's QuitRequested closes the window if true. | |
| + // If we return false, we must handle closing ourselves via window.close(). | |
| + // Correct for SFML is to send Closed event and NOT close immediately. | |
| + } | |
| + return true; | |
| + } | |
| + | |
| + void WindowActivated(bool active) override | |
| + { | |
| + if (m_sfmlWindow) | |
| + { | |
| + sf::Event event; | |
| + event.type = active ? sf::Event::GainedFocus : sf::Event::LostFocus; | |
| + PushEvent(event); | |
| + } | |
| + } | |
| + | |
| + void FrameMoved(BPoint origin) override | |
| + { | |
| + if (m_sfmlWindow) | |
| + { | |
| + sf::Event event; | |
| + event.type = sf::Event::Moved; | |
| + event.move.x = (int)origin.x; | |
| + event.move.y = (int)origin.y; | |
| + PushEvent(event); | |
| + } | |
| + } | |
| + | |
| + void FrameResized(float width, float height) override | |
| + { | |
| + if (m_sfmlWindow) | |
| + { | |
| + sf::Event event; | |
| + event.type = sf::Event::Resized; | |
| + event.size.width = (unsigned int)(width + 1); // width is right - left, so +1? BRect definition: right - left. | |
| + // Wait, BRect(0,0,10,10) has width 10? No, 10. | |
| + // FrameResized params are width and height delta? No, new width and height (content area). | |
| + event.size.height = (unsigned int)(height + 1); | |
| + PushEvent(event); | |
| + } | |
| + } | |
| + | |
| + void MessageReceived(BMessage* message) override | |
| + { | |
| + if (!m_sfmlWindow) | |
| + { | |
| + BDirectWindow::MessageReceived(message); | |
| + return; | |
| + } | |
| + | |
| + switch (message->what) | |
| + { | |
| + case B_KEY_DOWN: | |
| + case B_UNMAPPED_KEY_DOWN: | |
| + { | |
| + int32 key; | |
| + if (message->FindInt32("key", &key) == B_OK) // raw key code | |
| + { | |
| + // Convert to SFML key | |
| + // B_KEY_DOWN raw key code is "key". | |
| + // But "raw_char" or "byte" might be needed? | |
| + // "key" is the scancode usually? unique code. | |
| + | |
| + // Actually, keyToSf expects the raw key code (which is what we mapped in Utils.cpp). | |
| + // Wait, Utils.cpp mapped B_ESCAPE (0x01) etc. which are ASCII often? No, B_ESCAPE is defined in InterfaceDefs.h. | |
| + // Let's check Utils.cpp again. | |
| + // It maps things like 0x11, 0x12... these correspond to Haiku raw key codes (scancodes). | |
| + // So "key" field from B_KEY_DOWN is correct. | |
| + | |
| + sf::Event event; | |
| + event.type = sf::Event::KeyPressed; | |
| + event.key.code = sf::priv::keyToSf(key); | |
| + event.key.alt = (modifiers() & B_OPTION_KEY) != 0; // Haiku Option is Alt? Or Command? | |
| + // LAlt/RAlt map to B_OPTION_KEY in Haiku? | |
| + // B_COMMAND_KEY (Alt on PC usually, Command on Mac). | |
| + // SFML Alt usually means the Alt key. | |
| + // On Haiku (PC keyboard), Alt is command? | |
| + // Let's stick to B_COMMAND_KEY = Alt logic for compatibility with typical SFML apps? | |
| + // Or B_OPTION_KEY = Alt? | |
| + // Haiku: Alt key is Command usually. Option is Windows key? No. | |
| + // Standard PC: Alt -> Command (B_COMMAND_KEY). Windows -> Option (B_OPTION_KEY). Control -> Control (B_CONTROL_KEY). | |
| + | |
| + event.key.alt = (modifiers() & B_COMMAND_KEY) != 0; | |
| + event.key.control = (modifiers() & B_CONTROL_KEY) != 0; | |
| + event.key.shift = (modifiers() & B_SHIFT_KEY) != 0; | |
| + event.key.system = (modifiers() & B_OPTION_KEY) != 0; // Windows key | |
| + | |
| + PushEvent(event); | |
| + | |
| + // TextEntered | |
| + const char* bytes; | |
| + if (message->FindString("bytes", &bytes) == B_OK) | |
| + { | |
| + // Handle UTF-8 bytes provided by Haiku | |
| + sf::String str = sf::String::fromUtf8(bytes, bytes + strlen(bytes)); | |
| + for (const auto& curChar : str) | |
| + { | |
| + sf::Event textEvent; | |
| + textEvent.type = sf::Event::TextEntered; | |
| + textEvent.text.unicode = curChar; | |
| + PushEvent(textEvent); | |
| + } | |
| + } | |
| + } | |
| + break; | |
| + } | |
| + | |
| + case B_KEY_UP: | |
| + case B_UNMAPPED_KEY_UP: | |
| + { | |
| + int32 key; | |
| + if (message->FindInt32("key", &key) == B_OK) | |
| + { | |
| + sf::Event event; | |
| + event.type = sf::Event::KeyReleased; | |
| + event.key.code = sf::priv::keyToSf(key); | |
| + event.key.alt = (modifiers() & B_COMMAND_KEY) != 0; | |
| + event.key.control = (modifiers() & B_CONTROL_KEY) != 0; | |
| + event.key.shift = (modifiers() & B_SHIFT_KEY) != 0; | |
| + event.key.system = (modifiers() & B_OPTION_KEY) != 0; | |
| + PushEvent(event); | |
| + } | |
| + break; | |
| + } | |
| + | |
| + case B_MOUSE_DOWN: | |
| + { | |
| + sf::Event event; | |
| + event.type = sf::Event::MouseButtonPressed; | |
| + int32 buttons; | |
| + if (message->FindInt32("buttons", &buttons) == B_OK) | |
| + { | |
| + if (buttons & B_PRIMARY_MOUSE_BUTTON) | |
| + event.mouseButton.button = sf::Mouse::Left; | |
| + else if (buttons & B_SECONDARY_MOUSE_BUTTON) | |
| + event.mouseButton.button = sf::Mouse::Right; | |
| + else if (buttons & B_TERTIARY_MOUSE_BUTTON) | |
| + event.mouseButton.button = sf::Mouse::Middle; | |
| + else if (buttons & B_MOUSE_BUTTON(4)) | |
| + event.mouseButton.button = sf::Mouse::XButton1; | |
| + else if (buttons & B_MOUSE_BUTTON(5)) | |
| + event.mouseButton.button = sf::Mouse::XButton2; | |
| + else | |
| + return; // Unknown button | |
| + | |
| + BPoint where; | |
| + if (message->FindPoint("where", &where) == B_OK) | |
| + { | |
| + // Convert where (screen? window?) | |
| + // BWindow message 'where' is usually in window coordinates if passed to a view, | |
| + // but BWindow receives it from App Server. docs say: "coordinate space is undefined" for BWindow? | |
| + // Actually, we usually add a BView to catch mouse events properly. | |
| + // Mouse events go to the view under cursor. | |
| + // If we don't have a view covering content, BWindow might not see it correctly or it's raw. | |
| + // BUT, WindowImplHaiku creates a BView? | |
| + // Let's ensure we forward events from the View to here, OR we just let the window handle it if we make the view a simple pass-through. | |
| + // Better: The SFWindow should have a generic "InputView" that fills the window and catches messages. | |
| + // This class SFWindow handles window messages. | |
| + // Let's create `SFView` inside this file too or just use `BView`. | |
| + // MouseDown is sent to the BView. | |
| + event.mouseButton.x = (int)where.x; | |
| + event.mouseButton.y = (int)where.y; | |
| + PushEvent(event); | |
| + } | |
| + } | |
| + break; | |
| + } | |
| + | |
| + case B_MOUSE_UP: | |
| + { | |
| + sf::Event event; | |
| + event.type = sf::Event::MouseButtonReleased; | |
| + int32 buttons; | |
| + // B_MOUSE_UP doesn't always contain "buttons" field with the button released, it contains *current* buttons (which might be 0). | |
| + // We might need to track state or assume. | |
| + // Actually, "buttons" in Message is state after event? | |
| + // Let's assume Left for now if not present or try to deduce? | |
| + // Wait, `B_MOUSE_UP` is usually sent to the view. | |
| + // Let's handle it in the `SFView` class logic if possible. | |
| + // For now, assume we get it. | |
| + event.mouseButton.button = sf::Mouse::Left; // Fallback | |
| + BPoint where; | |
| + if (message->FindPoint("where", &where) == B_OK) | |
| + { | |
| + event.mouseButton.x = (int)where.x; | |
| + event.mouseButton.y = (int)where.y; | |
| + } | |
| + PushEvent(event); | |
| + break; | |
| + } | |
| + | |
| + case B_MOUSE_MOVED: | |
| + { | |
| + sf::Event event; | |
| + event.type = sf::Event::MouseMoved; | |
| + BPoint where; | |
| + if (message->FindPoint("where", &where) == B_OK) | |
| + { | |
| + event.mouseMove.x = (int)where.x; | |
| + event.mouseMove.y = (int)where.y; | |
| + PushEvent(event); | |
| + } | |
| + break; | |
| + } | |
| + | |
| + case B_MOUSE_WHEEL_CHANGED: | |
| + { | |
| + sf::Event event; | |
| + event.type = sf::Event::MouseWheelScrolled; | |
| + float deltaY; | |
| + if (message->FindFloat("be:wheel_delta_y", &deltaY) == B_OK) | |
| + { | |
| + event.mouseWheelScroll.wheel = sf::Mouse::VerticalWheel; | |
| + event.mouseWheelScroll.delta = -deltaY; // Invert? Haiku down is positive? | |
| + event.mouseWheelScroll.x = 0; // Need mouse pos... check "where"? | |
| + event.mouseWheelScroll.y = 0; | |
| + PushEvent(event); | |
| + } | |
| + float deltaX; | |
| + if (message->FindFloat("be:wheel_delta_x", &deltaX) == B_OK) | |
| + { | |
| + event.mouseWheelScroll.wheel = sf::Mouse::HorizontalWheel; | |
| + event.mouseWheelScroll.delta = deltaX; | |
| + event.mouseWheelScroll.x = 0; | |
| + event.mouseWheelScroll.y = 0; | |
| + PushEvent(event); | |
| + } | |
| + break; | |
| + } | |
| + | |
| + default: | |
| + BDirectWindow::MessageReceived(message); | |
| + break; | |
| + } | |
| + } | |
| + | |
| + void PushEvent(const sf::Event& event) | |
| + { | |
| + // Add to queue safely | |
| + m_mutex.lock(); | |
| + m_events.push(event); | |
| + m_mutex.unlock(); | |
| + } | |
| + | |
| + // Helper to retrieve events from the window thread | |
| + bool PopEvent(sf::Event& event) | |
| + { | |
| + std::lock_guard<std::mutex> lock(m_mutex); | |
| + if (m_events.empty()) | |
| + return false; | |
| + event = m_events.front(); | |
| + m_events.pop(); | |
| + return true; | |
| + } | |
| + | |
| +private: | |
| + sf::priv::WindowImplHaiku* m_sfmlWindow; | |
| + std::queue<sf::Event> m_events; | |
| + std::mutex m_mutex; | |
| +}; | |
| + | |
| + | |
| +// SFView Implementation (to catch mouse events properly) | |
| +class SFView : public BView | |
| +{ | |
| +public: | |
| + SFView(BRect frame, SFWindow* window) : | |
| + BView(frame, "SFView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE), | |
| + m_window(window) | |
| + { | |
| + } | |
| + | |
| + void MouseDown(BPoint where) override | |
| + { | |
| + BMessage* msg = Window()->CurrentMessage(); | |
| + if (msg) | |
| + { | |
| + // Forward to window or handle here | |
| + // We can manually construct a message or just invoke base logic which might send to window? | |
| + // Actually, we can just call m_window->MessageReceived(msg); | |
| + // But we shouldn't steal it if BWindow doesn't expect it? | |
| + // BWindow usually dispatches to View. | |
| + // So we should call m_window->MessageReceived(msg) carefully. | |
| + // Or better: Just process it here and push to window's queue. | |
| + m_window->MessageReceived(msg); | |
| + } | |
| + } | |
| + | |
| + void MouseUp(BPoint where) override | |
| + { | |
| + // BView doesn't always receive MouseUp unless it captures mouse. | |
| + // But MouseDown + SetMouseEventMask is typical. | |
| + BMessage* msg = Window()->CurrentMessage(); | |
| + if (msg) | |
| + m_window->MessageReceived(msg); | |
| + } | |
| + | |
| + void MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage) override | |
| + { | |
| + BMessage* msg = Window()->CurrentMessage(); | |
| + if (msg) | |
| + m_window->MessageReceived((BMessage*)msg); | |
| + } | |
| + | |
| + void KeyDown(const char* bytes, int32 numBytes) override | |
| + { | |
| + BMessage* msg = Window()->CurrentMessage(); | |
| + if (msg) | |
| + m_window->MessageReceived(msg); | |
| + } | |
| + | |
| + void KeyUp(const char* bytes, int32 numBytes) override | |
| + { | |
| + BMessage* msg = Window()->CurrentMessage(); | |
| + if (msg) | |
| + m_window->MessageReceived(msg); | |
| + } | |
| + | |
| +private: | |
| + SFWindow* m_window; | |
| +}; | |
| + | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +WindowImplHaiku::WindowImplHaiku(WindowHandle handle) : | |
| +m_window(NULL), | |
| +m_view(NULL), | |
| +m_ownsWindow(false), | |
| +m_keyRepeatEnabled(true) | |
| +{ | |
| + // Adopt existing window | |
| + if (handle) | |
| + { | |
| + m_window = (BWindow*)handle; | |
| + // Check if we can/should attach a view? | |
| + m_ownsWindow = false; | |
| + } | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +WindowImplHaiku::WindowImplHaiku(VideoMode mode, const String& title, std::uint32_t style, const ContextSettings& settings) : | |
| +m_window(NULL), | |
| +m_view(NULL), | |
| +m_ownsWindow(true), | |
| +m_keyRepeatEnabled(true) | |
| +{ | |
| + // Create BWindow | |
| + BRect frame(0, 0, (float)mode.size.x - 1, (float)mode.size.y - 1); | |
| + | |
| + // Map style | |
| + uint32 flags = 0; | |
| + if (style & Style::Titlebar) | |
| + { | |
| + } // Default | |
| + if (!(style & Style::Resize)) | |
| + flags |= B_NOT_RESIZABLE; | |
| + if (!(style & Style::Close)) | |
| + flags |= B_NOT_CLOSABLE; | |
| + if (style & Style::Fullscreen) | |
| + { | |
| + // Fullscreen logic | |
| + // ... | |
| + } | |
| + | |
| + // Initialize application if needed (BApplication must exist) | |
| + if (!be_app) | |
| + { | |
| + // We cannot create BApplication here easily if the user didn't. | |
| + // SFML generally requires main() to create the app loop context, | |
| + // but often libraries hide this. | |
| + // Haiku REQUIRES a BApplication for windowing messages. | |
| + // If we are a library, we might need a "DummyApplication". | |
| + // But `new BApplication` converts the current thread into the app thread when `Run()` is called. | |
| + // We can't do that inside `WindowImplHaiku` constructor. | |
| + // User MUST have created a BApplication. | |
| + // We will output an error if not. | |
| + err() << "SFML warning: No BApplication found. Ensure you have created a BApplication instance in your main()." | |
| + << std::endl; | |
| + } | |
| + | |
| + SFWindow* window = new SFWindow(frame, title.toAnsiString().c_str(), flags); | |
| + m_window = window; | |
| + window->SetSFMLWindow(this); | |
| + | |
| + // Create View | |
| + m_view = new SFView(window->Bounds(), window); | |
| + window->AddChild(m_view); | |
| + | |
| + // Center on screen | |
| + window->CenterOnScreen(); | |
| + | |
| + if (style & Style::Fullscreen) | |
| + { | |
| + // implement SetFullScreen | |
| + } | |
| + | |
| + window->Show(); | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +WindowImplHaiku::~WindowImplHaiku() | |
| +{ | |
| + if (m_ownsWindow && m_window) | |
| + { | |
| + m_window->Lock(); | |
| + m_window->Quit(); // Closes and deletes | |
| + } | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +WindowHandle WindowImplHaiku::getNativeHandle() const | |
| +{ | |
| + return (WindowHandle)m_window; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +Vector2i WindowImplHaiku::getPosition() const | |
| +{ | |
| + if (m_window) | |
| + { | |
| + // Check synchronization? BWindow access usually requires Lock, but Frame() might be cached. | |
| + // Safer to Lock. | |
| + if (m_window->Lock()) | |
| + { | |
| + BRect frame = m_window->Frame(); | |
| + m_window->Unlock(); | |
| + return Vector2i((int)frame.left, (int)frame.top); | |
| + } | |
| + } | |
| + return Vector2i(0, 0); | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void WindowImplHaiku::setPosition(Vector2i position) | |
| +{ | |
| + if (m_window) | |
| + { | |
| + if (m_window->Lock()) | |
| + { | |
| + m_window->MoveTo((float)position.x, (float)position.y); | |
| + m_window->Unlock(); | |
| + } | |
| + } | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +Vector2u WindowImplHaiku::getSize() const | |
| +{ | |
| + if (m_window) | |
| + { | |
| + if (m_window->Lock()) | |
| + { | |
| + BRect bounds = m_window->Bounds(); | |
| + m_window->Unlock(); | |
| + return Vector2u((unsigned int)bounds.Width() + 1, (unsigned int)bounds.Height() + 1); | |
| + } | |
| + } | |
| + return Vector2u(0, 0); | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void WindowImplHaiku::setSize(Vector2u size) | |
| +{ | |
| + if (m_window) | |
| + { | |
| + if (m_window->Lock()) | |
| + { | |
| + m_window->ResizeTo((float)size.x - 1, (float)size.y - 1); | |
| + m_window->Unlock(); | |
| + } | |
| + } | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void WindowImplHaiku::setTitle(const String& title) | |
| +{ | |
| + if (m_window) | |
| + { | |
| + if (m_window->Lock()) | |
| + { | |
| + m_window->SetTitle(title.toAnsiString().c_str()); | |
| + m_window->Unlock(); | |
| + } | |
| + } | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void WindowImplHaiku::setIcon(Vector2u size, const std::uint8_t* pixels) | |
| +{ | |
| + // Not directly supported on BWindow to set Icon from pixels easily? | |
| + // R1/Beta supports SetIcon with BBitmap? | |
| + // Actually typically app icon is resource based. | |
| + // There isn't a simple SetIcon API on BWindow for arbitrary bitmaps in all versions. | |
| + // Use BApplication::SetAppInfo? No that's global. | |
| + // Pass for now or implement if API found. | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void WindowImplHaiku::setVisible(bool visible) | |
| +{ | |
| + if (m_window) | |
| + { | |
| + if (m_window->Lock()) | |
| + { | |
| + if (visible && m_window->IsHidden()) | |
| + m_window->Show(); | |
| + else if (!visible && !m_window->IsHidden()) | |
| + m_window->Hide(); | |
| + m_window->Unlock(); | |
| + } | |
| + } | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void WindowImplHaiku::setMouseCursorVisible(bool visible) | |
| +{ | |
| + if (be_app) | |
| + { | |
| + if (visible) | |
| + be_app->ShowCursor(); | |
| + else | |
| + be_app->HideCursor(); | |
| + } | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void WindowImplHaiku::setMouseCursorGrabbed(bool grabbed) | |
| +{ | |
| + // Can restrict mouse to window bounds? | |
| + // Not standard BWindow API. | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void WindowImplHaiku::setMouseCursor(const CursorImpl& cursor) | |
| +{ | |
| + if (be_app) | |
| + { | |
| + if (cursor.getCursor()) | |
| + be_app->SetCursor(cursor.getCursor()); | |
| + } | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void WindowImplHaiku::setKeyRepeatEnabled(bool enabled) | |
| +{ | |
| + m_keyRepeatEnabled = enabled; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void WindowImplHaiku::requestFocus() | |
| +{ | |
| + if (m_window) | |
| + { | |
| + if (m_window->Lock()) | |
| + { | |
| + m_window->Activate(true); | |
| + m_window->Unlock(); | |
| + } | |
| + } | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +bool WindowImplHaiku::hasFocus() const | |
| +{ | |
| + if (m_window) | |
| + { | |
| + if (m_window->Lock()) | |
| + { | |
| + bool active = m_window->IsActive(); | |
| + m_window->Unlock(); | |
| + return active; | |
| + } | |
| + } | |
| + return false; | |
| +} | |
| + | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +void WindowImplHaiku::processEvents() | |
| +{ | |
| + // Pull events from the window queue | |
| + if (m_window) | |
| + { | |
| + SFWindow* win = dynamic_cast<SFWindow*>(m_window); | |
| + if (win) | |
| + { | |
| + sf::Event event; | |
| + while (win->PopEvent(event)) | |
| + { | |
| + pushEvent(event); | |
| + } | |
| + } | |
| + } | |
| +} | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/Haiku/WindowImplHaiku.hpp b/src/SFML/Window/Haiku/WindowImplHaiku.hpp | |
| new file mode 100644 | |
| index 00000000..ef194ca1 | |
| --- /dev/null | |
| +++ b/src/SFML/Window/Haiku/WindowImplHaiku.hpp | |
| @@ -0,0 +1,212 @@ | |
| +//////////////////////////////////////////////////////////// | |
| +// | |
| +// SFML - Simple and Fast Multimedia Library | |
| +// Copyright (C) 2007-2025 Laurent Gomila (laurent@sfml-dev.org) | |
| +// | |
| +// 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. | |
| +// | |
| +//////////////////////////////////////////////////////////// | |
| + | |
| +#pragma once | |
| + | |
| +//////////////////////////////////////////////////////////// | |
| +// Headers | |
| +//////////////////////////////////////////////////////////// | |
| +#include <SFML/Window/Event.hpp> | |
| +#include <SFML/Window/Haiku/CursorImpl.hpp> | |
| +#include <SFML/Window/WindowImpl.hpp> | |
| + | |
| +#include <SFML/System/String.hpp> | |
| + | |
| +#include <vector> | |
| + | |
| +class BWindow; | |
| +class BView; | |
| + | |
| +namespace sf | |
| +{ | |
| +namespace priv | |
| +{ | |
| +//////////////////////////////////////////////////////////// | |
| +/// \brief Haiku implementation of WindowImpl | |
| +/// | |
| +//////////////////////////////////////////////////////////// | |
| +class WindowImplHaiku : public WindowImpl | |
| +{ | |
| +public: | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Construct the window implementation from an existing control | |
| + /// | |
| + /// \param handle Platform-specific handle of the control | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + WindowImplHaiku(WindowHandle handle); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Create the window implementation | |
| + /// | |
| + /// \param mode Video mode to use | |
| + /// \param title Title of the window | |
| + /// \param style Window style | |
| + /// \param settings Additional settings for the underlying OpenGL context | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + WindowImplHaiku(VideoMode mode, const String& title, std::uint32_t style, const ContextSettings& settings); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Destructor | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + ~WindowImplHaiku(); | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Get the OS-specific handle of the window | |
| + /// | |
| + /// \return Handle of the window | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + WindowHandle getNativeHandle() const override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Get the position of the window | |
| + /// | |
| + /// \return Position of the window, in pixels | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + Vector2i getPosition() const override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Change the position of the window on screen | |
| + /// | |
| + /// \param position New position of the window, in pixels | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void setPosition(Vector2i position) override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Get the client size of the window | |
| + /// | |
| + /// \return Size of the window, in pixels | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + Vector2u getSize() const override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Change the size of the rendering region of the window | |
| + /// | |
| + /// \param size New size, in pixels | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void setSize(Vector2u size) override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Change the title of the window | |
| + /// | |
| + /// \param title New title | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void setTitle(const String& title) override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Change the window's icon | |
| + /// | |
| + /// \param size Icon's width and height, in pixels | |
| + /// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void setIcon(Vector2u size, const std::uint8_t* pixels) override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Show or hide the window | |
| + /// | |
| + /// \param visible True to show, false to hide | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void setVisible(bool visible) override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Show or hide the mouse cursor | |
| + /// | |
| + /// \param visible True to show, false to hide | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void setMouseCursorVisible(bool visible) override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Grab or release the mouse cursor and keeps it from leaving | |
| + /// | |
| + /// \param grabbed True to enable, false to disable | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void setMouseCursorGrabbed(bool grabbed) override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Set the displayed cursor to a native system cursor | |
| + /// | |
| + /// \param cursor Native system cursor type to display | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void setMouseCursor(const CursorImpl& cursor) override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Enable or disable automatic key-repeat | |
| + /// | |
| + /// \param enabled True to enable, false to disable | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void setKeyRepeatEnabled(bool enabled) override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Request the current window to be made the active | |
| + /// foreground window | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void requestFocus() override; | |
| + | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Check whether the window has the input focus | |
| + /// | |
| + /// \return True if window has focus, false otherwise | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + bool hasFocus() const override; | |
| + | |
| +protected: | |
| + //////////////////////////////////////////////////////////// | |
| + /// \brief Process incoming events from the operating system | |
| + /// | |
| + //////////////////////////////////////////////////////////// | |
| + void processEvents() override; | |
| + | |
| +private: | |
| + //////////////////////////////////////////////////////////// | |
| + // Member data | |
| + //////////////////////////////////////////////////////////// | |
| + BWindow* m_window; //!< Pointer to the Haiku window | |
| + BView* m_view; //!< View for key/mouse event capture | |
| + bool m_ownsWindow; //!< Do we own the window? | |
| + bool m_keyRepeatEnabled; //!< Is key repeat enabled? | |
| + CursorImpl m_cursor; //!< Current cursor implementation | |
| + std::vector<Event> m_eventQueue; //!< Local event queue to store events from BWindow thread | |
| + // Thread safety needed? Yes, BWindow runs in separate thread. | |
| + // We need a way to pass events safely. | |
| + // Semaphores or ports are standard. | |
| +}; | |
| + | |
| +} // namespace priv | |
| +} // namespace sf | |
| diff --git a/src/SFML/Window/JoystickImpl.hpp b/src/SFML/Window/JoystickImpl.hpp | |
| index 65ec74d5..79b07e68 100644 | |
| --- a/src/SFML/Window/JoystickImpl.hpp | |
| +++ b/src/SFML/Window/JoystickImpl.hpp | |
| @@ -93,4 +93,8 @@ struct JoystickState | |
| #include <SFML/Window/Android/JoystickImpl.hpp> | |
| +#elif defined(SFML_SYSTEM_HAIKU) | |
| + | |
| +#include <SFML/Window/Haiku/JoystickImpl.hpp> | |
| + | |
| #endif | |
| diff --git a/src/SFML/Window/SensorImpl.hpp b/src/SFML/Window/SensorImpl.hpp | |
| index c27acf14..96c4c4c1 100644 | |
| --- a/src/SFML/Window/SensorImpl.hpp | |
| +++ b/src/SFML/Window/SensorImpl.hpp | |
| @@ -52,4 +52,8 @@ | |
| #include <SFML/Window/Android/SensorImpl.hpp> | |
| +#elif defined(SFML_SYSTEM_HAIKU) | |
| + | |
| +#include <SFML/Window/Haiku/SensorImpl.hpp> | |
| + | |
| #endif | |
| diff --git a/src/SFML/Window/WindowImpl.cpp b/src/SFML/Window/WindowImpl.cpp | |
| index 2b162b47..ead4deb4 100644 | |
| --- a/src/SFML/Window/WindowImpl.cpp | |
| +++ b/src/SFML/Window/WindowImpl.cpp | |
| @@ -89,6 +89,13 @@ using WindowImplType = sf::priv::WindowImplAndroid; | |
| #define SFML_VULKAN_IMPLEMENTATION_NOT_AVAILABLE | |
| +#elif defined(SFML_SYSTEM_HAIKU) | |
| + | |
| +#include <SFML/Window/Haiku/WindowImplHaiku.hpp> | |
| +using WindowImplType = sf::priv::WindowImplHaiku; | |
| + | |
| +#define SFML_VULKAN_IMPLEMENTATION_NOT_AVAILABLE | |
| + | |
| #endif | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment