Merge branch '2.6.x' into master

This commit is contained in:
Lukas Dürrenberger 2022-10-25 18:30:33 +02:00
commit d4d518e1be
5 changed files with 140 additions and 106 deletions

View File

@ -18,8 +18,8 @@ jobs:
- { name: Windows VS2022 Clang, os: windows-2022, flags: -T ClangCL } - { name: Windows VS2022 Clang, os: windows-2022, flags: -T ClangCL }
- { name: Linux GCC, os: ubuntu-latest } - { name: Linux GCC, os: ubuntu-latest }
- { name: Linux Clang, os: ubuntu-latest, flags: -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, gcovr_options: '--gcov-executable="llvm-cov-$CLANG_VERSION gcov"' } - { name: Linux Clang, os: ubuntu-latest, flags: -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, gcovr_options: '--gcov-executable="llvm-cov-$CLANG_VERSION gcov"' }
- { name: MacOS, os: macos-latest } - { name: MacOS, os: macos-11 }
- { name: MacOS Xcode, os: macos-latest, flags: -GXcode } - { name: MacOS Xcode, os: macos-11, flags: -GXcode }
config: config:
- { name: Shared, flags: -DBUILD_SHARED_LIBS=TRUE } - { name: Shared, flags: -DBUILD_SHARED_LIBS=TRUE }
- { name: Static, flags: -DBUILD_SHARED_LIBS=FALSE } - { name: Static, flags: -DBUILD_SHARED_LIBS=FALSE }
@ -34,9 +34,9 @@ jobs:
- platform: { name: Windows VS2022, os: windows-2022 } - platform: { name: Windows VS2022, os: windows-2022 }
config: { name: Unity, flags: -DBUILD_SHARED_LIBS=TRUE -DCMAKE_UNITY_BUILD=ON } config: { name: Unity, flags: -DBUILD_SHARED_LIBS=TRUE -DCMAKE_UNITY_BUILD=ON }
type: { name: Debug, flags: -DCMAKE_BUILD_TYPE=Debug -DSFML_ENABLE_COVERAGE=TRUE } type: { name: Debug, flags: -DCMAKE_BUILD_TYPE=Debug -DSFML_ENABLE_COVERAGE=TRUE }
- platform: { name: MacOS, os: macos-latest } - platform: { name: MacOS, os: macos-11 }
config: { name: Frameworks, flags: -DSFML_BUILD_FRAMEWORKS=TRUE } config: { name: Frameworks, flags: -DSFML_BUILD_FRAMEWORKS=TRUE }
- platform: { name: MacOS, os: macos-latest } - platform: { name: MacOS, os: macos-11 }
config: { name: iOS, flags: -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/cmake/toolchains/iOS.toolchain.cmake -DIOS_PLATFORM=SIMULATOR } config: { name: iOS, flags: -DCMAKE_TOOLCHAIN_FILE=$GITHUB_WORKSPACE/cmake/toolchains/iOS.toolchain.cmake -DIOS_PLATFORM=SIMULATOR }
- platform: { name: Android, os: ubuntu-latest } - platform: { name: Android, os: ubuntu-latest }
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 } 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 }

View File

@ -170,6 +170,26 @@ static int get_resources(int fd, drmModeRes **resources)
return 0; return 0;
} }
static int has_monitor_connected(int fd, drmModeRes* resources)
{
int i;
drmModeConnector *connector;
for (i = 0; i < resources->count_connectors; i++)
{
connector = drmModeGetConnector(fd, resources->connectors[i]);
if (connector->connection == DRM_MODE_CONNECTED)
{
/* There is a monitor connected */
drmModeFreeConnector(connector);
connector = NULL;
return 1;
}
drmModeFreeConnector(connector);
connector = NULL;
}
return 0;
}
#define MAX_DRM_DEVICES 64 #define MAX_DRM_DEVICES 64
static int find_drm_device(drmModeRes **resources) static int find_drm_device(drmModeRes **resources)
@ -199,7 +219,11 @@ static int find_drm_device(drmModeRes **resources)
if (fd < 0) if (fd < 0)
continue; continue;
ret = get_resources(fd, resources); ret = get_resources(fd, resources);
if (!ret) if(getenv("SFML_DRM_DEBUG"))
{
printf("DRM device used: %d\n", i);
}
if(!ret && has_monitor_connected(fd, *resources) != 0)
break; break;
close(fd); close(fd);
fd = -1; fd = -1;
@ -285,34 +309,6 @@ int init_drm(struct drm *drm, const char *device, const char *mode_str,
printf("requested mode not found, using default mode!\n"); 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: */ /* find encoder: */
for (i = 0; i < resources->count_encoders; i++) for (i = 0; i < resources->count_encoders; i++)
{ {
@ -349,6 +345,16 @@ int init_drm(struct drm *drm, const char *device, const char *mode_str,
// get original display mode so we can restore display mode after program exits // get original display mode so we can restore display mode after program exits
drm->original_crtc = drmModeGetCrtc(drm->fd, drm->crtc_id); drm->original_crtc = drmModeGetCrtc(drm->fd, drm->crtc_id);
/* Let's use the current mode rather than the preferred one if the user didn't
* specify a mode with env vars
*/
if (!drm->mode)
{
if(getenv("SFML_DRM_DEBUG"))
printf("DRM using the current mode\n");
drm->mode = &(drm->original_crtc->mode);
}
if (getenv("SFML_DRM_DEBUG")) if (getenv("SFML_DRM_DEBUG"))
{ {
printf("DRM Mode used: %s@%d\n", drm->mode->name, drm->mode->vrefresh); printf("DRM Mode used: %s@%d\n", drm->mode->name, drm->mode->vrefresh);

View File

@ -91,6 +91,8 @@ void cleanup()
if (!initialized) if (!initialized)
return; return;
/* Avoid a modeswitch if possible */
if (drmNode.mode != &drmNode.original_crtc->mode)
drmModeSetCrtc(drmNode.fd, drmModeSetCrtc(drmNode.fd,
drmNode.original_crtc->crtc_id, drmNode.original_crtc->crtc_id,
drmNode.original_crtc->buffer_id, drmNode.original_crtc->buffer_id,
@ -99,6 +101,8 @@ void cleanup()
&drmNode.connector_id, &drmNode.connector_id,
1, 1,
&drmNode.original_crtc->mode); &drmNode.original_crtc->mode);
else if (getenv("SFML_DRM_DEBUG"))
printf("DRM keeping the same mode since using the original one\n");
drmModeFreeConnector(drmNode.saved_connector); drmModeFreeConnector(drmNode.saved_connector);
drmModeFreeEncoder(drmNode.saved_encoder); drmModeFreeEncoder(drmNode.saved_encoder);

View File

@ -46,6 +46,7 @@
#include <X11/keysym.h> #include <X11/keysym.h>
#include <algorithm> #include <algorithm>
#include <bitset>
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <fcntl.h> #include <fcntl.h>
@ -77,6 +78,7 @@ namespace WindowsImplX11Impl
{ {
sf::priv::WindowImplX11* fullscreenWindow = nullptr; sf::priv::WindowImplX11* fullscreenWindow = nullptr;
std::vector<sf::priv::WindowImplX11*> allWindows; std::vector<sf::priv::WindowImplX11*> allWindows;
std::bitset<256> isKeyFiltered;
std::recursive_mutex allWindowsMutex; std::recursive_mutex allWindowsMutex;
sf::String windowManagerName; sf::String windowManagerName;
@ -88,23 +90,6 @@ constexpr unsigned long eventMask = FocusChangeMask | ButtonPressMask | ButtonRe
constexpr unsigned int maxTrialsCount = 5; constexpr unsigned int maxTrialsCount = 5;
// Predicate we use to find key repeat events in processEvent
struct KeyRepeatFinder
{
KeyRepeatFinder(unsigned int initalKeycode, Time initialTime) : keycode(initalKeycode), time(initialTime)
{
}
// Predicate operator that checks event type, keycode and timestamp
bool operator()(const XEvent& event)
{
return ((event.type == KeyPress) && (event.xkey.keycode == keycode) && (event.xkey.time - time < 2));
}
unsigned int keycode;
Time time;
};
// Filter the events received by windows (only allow those matching a specific window) // Filter the events received by windows (only allow those matching a specific window)
Bool checkEvent(::Display*, XEvent* event, XPointer userData) Bool checkEvent(::Display*, XEvent* event, XPointer userData)
{ {
@ -831,14 +816,61 @@ void WindowImplX11::processEvents()
// Pick out the events that are interesting for this window // Pick out the events that are interesting for this window
while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast<XPointer>(m_window))) while (XCheckIfEvent(m_display, &event, &checkEvent, reinterpret_cast<XPointer>(m_window)))
m_events.push_back(event);
// Handle the events for this window that we just picked out
while (!m_events.empty())
{ {
event = m_events.front(); // This function implements a workaround to properly discard
m_events.pop_front(); // repeated key events when necessary. The problem is that the
// system's key events policy doesn't match SFML's one: X server will generate
// both repeated KeyPress and KeyRelease events when maintaining a key down, while
// SFML only wants repeated KeyPress events. Thus, we have to:
// - Discard duplicated KeyRelease events when m_keyRepeat is true
// - Discard both duplicated KeyPress and KeyRelease events when m_keyRepeat is false
bool processThisEvent = true;
// Detect repeated key events
while (event.type == KeyRelease)
{
XEvent nextEvent;
if (XCheckIfEvent(m_display, &nextEvent, checkEvent, reinterpret_cast<XPointer>(m_window)))
{
if ((nextEvent.type == KeyPress) && (nextEvent.xkey.keycode == event.xkey.keycode) &&
(event.xkey.time <= nextEvent.xkey.time) && (nextEvent.xkey.time <= event.xkey.time + 1))
{
// This sequence of events comes from maintaining a key down
if (m_keyRepeat)
{
// Ignore the KeyRelease event and process the KeyPress event
event = nextEvent;
break;
}
else
{
// Ignore both events
processThisEvent = false;
break;
}
}
else
{
// This sequence of events does not come from maintaining a key down,
// so process the KeyRelease event normally,
processEvent(event); processEvent(event);
// but loop because the next event can be the first half
// of a sequence coming from maintaining a key down.
event = nextEvent;
}
}
else
{
// No event after this KeyRelease event so assume it can be processed.
break;
}
}
if (processThisEvent)
{
processEvent(event);
}
} }
// Process clipboard window events // Process clipboard window events
@ -1731,33 +1763,6 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
{ {
using namespace WindowsImplX11Impl; using namespace WindowsImplX11Impl;
// This function implements a workaround to properly discard
// repeated key events when necessary. The problem is that the
// system's key events policy doesn't match SFML's one: X server will generate
// both repeated KeyPress and KeyRelease events when maintaining a key down, while
// SFML only wants repeated KeyPress events. Thus, we have to:
// - Discard duplicated KeyRelease events when KeyRepeatEnabled is true
// - Discard both duplicated KeyPress and KeyRelease events when KeyRepeatEnabled is false
// Detect repeated key events
if (windowEvent.type == KeyRelease)
{
// Find the next KeyPress event with matching keycode and time
auto it = std::find_if(m_events.begin(),
m_events.end(),
KeyRepeatFinder(windowEvent.xkey.keycode, windowEvent.xkey.time));
if (it != m_events.end())
{
// If we don't want repeated events, remove the next KeyPress from the queue
if (!m_keyRepeat)
m_events.erase(it);
// This KeyRelease is a repeated event and we don't want it
return false;
}
}
// Convert the X11 event to a sf::Event // Convert the X11 event to a sf::Event
switch (windowEvent.type) switch (windowEvent.type)
{ {
@ -1913,10 +1918,30 @@ bool WindowImplX11::processEvent(XEvent& windowEvent)
event.key.control = windowEvent.xkey.state & ControlMask; event.key.control = windowEvent.xkey.state & ControlMask;
event.key.shift = windowEvent.xkey.state & ShiftMask; event.key.shift = windowEvent.xkey.state & ShiftMask;
event.key.system = windowEvent.xkey.state & Mod4Mask; event.key.system = windowEvent.xkey.state & Mod4Mask;
pushEvent(event);
// Generate a TextEntered event const bool filtered = XFilterEvent(&windowEvent, None);
if (!XFilterEvent(&windowEvent, None))
// Generate a KeyPressed event if needed
if (filtered)
{
pushEvent(event);
isKeyFiltered.set(windowEvent.xkey.keycode);
}
else
{
// Push a KeyPressed event if the key has never been filtered before
// (a KeyPressed event would have already been pushed if it had been filtered).
//
// Some dummy IMs (like the built-in one you get by setting XMODIFIERS=@im=none)
// never filter events away, and we have to take care of that.
//
// In addition, ignore text-only KeyPress events generated by IMs (with keycode set to 0).
if (!isKeyFiltered.test(windowEvent.xkey.keycode) && windowEvent.xkey.keycode != 0)
pushEvent(event);
}
// Generate TextEntered events if needed
if (!filtered)
{ {
#ifdef X_HAVE_UTF8_STRING #ifdef X_HAVE_UTF8_STRING
if (m_inputContext) if (m_inputContext)

View File

@ -302,7 +302,6 @@ private:
int m_screen; ///< Screen identifier int m_screen; ///< Screen identifier
XIM m_inputMethod; ///< Input method linked to the X display XIM m_inputMethod; ///< Input method linked to the X display
XIC m_inputContext; ///< Input context used to get unicode input in our window XIC m_inputContext; ///< Input context used to get unicode input in our window
std::deque<XEvent> m_events; ///< Queue we use to store pending events for this window
bool m_isExternal; ///< Tell whether the window has been created externally or by SFML bool m_isExternal; ///< Tell whether the window has been created externally or by SFML
RRMode m_oldVideoMode; ///< Video mode in use before we switch to fullscreen RRMode m_oldVideoMode; ///< Video mode in use before we switch to fullscreen
RRCrtc m_oldRRCrtc; ///< RRCrtc in use before we switch to fullscreen RRCrtc m_oldRRCrtc; ///< RRCrtc in use before we switch to fullscreen