Merge pull request #2082 from feature/backmerge

Backmerge 2.6.x to master
This commit is contained in:
Lukas Dürrenberger 2022-05-02 08:35:39 +02:00 committed by GitHub
commit d1ff823d9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 3045 additions and 52 deletions

View File

@ -38,14 +38,17 @@ jobs:
config: { name: x86, flags: -DCMAKE_ANDROID_ARCH_ABI=x86 -DCMAKE_SYSTEM_NAME=Android -DSFML_BUILD_TEST_SUITE=FALSE -DCMAKE_ANDROID_NDK=$GITHUB_WORKSPACE/android-ndk-r23b -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang -DCMAKE_ANDROID_STL_TYPE=c++_shared -DCMAKE_ANDROID_API=26 }
- platform: { name: Android, os: ubuntu-latest }
config: { name: armeabi-v7a, flags: -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a -DCMAKE_SYSTEM_NAME=Android -DSFML_BUILD_TEST_SUITE=FALSE -DCMAKE_ANDROID_NDK=$GITHUB_WORKSPACE/android-ndk-r23b -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=clang -DCMAKE_ANDROID_STL_TYPE=c++_shared -DCMAKE_ANDROID_API=26 }
- platform: { name: Linux GCC, os: ubuntu-latest }
config: { name: Static DRM, flags: -DBUILD_SHARED_LIBS=FALSE -DSFML_USE_DRM=TRUE }
- platform: { name: Linux GCC, os: ubuntu-latest }
config: { name: Shared DRM, flags: -DBUILD_SHARED_LIBS=TRUE -DSFML_USE_DRM=TRUE }
steps:
- name: Checkout Code
uses: actions/checkout@v2
- name: Install Linux Dependencies
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install libxrandr-dev libxcursor-dev libudev-dev libopenal-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev
run: sudo apt-get update && sudo apt-get install libxrandr-dev libxcursor-dev libudev-dev libopenal-dev libflac-dev libvorbis-dev libgl1-mesa-dev libegl1-mesa-dev libdrm-dev libgbm-dev
- name: Install Android Components
if: matrix.platform.name == 'Android'

View File

@ -0,0 +1,18 @@
#
# Try to find EGL library and include path.
# Once done this will define
#
# DRM_FOUND
# DRM_INCLUDE_PATH
# DRM_LIBRARY
#
if(PKG_CONFIG_FOUND)
pkg_check_modules(PC_DRM drm QUIET)
endif()
find_path(DRM_INCLUDE_DIR NAMES libdrm/drm.h)
find_library(DRM_LIBRARY NAMES drm)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(DRM DEFAULT_MSG DRM_LIBRARY DRM_INCLUDE_DIR)

View File

@ -0,0 +1,18 @@
#
# Try to find GBM library and include path.
# Once done this will define
#
# GBM_FOUND
# GBM_INCLUDE_PATH
# GBM_LIBRARY
#
if(PKG_CONFIG_FOUND)
pkg_check_modules(PC_GBM gbm QUIET)
endif()
find_path(GBM_INCLUDE_DIR NAMES gbm.h)
find_library(GBM_LIBRARY NAMES gbm)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GBM DEFAULT_MSG GBM_LIBRARY GBM_INCLUDE_DIR)

View File

@ -31,7 +31,9 @@ if(SFML_BUILD_GRAPHICS)
if(SFML_OS_WINDOWS)
add_subdirectory(win32)
elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD)
if(NOT SFML_USE_DRM)
add_subdirectory(X11)
endif()
elseif(SFML_OS_MACOSX AND ${CMAKE_GENERATOR} MATCHES "Xcode")
add_subdirectory(cocoa)
endif()

358
extlibs/headers/drm/drm-common.c vendored Normal file
View File

@ -0,0 +1,358 @@
/*
* Copyright (c) 2017 Rob Clark <rclark@redhat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sub license,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <errno.h>
#include <inttypes.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <drm-common.h>
#include <gbm.h>
#define WEAK __attribute__((weak))
WEAK uint64_t gbm_bo_get_modifier(struct gbm_bo *bo);
WEAK int gbm_bo_get_plane_count(struct gbm_bo *bo);
WEAK uint32_t gbm_bo_get_stride_for_plane(struct gbm_bo *bo, int plane);
WEAK uint32_t gbm_bo_get_offset(struct gbm_bo *bo, int plane);
static void drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
{
int drm_fd = gbm_device_get_fd(gbm_bo_get_device(bo));
struct drm_fb *fb = data;
if (fb->fb_id)
drmModeRmFB(drm_fd, fb->fb_id);
free(fb);
}
struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo)
{
int drm_fd = gbm_device_get_fd(gbm_bo_get_device(bo));
struct drm_fb *fb = gbm_bo_get_user_data(bo);
uint32_t width, height, format,
strides[4] = {0}, handles[4] = {0},
offsets[4] = {0}, flags = 0;
int ret = -1;
if (fb)
return fb;
fb = calloc(1, sizeof *fb);
fb->bo = bo;
width = gbm_bo_get_width(bo);
height = gbm_bo_get_height(bo);
format = gbm_bo_get_format(bo);
if (gbm_bo_get_modifier && gbm_bo_get_plane_count &&
gbm_bo_get_stride_for_plane && gbm_bo_get_offset)
{
uint64_t modifiers[4] = {0};
modifiers[0] = gbm_bo_get_modifier(bo);
const int num_planes = gbm_bo_get_plane_count(bo);
for (int i = 0; i < num_planes; i++)
{
strides[i] = gbm_bo_get_stride_for_plane(bo, i);
handles[i] = gbm_bo_get_handle(bo).u32;
offsets[i] = gbm_bo_get_offset(bo, i);
modifiers[i] = modifiers[0];
}
if (modifiers[0])
{
flags = DRM_MODE_FB_MODIFIERS;
// printf("Using modifier %" PRIx64 "\n", modifiers[0]);
}
ret = drmModeAddFB2WithModifiers(drm_fd, width, height,
format, handles, strides, offsets,
modifiers, &fb->fb_id, flags);
}
if (ret)
{
// if (flags)
// fprintf(stderr, "Modifiers failed!\n");
memcpy(handles, (uint32_t [4]){gbm_bo_get_handle(bo).u32,0,0,0}, 16);
memcpy(strides, (uint32_t [4]){gbm_bo_get_stride(bo),0,0,0}, 16);
memset(offsets, 0, 16);
ret = drmModeAddFB2(drm_fd, width, height, format,
handles, strides, offsets, &fb->fb_id, 0);
}
if (ret)
{
printf("failed to create fb: %s\n", strerror(errno));
free(fb);
return NULL;
}
gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
return fb;
}
static uint32_t find_crtc_for_encoder(const drmModeRes *resources,
const drmModeEncoder *encoder)
{
for (int i = 0; i < resources->count_crtcs; i++)
{
/* possible_crtcs is a bitmask as described here:
* https://dvdhrm.wordpress.com/2012/09/13/linux-drm-mode-setting-api
*/
const uint32_t crtc_mask = 1U << i;
const uint32_t crtc_id = resources->crtcs[i];
if (encoder->possible_crtcs & crtc_mask)
{
return crtc_id;
}
}
/* no match found */
return 0;
}
static uint32_t find_crtc_for_connector(const struct drm *drm, const drmModeRes *resources, const drmModeConnector *connector)
{
for (int i = 0; i < connector->count_encoders; i++)
{
const uint32_t encoder_id = connector->encoders[i];
drmModeEncoder *encoder = drmModeGetEncoder(drm->fd, encoder_id);
if (encoder)
{
const uint32_t crtc_id = find_crtc_for_encoder(resources, encoder);
drmModeFreeEncoder(encoder);
if (crtc_id != 0)
{
return crtc_id;
}
}
}
/* no match found */
return 0;
}
static int get_resources(int fd, drmModeRes **resources)
{
*resources = drmModeGetResources(fd);
if (*resources == NULL)
return -1;
return 0;
}
#define MAX_DRM_DEVICES 64
static int find_drm_device(drmModeRes **resources)
{
drmDevicePtr devices[MAX_DRM_DEVICES] = { NULL };
int num_devices, fd = -1;
num_devices = drmGetDevices2(0, devices, MAX_DRM_DEVICES);
if (num_devices < 0)
{
printf("drmGetDevices2 failed: %s\n", strerror(-num_devices));
return -1;
}
for (int i = 0; i < num_devices; i++)
{
drmDevicePtr device = devices[i];
int ret;
if (!(device->available_nodes & (1 << DRM_NODE_PRIMARY)))
continue;
/* OK, it's a primary device. If we can get the
* drmModeResources, it means it's also a
* KMS-capable device.
*/
fd = open(device->nodes[DRM_NODE_PRIMARY], O_RDWR);
if (fd < 0)
continue;
ret = get_resources(fd, resources);
if (!ret)
break;
close(fd);
fd = -1;
}
drmFreeDevices(devices, num_devices);
if (fd < 0)
printf("no drm device found!\n");
return fd;
}
int init_drm(struct drm *drm, const char *device, const char *mode_str,
unsigned int vrefresh)
{
drmModeRes *resources;
drmModeConnector *connector = NULL;
drmModeEncoder *encoder = NULL;
int i, ret, area;
if (device)
{
drm->fd = open(device, O_RDWR);
ret = get_resources(drm->fd, &resources);
if (ret < 0 && errno == EOPNOTSUPP)
printf("%s does not look like a modeset device\n", device);
}
else
{
drm->fd = find_drm_device(&resources);
}
if (drm->fd < 0)
{
printf("could not open drm device\n");
return -1;
}
if (!resources)
{
printf("drmModeGetResources failed: %s\n", strerror(errno));
return -1;
}
/* find a connected connector: */
for (i = 0; i < resources->count_connectors; i++)
{
connector = drmModeGetConnector(drm->fd, resources->connectors[i]);
if (connector->connection == DRM_MODE_CONNECTED)
{
/* it's connected, let's use this! */
break;
}
drmModeFreeConnector(connector);
connector = NULL;
}
if (!connector)
{
/* we could be fancy and listen for hotplug events and wait for
* a connector..
*/
printf("no connected connector!\n");
return -1;
}
/* find user requested mode: */
if (mode_str && *mode_str)
{
for (i = 0; i < connector->count_modes; i++)
{
drmModeModeInfo *current_mode = &connector->modes[i];
if (strcmp(current_mode->name, mode_str) == 0)
{
if (vrefresh == 0 || current_mode->vrefresh == vrefresh)
{
drm->mode = current_mode;
break;
}
}
}
if (!drm->mode)
printf("requested mode not found, using default mode!\n");
}
/* find preferred mode or the highest resolution mode: */
if (!drm->mode)
{
for (i = 0, area = 0; i < connector->count_modes; i++)
{
drmModeModeInfo *current_mode = &connector->modes[i];
if (current_mode->type & DRM_MODE_TYPE_PREFERRED)
{
drm->mode = current_mode;
break;
}
int current_area = current_mode->hdisplay * current_mode->vdisplay;
if (current_area > area)
{
drm->mode = current_mode;
area = current_area;
}
}
}
if (!drm->mode)
{
printf("could not find mode!\n");
return -1;
}
/* find encoder: */
for (i = 0; i < resources->count_encoders; i++)
{
encoder = drmModeGetEncoder(drm->fd, resources->encoders[i]);
if (encoder->encoder_id == connector->encoder_id)
break;
drmModeFreeEncoder(encoder);
encoder = NULL;
}
if (encoder)
{
drm->crtc_id = encoder->crtc_id;
}
else
{
uint32_t crtc_id = find_crtc_for_connector(drm, resources, connector);
if (crtc_id == 0)
{
printf("no crtc found!\n");
return -1;
}
drm->crtc_id = crtc_id;
}
drmModeFreeResources(resources);
drm->connector_id = connector->connector_id;
drm->saved_connector = connector;
drm->saved_encoder = encoder;
// get original display mode so we can restore display mode after program exits
drm->original_crtc = drmModeGetCrtc(drm->fd, drm->crtc_id);
if(getenv("SFML_DRM_DEBUG"))
{
printf("DRM Mode used: %s@%d\n", drm->mode->name, drm->mode->vrefresh);
}
return 0;
}

86
extlibs/headers/drm/drm-common.h vendored Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2017 Rob Clark <rclark@redhat.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sub license,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef _DRM_COMMON_H
#define _DRM_COMMON_H
#include <xf86drm.h>
#include <xf86drmMode.h>
#ifdef __cplusplus
extern "C" {
#endif
struct gbm;
struct egl;
struct plane
{
drmModePlane *plane;
drmModeObjectProperties *props;
drmModePropertyRes **props_info;
};
struct crtc
{
drmModeCrtc *crtc;
drmModeObjectProperties *props;
drmModePropertyRes **props_info;
};
struct connector
{
drmModeConnector *connector;
drmModeObjectProperties *props;
drmModePropertyRes **props_info;
};
struct drm
{
int fd;
drmModeModeInfo *mode;
uint32_t crtc_id;
uint32_t connector_id;
drmModeCrtcPtr original_crtc;
drmModeConnectorPtr saved_connector;
drmModeEncoderPtr saved_encoder;
};
struct drm_fb
{
struct gbm_bo *bo;
uint32_t fb_id;
};
struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo);
int init_drm(struct drm *drm, const char *device, const char *mode_str, unsigned int vrefresh);
#ifdef __cplusplus
}
#endif
#endif /* _DRM_COMMON_H */

View File

@ -82,29 +82,45 @@ if(SFML_OS_WINDOWS)
# make sure that we use the Unicode version of the Win API functions
add_definitions(-DUNICODE -D_UNICODE)
elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD)
if(SFML_USE_DRM)
add_definitions(-DSFML_USE_DRM)
set(PLATFORM_SRC
${PLATFORM_SRC}
${SRCROOT}/DRM/CursorImpl.hpp
${SRCROOT}/DRM/CursorImpl.cpp
${SRCROOT}/DRM/ClipboardImpl.hpp
${SRCROOT}/DRM/ClipboardImpl.cpp
${SRCROOT}/Unix/SensorImpl.cpp
${SRCROOT}/Unix/SensorImpl.hpp
${SRCROOT}/DRM/InputImplUDev.cpp
${SRCROOT}/DRM/InputImplUDev.hpp
${SRCROOT}/DRM/VideoModeImpl.cpp
${SRCROOT}/DRM/DRMContext.cpp
${SRCROOT}/DRM/DRMContext.hpp
${SRCROOT}/DRM/WindowImplDRM.cpp
${SRCROOT}/DRM/WindowImplDRM.hpp
)
else()
set(PLATFORM_SRC
${PLATFORM_SRC}
${SRCROOT}/Unix/CursorImpl.hpp
${SRCROOT}/Unix/CursorImpl.cpp
${SRCROOT}/Unix/ClipboardImpl.hpp
${SRCROOT}/Unix/ClipboardImpl.cpp
${SRCROOT}/Unix/Display.cpp
${SRCROOT}/Unix/Display.hpp
${SRCROOT}/Unix/InputImpl.cpp
${SRCROOT}/Unix/InputImpl.hpp
${SRCROOT}/Unix/SensorImpl.cpp
${SRCROOT}/Unix/SensorImpl.hpp
${SRCROOT}/Unix/Display.cpp
${SRCROOT}/Unix/Display.hpp
${SRCROOT}/Unix/GlxContext.cpp
${SRCROOT}/Unix/GlxContext.hpp
${SRCROOT}/Unix/VideoModeImpl.cpp
${SRCROOT}/Unix/VulkanImplX11.cpp
${SRCROOT}/Unix/VulkanImplX11.hpp
${SRCROOT}/Unix/WindowImplX11.cpp
${SRCROOT}/Unix/WindowImplX11.hpp
)
if(NOT SFML_OS_ANDROID)
set(PLATFORM_SRC
${PLATFORM_SRC}
${SRCROOT}/Unix/GlxContext.cpp
${SRCROOT}/Unix/GlxContext.hpp
)
endif()
if(SFML_OS_LINUX)
set(PLATFORM_SRC
@ -236,6 +252,21 @@ endif()
# define the sfml-window target
sfml_add_library(Window
SOURCES ${SRC} ${PLATFORM_SRC})
# DRM libraries
if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD)
if(SFML_USE_DRM)
target_sources(sfml-window PRIVATE $<TARGET_OBJECTS:drm-common>)
sfml_find_package(DRM INCLUDE "DRM_INCLUDE_DIR" LINK "DRM_LIBRARY")
target_include_directories(sfml-window PRIVATE ${PROJECT_SOURCE_DIR}/extlibs/headers/drm ${DRM_INCLUDE_DIR}/libdrm)
sfml_find_package(GBM INCLUDE "GBM_INCLUDE_DIR" LINK "GBM_LIBRARY")
target_link_libraries(sfml-window PRIVATE drm gbm EGL)
add_library(drm-common OBJECT ${PROJECT_SOURCE_DIR}/extlibs/headers/drm/drm-common.c)
target_include_directories(drm-common PRIVATE ${PROJECT_SOURCE_DIR}/extlibs/headers/drm ${DRM_INCLUDE_DIR}/libdrm)
else()
sfml_find_package(X11 INCLUDE "X11_INCLUDE_DIR" LINK "X11_X11_LIB" "X11_Xrandr_LIB" "X11_Xcursor_LIB")
target_link_libraries(sfml-window PRIVATE X11)
endif()
endif()
target_link_libraries(sfml-window PUBLIC SFML::System)
# glad sources
@ -249,12 +280,6 @@ endif()
# Vulkan headers
target_include_directories(sfml-window SYSTEM PRIVATE "${PROJECT_SOURCE_DIR}/extlibs/headers/vulkan")
# find and setup usage for external libraries
if(SFML_OS_LINUX OR SFML_OS_FREEBSD OR SFML_OS_OPENBSD OR SFML_OS_NETBSD)
sfml_find_package(X11 INCLUDE "X11_INCLUDE_DIR" LINK "X11_X11_LIB" "X11_Xrandr_LIB" "X11_Xcursor_LIB")
target_link_libraries(sfml-window PRIVATE X11)
endif()
# CMake 3.11 and later prefer to choose GLVND, but we choose legacy OpenGL for backward compability
# (unless the OpenGL_GL_PREFERENCE was explicitly set)
# See CMP0072 for more details (cmake --help-policy CMP0072)
@ -268,7 +293,6 @@ if(SFML_OS_IOS)
target_link_libraries(sfml-window PRIVATE GLES)
elseif(SFML_OS_ANDROID)
sfml_find_package(GLES INCLUDE "GLES_INCLUDE_DIR" LINK "GLES_LIBRARY")
sfml_find_package(EGL INCLUDE "EGL_INCLUDE_DIR" LINK "EGL_LIBRARY")
target_link_libraries(sfml-window PRIVATE EGL)
target_link_libraries(sfml-window PRIVATE GLES)

View File

@ -33,7 +33,11 @@
#if defined(SFML_SYSTEM_WINDOWS)
#include <SFML/Window/Win32/ClipboardImpl.hpp>
#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD)
#if defined(SFML_USE_DRM)
#include <SFML/Window/DRM/ClipboardImpl.hpp>
#else
#include <SFML/Window/Unix/ClipboardImpl.hpp>
#endif
#elif defined(SFML_SYSTEM_MACOS)
#include <SFML/Window/OSX/ClipboardImpl.hpp>
#elif defined(SFML_SYSTEM_IOS)

View File

@ -31,25 +31,19 @@
#include <SFML/Config.hpp>
#if defined(SFML_SYSTEM_WINDOWS)
#include <SFML/Window/Win32/CursorImpl.hpp>
#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD)
#if defined(SFML_USE_DRM)
#include <SFML/Window/DRM/CursorImpl.hpp>
#else
#include <SFML/Window/Unix/CursorImpl.hpp>
#endif
#elif defined(SFML_SYSTEM_MACOS)
#include <SFML/Window/OSX/CursorImpl.hpp>
#elif defined(SFML_SYSTEM_IOS)
#include <SFML/Window/iOS/CursorImpl.hpp>
#elif defined(SFML_SYSTEM_ANDROID)
#include <SFML/Window/Android/CursorImpl.hpp>
#endif

View File

@ -0,0 +1,49 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2022 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/DRM/ClipboardImpl.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
String ClipboardImpl::getString()
{
return "";
}
////////////////////////////////////////////////////////////
void ClipboardImpl::setString(const String& /*text*/)
{
}
} // namespace priv
} // namespace sf

View File

@ -0,0 +1,76 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2022 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.
//
////////////////////////////////////////////////////////////
#ifndef SFML_CLIPBOARDIMPLDRM_HPP
#define SFML_CLIPBOARDIMPLDRM_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/System/String.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Give access to the system clipboard
///
////////////////////////////////////////////////////////////
class ClipboardImpl
{
public:
////////////////////////////////////////////////////////////
/// \brief Get the content of the clipboard as string data
///
/// This function returns the content of the clipboard
/// as a string. If the clipboard does not contain string
/// it returns an empty sf::String object.
///
/// \return Current content of the clipboard
///
////////////////////////////////////////////////////////////
static String getString();
////////////////////////////////////////////////////////////
/// \brief Set the content of the clipboard as string data
///
/// This function sets the content of the clipboard as a
/// string.
///
/// \param text sf::String object containing the data to be sent
/// to the clipboard
///
////////////////////////////////////////////////////////////
static void setString(const String& text);
};
} // namespace priv
} // namespace sf
#endif // SFML_CLIPBOARDIMPLDRM_HPP

View File

@ -0,0 +1,90 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2022 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/DRM/CursorImpl.hpp>
#include <vector>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
CursorImpl::CursorImpl()
{
}
////////////////////////////////////////////////////////////
CursorImpl::~CursorImpl()
{
}
////////////////////////////////////////////////////////////
bool CursorImpl::loadFromPixels(const Uint8* /*pixels*/, Vector2u /*size*/, Vector2u /*hotspot*/)
{
return false;
}
////////////////////////////////////////////////////////////
bool CursorImpl::loadFromPixelsARGB(const Uint8* /*pixels*/, Vector2u /*size*/, Vector2u /*hotspot*/)
{
return false;
}
////////////////////////////////////////////////////////////
bool CursorImpl::loadFromPixelsMonochrome(const Uint8* /*pixels*/, Vector2u /*size*/, Vector2u /*hotspot*/)
{
return false;
}
////////////////////////////////////////////////////////////
bool CursorImpl::loadFromSystem(Cursor::Type /*type*/)
{
return false;
}
////////////////////////////////////////////////////////////
bool CursorImpl::isColorCursorSupported()
{
return false;
}
////////////////////////////////////////////////////////////
void CursorImpl::release()
{
}
} // namespace priv
} // namespace sf

View File

@ -0,0 +1,130 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2022 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.
//
////////////////////////////////////////////////////////////
#ifndef SFML_CURSORIMPLDRM_HPP
#define SFML_CURSORIMPLDRM_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/Cursor.hpp>
#include <SFML/System/Vector2.hpp>
#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Unix implementation of Cursor
///
////////////////////////////////////////////////////////////
class CursorImpl
{
public:
////////////////////////////////////////////////////////////
/// \brief Default constructor
///
/// Refer to sf::Cursor::Cursor().
///
////////////////////////////////////////////////////////////
CursorImpl();
////////////////////////////////////////////////////////////
/// \brief Destructor
///
/// Refer to sf::Cursor::~Cursor().
///
////////////////////////////////////////////////////////////
~CursorImpl();
////////////////////////////////////////////////////////////
/// \brief Deleted copy constructor
///
////////////////////////////////////////////////////////////
CursorImpl(const CursorImpl&) = delete;
////////////////////////////////////////////////////////////
/// \brief Deleted copy assignment
///
////////////////////////////////////////////////////////////
CursorImpl& operator=(const CursorImpl&) = delete;
////////////////////////////////////////////////////////////
/// \brief Create a cursor with the provided image
///
/// Refer to sf::Cursor::loadFromPixels().
///
////////////////////////////////////////////////////////////
bool loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot);
////////////////////////////////////////////////////////////
/// \brief Create a native system cursor
///
/// Refer to sf::Cursor::loadFromSystem().
///
////////////////////////////////////////////////////////////
bool loadFromSystem(Cursor::Type type);
private:
friend class WindowImplDRM;
////////////////////////////////////////////////////////////
/// \brief Checks if colored cursors are supported for this display.
///
////////////////////////////////////////////////////////////
bool isColorCursorSupported();
////////////////////////////////////////////////////////////
/// \brief Create a cursor with the provided image (ARGB support)
///
/// Refer to sf::Cursor::loadFromPixels().
///
////////////////////////////////////////////////////////////
bool loadFromPixelsARGB(const Uint8* pixels, Vector2u size, Vector2u hotspot);
////////////////////////////////////////////////////////////
/// \brief Create a cursor with the provided image (monochrome)
///
/// Refer to sf::Cursor::loadFromPixels().
///
////////////////////////////////////////////////////////////
bool loadFromPixelsMonochrome(const Uint8* pixels, Vector2u size, Vector2u hotspot);
////////////////////////////////////////////////////////////
/// \brief Release the cursor, if we have loaded one.
///
////////////////////////////////////////////////////////////
void release();
};
} // namespace priv
} // namespace sf
#endif // SFML_CUSROSIMPLDRM_HPP

View File

@ -0,0 +1,552 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2020 Andrew Mickelson
// 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/DRM/DRMContext.hpp>
#include <SFML/Window/DRM/WindowImplDRM.hpp>
#include <SFML/OpenGL.hpp>
#include <SFML/System/Err.hpp>
#include <SFML/System/Sleep.hpp>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <poll.h>
#include <unistd.h>
namespace
{
bool initialized = false;
drm drmNode;
drmEventContext drmEventCtx;
pollfd pollFD;
gbm_device* gbmDevice = NULL;
int contextCount = 0;
EGLDisplay display = EGL_NO_DISPLAY;
int waitingForFlip = 0;
static void pageFlipHandler(int fd, unsigned int frame,
unsigned int sec, unsigned int usec, void* data)
{
// suppress unused param warning
(void)fd, (void)frame, (void)sec, (void)usec;
int* temp = static_cast<int*>(data);
*temp = 0;
}
static bool waitForFlip(int timeout)
{
while (waitingForFlip)
{
pollFD.revents = 0;
if (poll(&pollFD, 1, timeout) < 0)
return false;
if (pollFD.revents & (POLLHUP | POLLERR))
return false;
if (pollFD.revents & POLLIN)
{
drmHandleEvent(drmNode.fd, &drmEventCtx);
}
else
{
return false;
}
}
return true;
}
void cleanup()
{
if (!initialized)
return;
drmModeSetCrtc(drmNode.fd,
drmNode.original_crtc->crtc_id,
drmNode.original_crtc->buffer_id,
drmNode.original_crtc->x,
drmNode.original_crtc->y,
&drmNode.connector_id,
1,
&drmNode.original_crtc->mode);
drmModeFreeConnector(drmNode.saved_connector);
drmModeFreeEncoder(drmNode.saved_encoder);
drmModeFreeCrtc(drmNode.original_crtc);
eglTerminate(display);
display = EGL_NO_DISPLAY;
gbm_device_destroy(gbmDevice);
gbmDevice = NULL;
close(drmNode.fd);
drmNode.fd = -1;
drmNode.mode = 0;
std::memset(&pollFD, 0, sizeof(pollfd));
std::memset(&drmEventCtx, 0, sizeof(drmEventContext));
waitingForFlip = 0;
initialized = false;
}
void checkInit()
{
if (initialized)
return;
// Use environment variable "SFML_DRM_DEVICE" (or NULL if not set)
char* deviceString = std::getenv("SFML_DRM_DEVICE");
if (deviceString && !*deviceString)
deviceString = NULL;
// Use environment variable "SFML_DRM_MODE" (or NULL if not set)
char* modeString = std::getenv("SFML_DRM_MODE");
// Use environment variable "SFML_DRM_REFRESH" (or 0 if not set)
// Use in combination with mode to request specific refresh rate for the mode
// if multiple refresh rates for same mode might be supported
unsigned int refreshRate = 0;
char* refreshString = std::getenv("SFML_DRM_REFRESH");
if (refreshString)
refreshRate = static_cast<unsigned int>(atoi(refreshString));
if (init_drm(&drmNode,
deviceString, // device
modeString, // requested mode
refreshRate) < 0) // screen refresh rate
{
sf::err() << "Error initializing DRM" << std::endl;
return;
}
gbmDevice = gbm_create_device(drmNode.fd);
std::atexit(cleanup);
initialized = true;
pollFD.fd = drmNode.fd;
pollFD.events = POLLIN;
drmEventCtx.version = 2;
drmEventCtx.page_flip_handler = pageFlipHandler;
}
EGLDisplay getInitializedDisplay()
{
checkInit();
if (display == EGL_NO_DISPLAY)
{
display = eglCheck(eglGetDisplay(reinterpret_cast<EGLNativeDisplayType>(gbmDevice)));
EGLint major, minor;
eglCheck(eglInitialize(display, &major, &minor));
#if defined(SFML_OPENGL_ES)
if (!eglBindAPI(EGL_OPENGL_ES_API))
{
sf::err() << "failed to bind api EGL_OPENGL_ES_API" << std::endl;
}
#else
if (!eglBindAPI(EGL_OPENGL_API))
{
sf::err() << "failed to bind api EGL_OPENGL_API" << std::endl;
}
#endif
}
return display;
}
}
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
DRMContext::DRMContext(DRMContext* shared) :
m_display (EGL_NO_DISPLAY),
m_context (EGL_NO_CONTEXT),
m_surface (EGL_NO_SURFACE),
m_config (NULL),
m_currentBO (NULL),
m_nextBO (NULL),
m_gbmSurface (NULL),
m_width (0),
m_height (0),
m_shown (false),
m_scanOut (false)
{
contextCount++;
// Get the initialized EGL display
m_display = getInitializedDisplay();
// Get the best EGL config matching the default video settings
m_config = getBestConfig(m_display, VideoMode::getDesktopMode().bitsPerPixel, ContextSettings());
updateSettings();
// Create EGL context
createContext(shared);
if (shared)
createSurface(shared->m_width, shared->m_height, VideoMode::getDesktopMode().bitsPerPixel, false);
else // create a surface to force the GL to initialize (seems to be required for glGetString() etc )
createSurface(1, 1, VideoMode::getDesktopMode().bitsPerPixel, false);
}
////////////////////////////////////////////////////////////
DRMContext::DRMContext(DRMContext* shared, const ContextSettings& settings, const WindowImpl& owner, unsigned int bitsPerPixel) :
m_display (EGL_NO_DISPLAY),
m_context (EGL_NO_CONTEXT),
m_surface (EGL_NO_SURFACE),
m_config (NULL),
m_currentBO (NULL),
m_nextBO (NULL),
m_gbmSurface (NULL),
m_width (0),
m_height (0),
m_shown (false),
m_scanOut (false)
{
contextCount++;
// Get the initialized EGL display
m_display = getInitializedDisplay();
// Get the best EGL config matching the requested video settings
m_config = getBestConfig(m_display, bitsPerPixel, settings);
updateSettings();
// Create EGL context
createContext(shared);
Vector2u size = owner.getSize();
createSurface(size.x, size.y, bitsPerPixel, true);
}
////////////////////////////////////////////////////////////
DRMContext::DRMContext(DRMContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height) :
m_display (EGL_NO_DISPLAY),
m_context (EGL_NO_CONTEXT),
m_surface (EGL_NO_SURFACE),
m_config (NULL),
m_currentBO (NULL),
m_nextBO (NULL),
m_gbmSurface (NULL),
m_width (0),
m_height (0),
m_shown (false),
m_scanOut (false)
{
contextCount++;
// Get the initialized EGL display
m_display = getInitializedDisplay();
// Get the best EGL config matching the requested video settings
m_config = getBestConfig(m_display, VideoMode::getDesktopMode().bitsPerPixel, settings);
updateSettings();
// Create EGL context
createContext(shared);
createSurface(width, height, VideoMode::getDesktopMode().bitsPerPixel, false);
}
////////////////////////////////////////////////////////////
DRMContext::~DRMContext()
{
// Deactivate the current context
EGLContext currentContext = eglCheck(eglGetCurrentContext());
if (currentContext == m_context)
{
eglCheck(eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
}
// Destroy context
if (m_context != EGL_NO_CONTEXT)
{
eglCheck(eglDestroyContext(m_display, m_context));
m_context = EGL_NO_CONTEXT;
}
// Destroy surface
if (m_surface != EGL_NO_SURFACE)
{
eglCheck(eglDestroySurface(m_display, m_surface));
m_surface = EGL_NO_SURFACE;
}
if (m_currentBO)
gbm_surface_release_buffer(m_gbmSurface, m_currentBO);
if (m_nextBO)
gbm_surface_release_buffer(m_gbmSurface, m_nextBO);
if (m_gbmSurface)
gbm_surface_destroy(m_gbmSurface);
contextCount--;
if (contextCount == 0)
cleanup();
}
////////////////////////////////////////////////////////////
bool DRMContext::makeCurrent(bool current)
{
const EGLSurface surface = current ? m_surface : EGL_NO_SURFACE;
const EGLContext context = current ? m_context : EGL_NO_CONTEXT;
return m_surface != EGL_NO_SURFACE && eglMakeCurrent(m_display, surface, surface, context);
}
////////////////////////////////////////////////////////////
void DRMContext::display()
{
if (m_surface == EGL_NO_SURFACE)
return;
if (!m_scanOut)
{
eglCheck(eglSwapBuffers(m_display, m_surface));
return;
}
// Handle display of buffer to the screen
drm_fb* fb = NULL;
if (!waitForFlip(-1))
return;
if (m_currentBO)
{
gbm_surface_release_buffer(m_gbmSurface, m_currentBO);
m_currentBO = NULL;
}
eglCheck(eglSwapBuffers(m_display, m_surface));
m_currentBO = m_nextBO;
// This call must be preceeded by a single call to eglSwapBuffers()
m_nextBO = gbm_surface_lock_front_buffer(m_gbmSurface);
if (!m_nextBO)
return;
fb = drm_fb_get_from_bo(m_nextBO);
if (!fb)
{
err() << "Failed to get FB from buffer object" << std::endl;
return;
}
// If first time, need to first call drmModeSetCrtc()
if (!m_shown)
{
if (drmModeSetCrtc(drmNode.fd, drmNode.crtc_id, fb->fb_id, 0, 0,
&drmNode.connector_id, 1, drmNode.mode))
{
err() << "Failed to set mode: " << std::strerror(errno) << std::endl;
std::abort();
}
m_shown = true;
}
// Do page flip
if (!drmModePageFlip(drmNode.fd, drmNode.crtc_id, fb->fb_id,
DRM_MODE_PAGE_FLIP_EVENT, &waitingForFlip))
waitingForFlip = 1;
}
////////////////////////////////////////////////////////////
void DRMContext::setVerticalSyncEnabled(bool enabled)
{
eglCheck(eglSwapInterval(m_display, enabled ? 1 : 0));
}
////////////////////////////////////////////////////////////
void DRMContext::createContext(DRMContext* shared)
{
const EGLint contextVersion[] =
{
EGL_CONTEXT_CLIENT_VERSION, 1,
EGL_NONE
};
EGLContext toShared;
if (shared)
toShared = shared->m_context;
else
toShared = EGL_NO_CONTEXT;
if (toShared != EGL_NO_CONTEXT)
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
// Create EGL context
m_context = eglCheck(eglCreateContext(m_display, m_config, toShared, contextVersion));
if (m_context == EGL_NO_CONTEXT)
err() << "Failed to create EGL context" << std::endl;
}
////////////////////////////////////////////////////////////
void DRMContext::createSurface(unsigned int width, unsigned int height, unsigned int /*bpp*/, bool scanout)
{
sf::Uint32 flags = GBM_BO_USE_RENDERING;
m_scanOut = scanout;
if (m_scanOut)
flags |= GBM_BO_USE_SCANOUT;
m_gbmSurface = gbm_surface_create(
gbmDevice,
width,
height,
GBM_FORMAT_ARGB8888,
flags);
if (!m_gbmSurface)
{
err() << "Failed to create gbm surface." << std::endl;
return;
}
m_width = width;
m_height = height;
m_surface = eglCheck(eglCreateWindowSurface(m_display, m_config, reinterpret_cast<EGLNativeWindowType>(m_gbmSurface), NULL));
if (m_surface == EGL_NO_SURFACE)
{
err() << "Failed to create EGL Surface" << std::endl;
}
}
////////////////////////////////////////////////////////////
void DRMContext::destroySurface()
{
eglCheck(eglDestroySurface(m_display, m_surface));
m_surface = EGL_NO_SURFACE;
gbm_surface_destroy(m_gbmSurface);
m_gbmSurface = NULL;
// Ensure that this context is no longer active since our surface is now destroyed
setActive(false);
}
////////////////////////////////////////////////////////////
EGLConfig DRMContext::getBestConfig(EGLDisplay display, unsigned int bitsPerPixel, const ContextSettings& settings)
{
// Set our video settings constraint
const EGLint attributes[] =
{
EGL_BUFFER_SIZE, static_cast<EGLint>(bitsPerPixel),
EGL_DEPTH_SIZE, static_cast<EGLint>(settings.depthBits),
EGL_STENCIL_SIZE, static_cast<EGLint>(settings.stencilBits),
EGL_SAMPLE_BUFFERS, static_cast<EGLint>(settings.antialiasingLevel),
EGL_BLUE_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_RED_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
#if defined(SFML_OPENGL_ES)
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
#else
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
#endif
EGL_NONE
};
EGLint configCount;
EGLConfig configs[1];
// Ask EGL for the best config matching our video settings
eglCheck(eglChooseConfig(display, attributes, configs, 1, &configCount));
return configs[0];
}
////////////////////////////////////////////////////////////
void DRMContext::updateSettings()
{
EGLint tmp;
// Update the internal context settings with the current config
eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_DEPTH_SIZE, &tmp));
m_settings.depthBits = static_cast<unsigned int>(tmp);
eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_STENCIL_SIZE, &tmp));
m_settings.stencilBits = static_cast<unsigned int>(tmp);
eglCheck(eglGetConfigAttrib(m_display, m_config, EGL_SAMPLES, &tmp));
m_settings.antialiasingLevel = static_cast<unsigned int>(tmp);
m_settings.majorVersion = 1;
m_settings.minorVersion = 1;
m_settings.attributeFlags = ContextSettings::Default;
}
////////////////////////////////////////////////////////////
GlFunctionPointer DRMContext::getFunction(const char* name)
{
return reinterpret_cast<GlFunctionPointer>(eglGetProcAddress(name));
}
////////////////////////////////////////////////////////////
drm* DRMContext::getDRM()
{
checkInit();
return &drmNode;
}
} // namespace priv
} // namespace sf

View File

@ -0,0 +1,214 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2020 Andrew Mickelson
// 2013 Jonathan De Wachter (dewachter.jonathan@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////
#ifndef SFML_DRMCONTEXT_HPP
#define SFML_DRMCONTEXT_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/ContextSettings.hpp>
#include <SFML/Window/EGLCheck.hpp>
#include <SFML/Window/GlContext.hpp>
#include <SFML/Window/VideoMode.hpp>
#include <SFML/OpenGL.hpp>
#include <drm-common.h>
#define EGL_NO_X11
#define MESA_EGL_NO_X11_HEADERS
#include <EGL/egl.h>
#include <gbm.h>
#include <xf86drmMode.h>
namespace sf
{
namespace priv
{
class WindowImplDRM;
class DRMContext : public GlContext
{
public:
////////////////////////////////////////////////////////////
/// \brief Create a new context, not associated to a window
///
/// \param shared Context to share the new one with (can be NULL)
///
////////////////////////////////////////////////////////////
DRMContext(DRMContext* shared);
////////////////////////////////////////////////////////////
/// \brief Create a new context attached to a window
///
/// \param shared Context to share the new one with
/// \param settings Creation parameters
/// \param owner Pointer to the owner window
/// \param bitsPerPixel Pixel depth, in bits per pixel
///
////////////////////////////////////////////////////////////
DRMContext(DRMContext* shared, const ContextSettings& settings, const WindowImpl& owner, unsigned int bitsPerPixel);
////////////////////////////////////////////////////////////
/// \brief Create a new context that embeds its own rendering target
///
/// \param shared Context to share the new one with
/// \param settings Creation parameters
/// \param width Back buffer width, in pixels
/// \param height Back buffer height, in pixels
///
////////////////////////////////////////////////////////////
DRMContext(DRMContext* shared, const ContextSettings& settings, unsigned int width, unsigned int height);
////////////////////////////////////////////////////////////
/// \brief Destructor
///
////////////////////////////////////////////////////////////
~DRMContext();
////////////////////////////////////////////////////////////
/// \brief Activate the context as the current target
/// for rendering
///
/// \param current Whether to make the context current or no longer current
///
/// \return True on success, false if any error happened
///
////////////////////////////////////////////////////////////
virtual bool makeCurrent(bool current) override;
////////////////////////////////////////////////////////////
/// \brief Display what has been rendered to the context so far
///
////////////////////////////////////////////////////////////
virtual void display() override;
////////////////////////////////////////////////////////////
/// \brief Enable or disable vertical synchronization
///
/// Activating vertical synchronization will limit the number
/// of frames displayed to the refresh rate of the monitor.
/// This can avoid some visual artifacts, and limit the framerate
/// to a good value (but not constant across different computers).
///
/// \param enabled: True to enable v-sync, false to deactivate
///
////////////////////////////////////////////////////////////
virtual void setVerticalSyncEnabled(bool enabled) override;
////////////////////////////////////////////////////////////
/// \brief Create the EGL context
///
/// \param shared Context to share the new one with (can be NULL)
/// \param bitsPerPixel Pixel depth, in bits per pixel
/// \param settings Creation parameters
///
////////////////////////////////////////////////////////////
void createContext(DRMContext* shared);
////////////////////////////////////////////////////////////
/// \brief Create the EGL surface
///
/// \param width Back buffer width, in pixels
/// \param height Back buffer height, in pixels
/// \param bpp Pixel depth, in bits per pixel
/// \param scanout True to present the surface to the screen
///
////////////////////////////////////////////////////////////
void createSurface(unsigned int width, unsigned int height, unsigned int bpp, bool scanout);
////////////////////////////////////////////////////////////
/// \brief Destroy the EGL surface
///
/// This function must be called when the activity is stopped, or
/// when the orientation change.
///
////////////////////////////////////////////////////////////
void destroySurface();
////////////////////////////////////////////////////////////
/// \brief Get the best EGL visual for a given set of video settings
///
/// \param display EGL display
/// \param bitsPerPixel Pixel depth, in bits per pixel
/// \param settings Requested context settings
///
/// \return The best EGL config
///
////////////////////////////////////////////////////////////
static EGLConfig getBestConfig(EGLDisplay display, unsigned int bitsPerPixel, const ContextSettings& settings);
////////////////////////////////////////////////////////////
/// \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);
protected:
friend class VideoModeImpl;
friend class WindowImplDRM;
////////////////////////////////////////////////////////////
/// \brief Get Direct Rendering Manager pointer
///
////////////////////////////////////////////////////////////
static drm* getDRM();
private:
////////////////////////////////////////////////////////////
/// \brief Helper to copy the picked EGL configuration
///
////////////////////////////////////////////////////////////
void updateSettings();
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
EGLDisplay m_display; ///< The internal EGL display
EGLContext m_context; ///< The internal EGL context
EGLSurface m_surface; ///< The internal EGL surface
EGLConfig m_config; ///< The internal EGL config
gbm_bo* m_currentBO;
gbm_bo* m_nextBO;
gbm_surface* m_gbmSurface;
unsigned int m_width;
unsigned int m_height;
bool m_shown;
bool m_scanOut;
};
} // namespace priv
} // namespace sf
#endif // SFML_DRMCONTEXT_HPP

View File

@ -0,0 +1,715 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2016 Andrew Mickelson
//
// 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/DRM/InputImplUDev.hpp>
#include <SFML/System/Err.hpp>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fcntl.h>
#include <linux/input.h>
#include <mutex>
#include <queue>
#include <sstream>
#include <sys/stat.h>
#include <termios.h>
#include <unistd.h>
#include <vector>
namespace
{
struct TouchSlot
{
int oldId;
int id;
sf::Vector2i pos;
TouchSlot() :
oldId(-1),
id(-1),
pos(0, 0)
{
}
};
std::recursive_mutex inputMutex; // threadsafe? maybe...
sf::Vector2i mousePos; // current mouse position
std::vector<int> fileDescriptors; // list of open file descriptors for /dev/input
std::vector<bool> mouseMap(sf::Mouse::ButtonCount, false); // track whether keys are down
std::vector<bool> keyMap(sf::Keyboard::KeyCount, false); // track whether mouse buttons are down
int touchFd = -1; // file descriptor we have seen MT events on; assumes only 1
std::vector<TouchSlot> touchSlots; // track the state of each touch "slot"
int currentSlot = 0; // which slot are we currently updating?
std::queue<sf::Event> eventQueue; // events received and waiting to be consumed
const int MAX_QUEUE = 64; // The maximum size we let eventQueue grow to
termios newTerminalConfig, oldTerminalConfig; // Terminal configurations
bool altDown() { return (keyMap[sf::Keyboard::LAlt] || keyMap[sf::Keyboard::RAlt]); }
bool controlDown() { return (keyMap[sf::Keyboard::LControl] || keyMap[sf::Keyboard::RControl]); }
bool shiftDown() { return (keyMap[sf::Keyboard::LShift] || keyMap[sf::Keyboard::RShift]); }
bool systemDown() { return (keyMap[sf::Keyboard::LSystem] || keyMap[sf::Keyboard::RSystem]); }
void uninitFileDescriptors(void)
{
for (std::vector<int>::iterator itr = fileDescriptors.begin(); itr != fileDescriptors.end(); ++itr)
close(*itr);
}
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#define NBITS(x) (((x - 1) / BITS_PER_LONG) + 1)
#define OFF(x) (x % BITS_PER_LONG)
#define LONG(x) (x / BITS_PER_LONG)
#define TEST_BIT(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
// Only keep fileDescriptors that we think are a keyboard, mouse or touchpad/touchscreen
// Joysticks are handled in /src/SFML/Window/Unix/JoystickImpl.cpp
bool keepFileDescriptor(int fileDesc)
{
unsigned long bitmask_ev[NBITS(EV_MAX)];
unsigned long bitmask_key[NBITS(KEY_MAX)];
unsigned long bitmask_abs[NBITS(ABS_MAX)];
unsigned long bitmask_rel[NBITS(REL_MAX)];
ioctl(fileDesc, EVIOCGBIT(0, sizeof(bitmask_ev)), &bitmask_ev);
ioctl(fileDesc, EVIOCGBIT(EV_KEY, sizeof(bitmask_key)), &bitmask_key);
ioctl(fileDesc, EVIOCGBIT(EV_ABS, sizeof(bitmask_abs)), &bitmask_abs);
ioctl(fileDesc, EVIOCGBIT(EV_REL, sizeof(bitmask_rel)), &bitmask_rel);
// This is the keyboard test used by SDL.
// The first 32 bits are ESC, numbers and Q to D; If we have any of those,
// consider it a keyboard device; do not test for KEY_RESERVED, though
bool is_keyboard = (bitmask_key[0] & 0xFFFFFFFE);
bool is_abs = TEST_BIT(EV_ABS, bitmask_ev)
&& TEST_BIT(ABS_X, bitmask_abs) && TEST_BIT(ABS_Y, bitmask_abs);
bool is_rel = TEST_BIT(EV_REL, bitmask_ev)
&& TEST_BIT(REL_X, bitmask_rel) && TEST_BIT(REL_Y, bitmask_rel);
bool is_mouse = (is_abs || is_rel) && TEST_BIT(BTN_MOUSE, bitmask_key);
bool is_touch = is_abs && (TEST_BIT(BTN_TOOL_FINGER, bitmask_key) || TEST_BIT(BTN_TOUCH, bitmask_key));
return is_keyboard || is_mouse || is_touch;
}
void initFileDescriptors()
{
static bool initialized = false;
if (initialized)
return;
initialized = true;
for (int i = 0; i < 32; i++)
{
std::string name("/dev/input/event");
std::ostringstream stream;
stream << i;
name += stream.str();
int tempFD = open(name.c_str(), O_RDONLY | O_NONBLOCK);
if (tempFD < 0)
{
if (errno != ENOENT)
sf::err() << "Error opening " << name << ": " << std::strerror(errno) << std::endl;
continue;
}
if (keepFileDescriptor(tempFD))
fileDescriptors.push_back(tempFD);
else
close(tempFD);
}
std::atexit(uninitFileDescriptors);
}
sf::Mouse::Button toMouseButton(int code)
{
switch (code)
{
case BTN_LEFT: return sf::Mouse::Left;
case BTN_RIGHT: return sf::Mouse::Right;
case BTN_MIDDLE: return sf::Mouse::Middle;
case BTN_SIDE: return sf::Mouse::XButton1;
case BTN_EXTRA: return sf::Mouse::XButton2;
default:
return sf::Mouse::ButtonCount;
}
}
sf::Keyboard::Key toKey(int code)
{
switch (code)
{
case KEY_ESC: return sf::Keyboard::Escape;
case KEY_1: return sf::Keyboard::Num1;
case KEY_2: return sf::Keyboard::Num2;
case KEY_3: return sf::Keyboard::Num3;
case KEY_4: return sf::Keyboard::Num4;
case KEY_5: return sf::Keyboard::Num5;
case KEY_6: return sf::Keyboard::Num6;
case KEY_7: return sf::Keyboard::Num7;
case KEY_8: return sf::Keyboard::Num8;
case KEY_9: return sf::Keyboard::Num9;
case KEY_0: return sf::Keyboard::Num0;
case KEY_MINUS: return sf::Keyboard::Hyphen;
case KEY_EQUAL: return sf::Keyboard::Equal;
case KEY_BACKSPACE: return sf::Keyboard::Backspace;
case KEY_TAB: return sf::Keyboard::Tab;
case KEY_Q: return sf::Keyboard::Q;
case KEY_W: return sf::Keyboard::W;
case KEY_E: return sf::Keyboard::E;
case KEY_R: return sf::Keyboard::R;
case KEY_T: return sf::Keyboard::T;
case KEY_Y: return sf::Keyboard::Y;
case KEY_U: return sf::Keyboard::U;
case KEY_I: return sf::Keyboard::I;
case KEY_O: return sf::Keyboard::O;
case KEY_P: return sf::Keyboard::P;
case KEY_LEFTBRACE: return sf::Keyboard::LBracket;
case KEY_RIGHTBRACE: return sf::Keyboard::RBracket;
case KEY_KPENTER:
case KEY_ENTER: return sf::Keyboard::Enter;
case KEY_LEFTCTRL: return sf::Keyboard::LControl;
case KEY_A: return sf::Keyboard::A;
case KEY_S: return sf::Keyboard::S;
case KEY_D: return sf::Keyboard::D;
case KEY_F: return sf::Keyboard::F;
case KEY_G: return sf::Keyboard::G;
case KEY_H: return sf::Keyboard::H;
case KEY_J: return sf::Keyboard::J;
case KEY_K: return sf::Keyboard::K;
case KEY_L: return sf::Keyboard::L;
case KEY_SEMICOLON: return sf::Keyboard::Semicolon;
case KEY_APOSTROPHE: return sf::Keyboard::Quote;
case KEY_GRAVE: return sf::Keyboard::Tilde;
case KEY_LEFTSHIFT: return sf::Keyboard::LShift;
case KEY_BACKSLASH: return sf::Keyboard::Backslash;
case KEY_Z: return sf::Keyboard::Z;
case KEY_X: return sf::Keyboard::X;
case KEY_C: return sf::Keyboard::C;
case KEY_V: return sf::Keyboard::V;
case KEY_B: return sf::Keyboard::B;
case KEY_N: return sf::Keyboard::N;
case KEY_M: return sf::Keyboard::M;
case KEY_COMMA: return sf::Keyboard::Comma;
case KEY_DOT: return sf::Keyboard::Period;
case KEY_SLASH: return sf::Keyboard::Slash;
case KEY_RIGHTSHIFT: return sf::Keyboard::RShift;
case KEY_KPASTERISK: return sf::Keyboard::Multiply;
case KEY_LEFTALT: return sf::Keyboard::LAlt;
case KEY_SPACE: return sf::Keyboard::Space;
case KEY_F1: return sf::Keyboard::F1;
case KEY_F2: return sf::Keyboard::F2;
case KEY_F3: return sf::Keyboard::F3;
case KEY_F4: return sf::Keyboard::F4;
case KEY_F5: return sf::Keyboard::F5;
case KEY_F6: return sf::Keyboard::F6;
case KEY_F7: return sf::Keyboard::F7;
case KEY_F8: return sf::Keyboard::F8;
case KEY_F9: return sf::Keyboard::F9;
case KEY_F10: return sf::Keyboard::F10;
case KEY_F11: return sf::Keyboard::F11;
case KEY_F12: return sf::Keyboard::F12;
case KEY_F13: return sf::Keyboard::F13;
case KEY_F14: return sf::Keyboard::F14;
case KEY_F15: return sf::Keyboard::F15;
case KEY_KP7: return sf::Keyboard::Numpad7;
case KEY_KP8: return sf::Keyboard::Numpad8;
case KEY_KP9: return sf::Keyboard::Numpad9;
case KEY_KPMINUS: return sf::Keyboard::Subtract;
case KEY_KP4: return sf::Keyboard::Numpad4;
case KEY_KP5: return sf::Keyboard::Numpad5;
case KEY_KP6: return sf::Keyboard::Numpad6;
case KEY_KPPLUS: return sf::Keyboard::Add;
case KEY_KP1: return sf::Keyboard::Numpad1;
case KEY_KP2: return sf::Keyboard::Numpad2;
case KEY_KP3: return sf::Keyboard::Numpad3;
case KEY_KP0: return sf::Keyboard::Numpad0;
case KEY_KPDOT: return sf::Keyboard::Delete;
case KEY_RIGHTCTRL: return sf::Keyboard::RControl;
case KEY_KPSLASH: return sf::Keyboard::Divide;
case KEY_RIGHTALT: return sf::Keyboard::RAlt;
case KEY_HOME: return sf::Keyboard::Home;
case KEY_UP: return sf::Keyboard::Up;
case KEY_PAGEUP: return sf::Keyboard::PageUp;
case KEY_LEFT: return sf::Keyboard::Left;
case KEY_RIGHT: return sf::Keyboard::Right;
case KEY_END: return sf::Keyboard::End;
case KEY_DOWN: return sf::Keyboard::Down;
case KEY_PAGEDOWN: return sf::Keyboard::PageDown;
case KEY_INSERT: return sf::Keyboard::Insert;
case KEY_DELETE: return sf::Keyboard::Delete;
case KEY_PAUSE: return sf::Keyboard::Pause;
case KEY_LEFTMETA: return sf::Keyboard::LSystem;
case KEY_RIGHTMETA: return sf::Keyboard::RSystem;
case KEY_RESERVED:
case KEY_SYSRQ:
case KEY_CAPSLOCK:
case KEY_NUMLOCK:
case KEY_SCROLLLOCK:
default:
return sf::Keyboard::Unknown;
}
}
void pushEvent(sf::Event& event)
{
if (eventQueue.size() >= MAX_QUEUE)
eventQueue.pop();
eventQueue.push(event);
}
TouchSlot& atSlot(int idx)
{
if (idx >= static_cast<int>(touchSlots.size()))
touchSlots.resize(static_cast<size_t>(idx + 1));
return touchSlots.at(static_cast<size_t>(idx));
}
void processSlots()
{
for (std::vector<TouchSlot>::iterator slot = touchSlots.begin(); slot != touchSlots.end(); ++slot)
{
sf::Event event;
event.touch.x = slot->pos.x;
event.touch.y = slot->pos.y;
if (slot->oldId == slot->id)
{
event.type = sf::Event::TouchMoved;
event.touch.finger = static_cast<unsigned int>(slot->id);
pushEvent(event);
}
else
{
if (slot->oldId != -1)
{
event.type = sf::Event::TouchEnded;
event.touch.finger = static_cast<unsigned int>(slot->oldId);
pushEvent(event);
}
if (slot->id != -1)
{
event.type = sf::Event::TouchBegan;
event.touch.finger = static_cast<unsigned int>(slot->id);
pushEvent(event);
}
slot->oldId = slot->id;
}
}
}
bool eventProcess(sf::Event& event)
{
std::scoped_lock lock(inputMutex);
// Ensure that we are initialized
initFileDescriptors();
// This is for handling the Backspace and DEL text events, which we
// generate based on keystrokes (and not stdin)
static unsigned int doDeferredText = 0;
if (doDeferredText)
{
event.type = sf::Event::TextEntered;
event.text.unicode = doDeferredText;
doDeferredText = 0;
return true;
}
ssize_t bytesRead;
// Check all the open file descriptors for the next event
for (std::vector<int>::iterator itr = fileDescriptors.begin(); itr != fileDescriptors.end(); ++itr)
{
input_event inputEvent;
bytesRead = read(*itr, &inputEvent, sizeof(inputEvent));
while (bytesRead > 0)
{
if (inputEvent.type == EV_KEY)
{
sf::Mouse::Button mb = toMouseButton(inputEvent.code);
if (mb != sf::Mouse::ButtonCount)
{
event.type = inputEvent.value ? sf::Event::MouseButtonPressed : sf::Event::MouseButtonReleased;
event.mouseButton.button = mb;
event.mouseButton.x = mousePos.x;
event.mouseButton.y = mousePos.y;
mouseMap[mb] = inputEvent.value;
return true;
}
else
{
sf::Keyboard::Key kb = toKey(inputEvent.code);
unsigned int special = 0;
if ((kb == sf::Keyboard::Delete)
|| (kb == sf::Keyboard::Backspace))
special = (kb == sf::Keyboard::Delete) ? 127 : 8;
if (inputEvent.value == 2)
{
// key repeat events
//
if (special)
{
event.type = sf::Event::TextEntered;
event.text.unicode = special;
return true;
}
}
else if (kb != sf::Keyboard::Unknown)
{
// key down and key up events
//
event.type = inputEvent.value ? sf::Event::KeyPressed : sf::Event::KeyReleased;
event.key.code = kb;
event.key.alt = altDown();
event.key.control = controlDown();
event.key.shift = shiftDown();
event.key.system = systemDown();
keyMap[kb] = inputEvent.value;
if (special && inputEvent.value)
doDeferredText = special;
return true;
}
}
}
else if (inputEvent.type == EV_REL)
{
bool posChange = false;
switch (inputEvent.code)
{
case REL_X:
mousePos.x += inputEvent.value;
posChange = true;
break;
case REL_Y:
mousePos.y += inputEvent.value;
posChange = true;
break;
case REL_WHEEL:
event.type = sf::Event::MouseWheelScrolled;
event.mouseWheelScroll.delta = static_cast<float>(inputEvent.value);
event.mouseWheelScroll.x = mousePos.x;
event.mouseWheelScroll.y = mousePos.y;
return true;
}
if (posChange)
{
event.type = sf::Event::MouseMoved;
event.mouseMove.x = mousePos.x;
event.mouseMove.y = mousePos.y;
return true;
}
}
else if (inputEvent.type == EV_ABS)
{
switch (inputEvent.code)
{
case ABS_MT_SLOT:
currentSlot = inputEvent.value;
touchFd = *itr;
break;
case ABS_MT_TRACKING_ID:
atSlot(currentSlot).id = inputEvent.value;
touchFd = *itr;
break;
case ABS_MT_POSITION_X:
atSlot(currentSlot).pos.x = inputEvent.value;
touchFd = *itr;
break;
case ABS_MT_POSITION_Y:
atSlot(currentSlot).pos.y = inputEvent.value;
touchFd = *itr;
break;
}
}
else if (inputEvent.type == EV_SYN && inputEvent.code == SYN_REPORT &&
*itr == touchFd)
{
// This pushes events directly to the queue, because it
// can generate more than one event.
processSlots();
}
bytesRead = read(*itr, &inputEvent, sizeof(inputEvent));
}
if ((bytesRead < 0) && (errno != EAGAIN))
sf::err() << " Error: " << std::strerror(errno) << std::endl;
}
// Finally check if there is a Text event on stdin
//
// We only clear the ICANON flag for the time of reading
newTerminalConfig.c_lflag &= ~(tcflag_t)ICANON;
tcsetattr(STDIN_FILENO, TCSANOW, &newTerminalConfig);
timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
unsigned char code = 0;
fd_set readFDSet;
FD_ZERO(&readFDSet);
FD_SET(STDIN_FILENO, &readFDSet);
int ready = select(STDIN_FILENO + 1, &readFDSet, NULL, NULL, &timeout);
if (ready > 0 && FD_ISSET(STDIN_FILENO, &readFDSet))
bytesRead = read(STDIN_FILENO, &code, 1);
if ((code == 127) || (code == 8)) // Suppress 127 (DEL) to 8 (BACKSPACE)
code = 0;
else if (code == 27) // ESC
{
// Suppress ANSI escape sequences
FD_ZERO(&readFDSet);
FD_SET(STDIN_FILENO, &readFDSet);
ready = select(STDIN_FILENO + 1, &readFDSet, NULL, NULL, &timeout);
if (ready > 0 && FD_ISSET(STDIN_FILENO, &readFDSet))
{
unsigned char tempBuffer[16];
bytesRead = read(STDIN_FILENO, tempBuffer, 16);
code = 0;
}
}
newTerminalConfig.c_lflag |= ICANON;
tcsetattr(STDIN_FILENO, TCSANOW, &newTerminalConfig);
if (code > 0)
{
// TODO: Proper unicode handling
event.type = sf::Event::TextEntered;
event.text.unicode = code;
return true;
}
// No events available
return false;
}
// assumes inputMutex is locked
void update()
{
sf::Event event;
while (eventProcess(event))
{
pushEvent(event);
}
}
}
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
bool InputImpl::isKeyPressed(Keyboard::Key key)
{
std::scoped_lock lock(inputMutex);
if ((key < 0) || (key >= static_cast<int>(keyMap.size())))
return false;
update();
return keyMap[key];
}
////////////////////////////////////////////////////////////
void InputImpl::setVirtualKeyboardVisible(bool /*visible*/)
{
// Not applicable
}
////////////////////////////////////////////////////////////
bool InputImpl::isMouseButtonPressed(Mouse::Button button)
{
std::scoped_lock lock(inputMutex);
if ((button < 0) || (button >= static_cast<int>(mouseMap.size())))
return false;
update();
return mouseMap[button];
}
////////////////////////////////////////////////////////////
Vector2i InputImpl::getMousePosition()
{
std::scoped_lock lock(inputMutex);
return mousePos;
}
////////////////////////////////////////////////////////////
Vector2i InputImpl::getMousePosition(const WindowBase& /*relativeTo*/)
{
return getMousePosition();
}
////////////////////////////////////////////////////////////
void InputImpl::setMousePosition(const Vector2i& position)
{
std::scoped_lock lock(inputMutex);
mousePos = position;
}
////////////////////////////////////////////////////////////
void InputImpl::setMousePosition(const Vector2i& position, const WindowBase& /*relativeTo*/)
{
setMousePosition(position);
}
////////////////////////////////////////////////////////////
bool InputImpl::isTouchDown(unsigned int finger)
{
for (std::vector<TouchSlot>::iterator slot = touchSlots.begin(); slot != touchSlots.end(); ++slot)
{
if (slot->id == static_cast<int>(finger))
return true;
}
return false;
}
////////////////////////////////////////////////////////////
Vector2i InputImpl::getTouchPosition(unsigned int finger)
{
for (std::vector<TouchSlot>::iterator slot = touchSlots.begin(); slot != touchSlots.end(); ++slot)
{
if (slot->id == static_cast<int>(finger))
return slot->pos;
}
return Vector2i();
}
////////////////////////////////////////////////////////////
Vector2i InputImpl::getTouchPosition(unsigned int finger, const WindowBase& /*relativeTo*/)
{
return getTouchPosition(finger);
}
////////////////////////////////////////////////////////////
bool InputImpl::checkEvent(sf::Event& event)
{
std::scoped_lock lock(inputMutex);
if (!eventQueue.empty())
{
event = eventQueue.front();
eventQueue.pop();
return true;
}
if (eventProcess(event))
{
return true;
}
else
{
// In the case of multitouch, eventProcess() could have returned false
// but added events directly to the queue. (This is ugly, but I'm not
// sure of a good way to handle generating multiple events at once.)
if (!eventQueue.empty())
{
event = eventQueue.front();
eventQueue.pop();
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////
void InputImpl::setTerminalConfig()
{
std::scoped_lock lock(inputMutex);
initFileDescriptors();
tcgetattr(STDIN_FILENO, &newTerminalConfig); // get current terminal config
oldTerminalConfig = newTerminalConfig; // create a backup
newTerminalConfig.c_lflag &= ~(tcflag_t)ECHO; // disable console feedback
newTerminalConfig.c_lflag &= ~(tcflag_t)ISIG; // disable signals
newTerminalConfig.c_lflag |= ICANON; // disable noncanonical mode
newTerminalConfig.c_iflag |= IGNCR; // ignore carriage return
tcsetattr(STDIN_FILENO, TCSANOW, &newTerminalConfig); // set our new config
tcflush(STDIN_FILENO, TCIFLUSH); // flush the buffer
}
////////////////////////////////////////////////////////////
void InputImpl::restoreTerminalConfig()
{
std::scoped_lock lock(inputMutex);
initFileDescriptors();
tcsetattr(STDIN_FILENO, TCSANOW, &oldTerminalConfig); // restore terminal config
tcflush(STDIN_FILENO, TCIFLUSH); // flush the buffer
}
} // namespace priv
} // namespace sf

View File

@ -0,0 +1,193 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2016 Andrew Mickelson
//
// 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.
//
////////////////////////////////////////////////////////////
#ifndef SFML_INPUTIMPLUDEV_HPP
#define SFML_INPUTIMPLUDEV_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/Keyboard.hpp>
#include <SFML/Window/Mouse.hpp>
#include <SFML/Window/Event.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief Linux (DRM) implementation of inputs (keyboard + mouse)
///
////////////////////////////////////////////////////////////
class InputImpl
{
public:
////////////////////////////////////////////////////////////
/// \brief Check if a key is pressed
///
/// \param key Key to check
///
/// \return True if the key is pressed, false otherwise
///
////////////////////////////////////////////////////////////
static bool isKeyPressed(Keyboard::Key key);
////////////////////////////////////////////////////////////
/// \brief Show or hide the virtual keyboard
///
/// \param visible True to show, false to hide
///
////////////////////////////////////////////////////////////
static void setVirtualKeyboardVisible(bool visible);
////////////////////////////////////////////////////////////
/// \brief Check if a mouse button is pressed
///
/// \param button Button to check
///
/// \return True if the button is pressed, false otherwise
///
////////////////////////////////////////////////////////////
static bool isMouseButtonPressed(Mouse::Button button);
////////////////////////////////////////////////////////////
/// \brief Get the current position of the mouse in desktop coordinates
///
/// This function returns the current position of the mouse
/// cursor, in global (desktop) coordinates.
///
/// \return Current position of the mouse
///
////////////////////////////////////////////////////////////
static Vector2i getMousePosition();
////////////////////////////////////////////////////////////
/// \brief Get the current position of the mouse in window coordinates
///
/// This function returns the current position of the mouse
/// cursor, relative to the given window.
/// If no window is used, it returns desktop coordinates.
///
/// \param relativeTo Reference window
///
/// \return Current position of the mouse
///
////////////////////////////////////////////////////////////
static Vector2i getMousePosition(const WindowBase& relativeTo);
////////////////////////////////////////////////////////////
/// \brief Set the current position of the mouse in desktop coordinates
///
/// This function sets the current position of the mouse
/// cursor in global (desktop) coordinates.
/// If no window is used, it sets the position in desktop coordinates.
///
/// \param position New position of the mouse
///
////////////////////////////////////////////////////////////
static void setMousePosition(const Vector2i& position);
////////////////////////////////////////////////////////////
/// \brief Set the current position of the mouse in window coordinates
///
/// This function sets the current position of the mouse
/// cursor, relative to the given window.
/// If no window is used, it sets the position in desktop coordinates.
///
/// \param position New position of the mouse
/// \param relativeTo Reference window
///
////////////////////////////////////////////////////////////
static void setMousePosition(const Vector2i& position, const WindowBase& relativeTo);
////////////////////////////////////////////////////////////
/// \brief Check if a touch event is currently down
///
/// \param finger Finger index
///
/// \return True if \a finger is currently touching the screen, false otherwise
///
////////////////////////////////////////////////////////////
static bool isTouchDown(unsigned int finger);
////////////////////////////////////////////////////////////
/// \brief Get the current position of a touch in desktop coordinates
///
/// This function returns the current touch position
/// in global (desktop) coordinates.
///
/// \param finger Finger index
///
/// \return Current position of \a finger, or undefined if it's not down
///
////////////////////////////////////////////////////////////
static Vector2i getTouchPosition(unsigned int finger);
////////////////////////////////////////////////////////////
/// \brief Get the current position of a touch in window coordinates
///
/// This function returns the current touch position
/// in global (desktop) coordinates.
///
/// \param finger Finger index
/// \param relativeTo Reference window
///
/// \return Current position of \a finger, or undefined if it's not down
///
////////////////////////////////////////////////////////////
static Vector2i getTouchPosition(unsigned int finger, const WindowBase& relativeTo);
private:
friend class WindowImplDRM;
////////////////////////////////////////////////////////////
/// \brief Fetch input event from event queue
///
/// \return False if event queue is empty
///
////////////////////////////////////////////////////////////
static bool checkEvent(sf::Event& event);
////////////////////////////////////////////////////////////
/// \brief Backup terminal configuration and disable console feedback
///
////////////////////////////////////////////////////////////
static void setTerminalConfig();
////////////////////////////////////////////////////////////
/// \brief Restore terminal configuration from backup
///
////////////////////////////////////////////////////////////
static void restoreTerminalConfig();
};
} // namespace priv
} // namespace sf
#endif // SFML_INPUTIMPLUDEV_HPP

View File

@ -0,0 +1,73 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2020 Andrew Mickelson
//
// 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/Window/DRM/DRMContext.hpp>
#include <SFML/System/Err.hpp>
#include <drm-common.h>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
{
std::vector<VideoMode> modes;
drm* drm = sf::priv::DRMContext::getDRM();
drmModeConnectorPtr conn = drm->saved_connector;
if (conn)
{
for (int i = 0; i < conn->count_modes; i++)
modes.push_back(
VideoMode(conn->modes[i].hdisplay,
conn->modes[i].vdisplay));
}
else
modes.push_back(getDesktopMode());
return modes;
}
////////////////////////////////////////////////////////////
VideoMode VideoModeImpl::getDesktopMode()
{
drm* drm = sf::priv::DRMContext::getDRM();
drmModeModeInfoPtr ptr = drm->mode;
if (ptr)
return VideoMode(ptr->hdisplay, ptr->vdisplay);
else
return VideoMode(0, 0);
}
} // namespace priv
} // namespace sf

View File

@ -0,0 +1,161 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2020 Andrew Mickelson
//
// 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/DRM/WindowImplDRM.hpp>
#include <SFML/Window/DRM/DRMContext.hpp>
#include <SFML/Window/DRM/InputImplUDev.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Window/WindowStyle.hpp>
#include <SFML/System/Err.hpp>
#include <drm-common.h>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
WindowImplDRM::WindowImplDRM(WindowHandle /*handle*/) :
m_size(0, 0)
{
sf::priv::InputImpl::setTerminalConfig();
}
////////////////////////////////////////////////////////////
WindowImplDRM::WindowImplDRM(VideoMode mode, const String& /*title*/, unsigned long /*style*/, const ContextSettings& /*settings*/) :
m_size(mode.width, mode.height)
{
sf::priv::InputImpl::setTerminalConfig();
}
////////////////////////////////////////////////////////////
WindowImplDRM::~WindowImplDRM()
{
sf::priv::InputImpl::restoreTerminalConfig();
}
////////////////////////////////////////////////////////////
WindowHandle WindowImplDRM::getSystemHandle() const
{
drm* drm = sf::priv::DRMContext::getDRM();
return static_cast<WindowHandle>(drm->fd);
}
////////////////////////////////////////////////////////////
Vector2i WindowImplDRM::getPosition() const
{
return Vector2i(0, 0);
}
////////////////////////////////////////////////////////////
void WindowImplDRM::setPosition(const Vector2i& /*position*/)
{
}
////////////////////////////////////////////////////////////
Vector2u WindowImplDRM::getSize() const
{
return m_size;
}
////////////////////////////////////////////////////////////
void WindowImplDRM::setSize(const Vector2u& /*size*/)
{
}
////////////////////////////////////////////////////////////
void WindowImplDRM::setTitle(const String& /*title*/)
{
}
////////////////////////////////////////////////////////////
void WindowImplDRM::setIcon(unsigned int /*width*/, unsigned int /*height*/, const Uint8* /*pixels*/)
{
}
////////////////////////////////////////////////////////////
void WindowImplDRM::setVisible(bool /*visible*/)
{
}
////////////////////////////////////////////////////////////
void WindowImplDRM::setMouseCursorVisible(bool /*visible*/)
{
// TODO: not implemented
}
////////////////////////////////////////////////////////////
void WindowImplDRM::setMouseCursorGrabbed(bool /*grabbed*/)
{
//TODO: not implemented
}
////////////////////////////////////////////////////////////
void WindowImplDRM::setMouseCursor(const CursorImpl& /*cursor*/)
{
// TODO: not implemented
}
////////////////////////////////////////////////////////////
void WindowImplDRM::setKeyRepeatEnabled(bool /*enabled*/)
{
// TODO: not implemented
}
////////////////////////////////////////////////////////////
void WindowImplDRM::requestFocus()
{
// Not applicable
}
////////////////////////////////////////////////////////////
bool WindowImplDRM::hasFocus() const
{
return true;
}
void WindowImplDRM::processEvents()
{
sf::Event ev;
while (sf::priv::InputImpl::checkEvent(ev))
pushEvent(ev);
}
} // namespace priv
} // namespace sf

View File

@ -0,0 +1,205 @@
////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2020 Andrew Mickelson
//
// 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.
//
////////////////////////////////////////////////////////////
#ifndef SFML_WINDOWIMPLDRM_HPP
#define SFML_WINDOWIMPLDRM_HPP
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/Event.hpp>
#include <SFML/Window/WindowImpl.hpp>
namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
/// \brief DRM implementation of WindowImpl
///
////////////////////////////////////////////////////////////
class WindowImplDRM : public WindowImpl
{
public:
////////////////////////////////////////////////////////////
/// \brief Construct the window implementation from an existing control
///
/// \param handle Platform-specific handle of the control
///
////////////////////////////////////////////////////////////
WindowImplDRM(WindowHandle handle);
////////////////////////////////////////////////////////////
/// \brief Create the window implementation
///
/// \param mode Video mode to use
/// \param title Title of the window
/// \param style Window style (resizable, fixed, or fullscren)
/// \param settings Additional settings for the underlying OpenGL context
///
////////////////////////////////////////////////////////////
WindowImplDRM(VideoMode mode, const String& title, unsigned long style, const ContextSettings& settings);
////////////////////////////////////////////////////////////
/// \brief Destructor
///
////////////////////////////////////////////////////////////
~WindowImplDRM();
////////////////////////////////////////////////////////////
/// \brief Get the OS-specific handle of the window
///
/// \return Handle of the window
///
////////////////////////////////////////////////////////////
virtual WindowHandle getSystemHandle() const override;
////////////////////////////////////////////////////////////
/// \brief Get the position of the window
///
/// \return Position of the window, in pixels
///
////////////////////////////////////////////////////////////
virtual Vector2i getPosition() const override;
////////////////////////////////////////////////////////////
/// \brief Change the position of the window on screen
///
/// \param position New position of the window, in pixels
///
////////////////////////////////////////////////////////////
virtual void setPosition(const Vector2i& position) override;
////////////////////////////////////////////////////////////
/// \brief Get the client size of the window
///
/// \return Size of the window, in pixels
///
////////////////////////////////////////////////////////////
virtual Vector2u getSize() const override;
////////////////////////////////////////////////////////////
/// \brief Change the size of the rendering region of the window
///
/// \param size New size, in pixels
///
////////////////////////////////////////////////////////////
virtual void setSize(const Vector2u& size) override;
////////////////////////////////////////////////////////////
/// \brief Change the title of the window
///
/// \param title New title
///
////////////////////////////////////////////////////////////
virtual void setTitle(const String& title) override;
////////////////////////////////////////////////////////////
/// \brief Change the window's icon
///
/// \param width Icon's width, in pixels
/// \param height Icon's height, in pixels
/// \param pixels Pointer to the pixels in memory, format must be RGBA 32 bits
///
////////////////////////////////////////////////////////////
virtual void setIcon(unsigned int width, unsigned int height, const Uint8* pixels) override;
////////////////////////////////////////////////////////////
/// \brief Show or hide the window
///
/// \param visible True to show, false to hide
///
////////////////////////////////////////////////////////////
virtual void setVisible(bool visible) override;
////////////////////////////////////////////////////////////
/// \brief Show or hide the mouse cursor
///
/// \param visible True to show, false to hide
///
////////////////////////////////////////////////////////////
virtual void setMouseCursorVisible(bool visible) override;
////////////////////////////////////////////////////////////
/// \brief Grab or release the mouse cursor
///
/// \param grabbed True to enable, false to disable
///
////////////////////////////////////////////////////////////
virtual void setMouseCursorGrabbed(bool grabbed) override;
////////////////////////////////////////////////////////////
/// \brief Set the displayed cursor to a native system cursor
///
/// \param cursor Native system cursor type to display
///
////////////////////////////////////////////////////////////
virtual void setMouseCursor(const CursorImpl& cursor) override;
////////////////////////////////////////////////////////////
/// \brief Enable or disable automatic key-repeat
///
/// \param enabled True to enable, false to disable
///
////////////////////////////////////////////////////////////
virtual void setKeyRepeatEnabled(bool enabled) override;
////////////////////////////////////////////////////////////
/// \brief Request the current window to be made the active
/// foreground window
///
////////////////////////////////////////////////////////////
virtual void requestFocus() override;
////////////////////////////////////////////////////////////
/// \brief Check whether the window has the input focus
///
/// \return True if window has focus, false otherwise
///
////////////////////////////////////////////////////////////
virtual bool hasFocus() const override;
protected:
////////////////////////////////////////////////////////////
/// \brief Process incoming events from the operating system
///
////////////////////////////////////////////////////////////
virtual void processEvents() override;
private:
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
Vector2u m_size; ///< Window size
};
} // namespace priv
} // namespace sf
#endif // SFML_WINDOWIMPLDRM_HPP

View File

@ -35,7 +35,7 @@
#ifdef SFML_SYSTEM_ANDROID
#include <SFML/System/Android/Activity.hpp>
#endif
#ifdef SFML_SYSTEM_LINUX
#if defined(SFML_SYSTEM_LINUX) && !defined(SFML_USE_DRM)
#include <X11/Xlib.h>
#endif
@ -361,7 +361,7 @@ void EglContext::updateSettings()
}
#ifdef SFML_SYSTEM_LINUX
#if defined(SFML_SYSTEM_LINUX) && !defined(SFML_USE_DRM)
////////////////////////////////////////////////////////////
XVisualInfo EglContext::selectBestVisual(::Display* XDisplay, unsigned int bitsPerPixel, const ContextSettings& settings)
{

View File

@ -34,7 +34,7 @@
#include <SFML/Window/GlContext.hpp>
#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
#include <glad/egl.h>
#ifdef SFML_SYSTEM_LINUX
#if defined(SFML_SYSTEM_LINUX) && !defined(SFML_USE_DRM)
#include <X11/Xlib.h>
#endif
@ -165,7 +165,7 @@ public:
////////////////////////////////////////////////////////////
static EGLConfig getBestConfig(EGLDisplay display, unsigned int bitsPerPixel, const ContextSettings& settings);
#ifdef SFML_SYSTEM_LINUX
#if defined(SFML_SYSTEM_LINUX) && !defined(SFML_USE_DRM)
////////////////////////////////////////////////////////////
/// \brief Select the best EGL visual for a given set of settings
///

View File

@ -65,6 +65,11 @@
using ContextType = sf::priv::EglContext;
#elif defined(SFML_USE_DRM)
#include <SFML/Window/DRM/DRMContext.hpp>
using ContextType = sf::priv::DRMContext;
#else
#include <SFML/Window/Unix/GlxContext.hpp>

View File

@ -33,7 +33,11 @@
#if defined(SFML_SYSTEM_WINDOWS)
#include <SFML/Window/Win32/InputImpl.hpp>
#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD)
#if defined(SFML_USE_DRM)
#include <SFML/Window/DRM/InputImplUDev.hpp>
#else
#include <SFML/Window/Unix/InputImpl.hpp>
#endif
#elif defined(SFML_SYSTEM_MACOS)
#include <SFML/Window/OSX/InputImpl.hpp>
#elif defined(SFML_SYSTEM_IOS)
@ -42,5 +46,4 @@
#include <SFML/Window/Android/InputImpl.hpp>
#endif
#endif // SFML_INPUTIMPL_HPP

View File

@ -34,8 +34,16 @@ using VulkanImplType = sf::priv::VulkanImplWin32;
#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD)
#include <SFML/Window/Unix/VulkanImplX11.hpp>
using VulkanImplType = sf::priv::VulkanImplX11;
#if defined(SFML_USE_DRM)
#define SFML_VULKAN_IMPLEMENTATION_NOT_AVAILABLE
#else
#include <SFML/Window/Unix/VulkanImplX11.hpp>
using VulkanImplType = sf::priv::VulkanImplX11;
#endif
#else

View File

@ -46,12 +46,23 @@
#elif defined(SFML_SYSTEM_LINUX) || defined(SFML_SYSTEM_FREEBSD) || defined(SFML_SYSTEM_OPENBSD) || defined(SFML_SYSTEM_NETBSD)
#if defined(SFML_USE_DRM)
#include <SFML/Window/DRM/WindowImplDRM.hpp>
using WindowImplType = sf::priv::WindowImplDRM;
#define SFML_VULKAN_IMPLEMENTATION_NOT_AVAILABLE
#else
#include <SFML/Window/Unix/WindowImplX11.hpp>
using WindowImplType = sf::priv::WindowImplX11;
#include <SFML/Window/Unix/VulkanImplX11.hpp>
using VulkanImplType = sf::priv::VulkanImplX11;
#endif
#elif defined(SFML_SYSTEM_MACOS)
#include <SFML/Window/OSX/WindowImplCocoa.hpp>
@ -80,6 +91,7 @@ namespace sf
{
namespace priv
{
////////////////////////////////////////////////////////////
struct WindowImpl::JoystickStatesImpl
{