Add ScopedXcbPtr to CMakeLists.txt, replaced xcb_query_extension with xcb_get_extension_data where possible, removed decorations from fullscreen windows, fixed DRI2 events not being forwarded as Xlib events leading to Mesa not functioning correctly in certain situations.

This commit is contained in:
binary1248 2015-03-27 16:53:24 +01:00 committed by Lukas Dürrenberger
parent bd34935f2a
commit 39cdebfe71
3 changed files with 234 additions and 63 deletions

View File

@ -75,6 +75,8 @@ elseif(SFML_OS_LINUX OR SFML_OS_FREEBSD)
${SRCROOT}/Unix/Display.hpp ${SRCROOT}/Unix/Display.hpp
${SRCROOT}/Unix/InputImpl.cpp ${SRCROOT}/Unix/InputImpl.cpp
${SRCROOT}/Unix/InputImpl.hpp ${SRCROOT}/Unix/InputImpl.hpp
${SRCROOT}/Unix/ScopedXcbPtr.hpp
${SRCROOT}/Unix/ScopedXcbPtr.inl
${SRCROOT}/Unix/SensorImpl.cpp ${SRCROOT}/Unix/SensorImpl.cpp
${SRCROOT}/Unix/SensorImpl.hpp ${SRCROOT}/Unix/SensorImpl.hpp
${SRCROOT}/Unix/VideoModeImpl.cpp ${SRCROOT}/Unix/VideoModeImpl.cpp

View File

@ -50,19 +50,9 @@ std::vector<VideoMode> VideoModeImpl::getFullscreenModes()
ScopedXcbPtr<xcb_generic_error_t> error(NULL); ScopedXcbPtr<xcb_generic_error_t> error(NULL);
// Check if the RandR extension is present const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id);
static const std::string RANDR = "RANDR";
ScopedXcbPtr<xcb_query_extension_reply_t> randr_ext(xcb_query_extension_reply(
connection,
xcb_query_extension(
connection,
RANDR.size(),
RANDR.c_str()
),
&error
));
if (error || !randr_ext->present) if (!randrExt || !randrExt->present)
{ {
// Randr extension is not supported: we cannot get the video modes // Randr extension is not supported: we cannot get the video modes
err() << "Failed to use the RandR extension while trying to get the supported video modes" << std::endl; err() << "Failed to use the RandR extension while trying to get the supported video modes" << std::endl;
@ -161,18 +151,9 @@ VideoMode VideoModeImpl::getDesktopMode()
ScopedXcbPtr<xcb_generic_error_t> error(NULL); ScopedXcbPtr<xcb_generic_error_t> error(NULL);
// Check if the RandR extension is present // Check if the RandR extension is present
static const std::string RANDR = "RANDR"; const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(connection, &xcb_randr_id);
ScopedXcbPtr<xcb_query_extension_reply_t> randr_ext(xcb_query_extension_reply(
connection,
xcb_query_extension(
connection,
RANDR.size(),
RANDR.c_str()
),
&error
));
if (error || !randr_ext->present) if (!randrExt || !randrExt->present)
{ {
// Randr extension is not supported: we cannot get the video modes // Randr extension is not supported: we cannot get the video modes
err() << "Failed to use the RandR extension while trying to get the desktop video mode" << std::endl; err() << "Failed to use the RandR extension while trying to get the desktop video mode" << std::endl;

View File

@ -36,12 +36,17 @@
#include <xcb/xcb_icccm.h> #include <xcb/xcb_icccm.h>
#include <xcb/xcb_image.h> #include <xcb/xcb_image.h>
#include <xcb/randr.h> #include <xcb/randr.h>
#include <X11/Xlibint.h>
#include <unistd.h> #include <unistd.h>
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <string> #include <string>
#include <cstring> #include <cstring>
// So we don't have to require xcb dri2 to be present
#define XCB_DRI2_BUFFER_SWAP_COMPLETE 0
#define XCB_DRI2_INVALIDATE_BUFFERS 1
#ifdef SFML_OPENGL_ES #ifdef SFML_OPENGL_ES
#include <SFML/Window/EglContext.hpp> #include <SFML/Window/EglContext.hpp>
typedef sf::priv::EglContext ContextType; typedef sf::priv::EglContext ContextType;
@ -58,11 +63,11 @@ namespace
sf::priv::WindowImplX11* fullscreenWindow = NULL; sf::priv::WindowImplX11* fullscreenWindow = NULL;
std::vector<sf::priv::WindowImplX11*> allWindows; std::vector<sf::priv::WindowImplX11*> allWindows;
sf::Mutex allWindowsMutex; sf::Mutex allWindowsMutex;
unsigned long eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS | unsigned long eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION |
XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS |
XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW; XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW;
// Find the name of the current executable // Find the name of the current executable
std::string findExecutableName() std::string findExecutableName()
@ -174,6 +179,123 @@ namespace
ewmhSupported = true; ewmhSupported = true;
return true; return true;
} }
xcb_query_extension_reply_t getDriExtension()
{
xcb_connection_t* connection = sf::priv::OpenConnection();
sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
// Check if the DRI2 extension is present
// We don't use xcb_get_extension_data here to avoid having to link to xcb_dri2
static const std::string DRI2 = "DRI2";
sf::priv::ScopedXcbPtr<xcb_query_extension_reply_t> driExt(xcb_query_extension_reply(
connection,
xcb_query_extension(
connection,
DRI2.size(),
DRI2.c_str()
),
&error
));
// Close the connection with the X server
sf::priv::CloseConnection(connection);
if (error || !driExt || !driExt->present)
{
xcb_query_extension_reply_t reply;
std::memset(&reply, 0, sizeof(reply));
return reply;
}
return *driExt.get();
}
void dumpXcbExtensions()
{
xcb_connection_t* connection = sf::priv::OpenConnection();
sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
// Check if the RandR extension is present
sf::priv::ScopedXcbPtr<xcb_list_extensions_reply_t> extensions(xcb_list_extensions_reply(
connection,
xcb_list_extensions(
connection
),
&error
));
if (error || !extensions)
{
// Close the connection with the X server
sf::priv::CloseConnection(connection);
sf::err() << "Couldn't get list of X extensions" << std::endl;
return;
}
xcb_str_iterator_t iter = xcb_list_extensions_names_iterator(extensions.get());
sf::err() << "X Extensions:" << std::endl;
while (iter.rem)
{
std::string name(xcb_str_name(iter.data), xcb_str_name_length(iter.data));
sf::priv::ScopedXcbPtr<xcb_generic_error_t> error(NULL);
// Check if the RandR extension is present
sf::priv::ScopedXcbPtr<xcb_query_extension_reply_t> extension(xcb_query_extension_reply(
connection,
xcb_query_extension(
connection,
name.size(),
name.c_str()
),
&error
));
if (error || !extension || !extension->present)
{
sf::err() << "\t" << name << " - Failed to query" << std::endl;
continue;
}
int firstEvent = extension->first_event;
sf::err() << "\t" << name << " - First event: " << firstEvent << std::endl;
iter.data += xcb_str_name_length(iter.data) + 1;
--iter.rem;
}
// Close the connection with the X server
sf::priv::CloseConnection(connection);
}
void dumpUnhandledEvent(uint8_t type)
{
static std::vector<uint8_t> types;
// Check if we already reported this type
if (std::find(types.begin(), types.end(), type) != types.end())
return;
// Insert it if new
types.push_back(type);
static bool dumpedExtensions = false;
if (!dumpedExtensions)
{
dumpXcbExtensions();
dumpedExtensions = true;
}
sf::err() << "Unhandled event type: " << (static_cast<int>(type) & ~0x80) << std::endl
<< "Report this to the SFML maintainers if possible" << std::endl;
}
} }
@ -350,18 +472,14 @@ m_fullscreen ((style & Style::Fullscreen) != 0)
std::memset(&sizeHints, 0, sizeof(sizeHints)); std::memset(&sizeHints, 0, sizeof(sizeHints));
// Set the window's style (tell the window manager to change our window's decorations and functions according to the requested style) // Set the window's style (tell the window manager to change our window's decorations and functions according to the requested style)
if (!m_fullscreen) setMotifHints(style);
{
// Set the Motif WM hints
setMotifHints(style);
// This is a hack to force some windows managers to disable resizing // This is a hack to force some windows managers to disable resizing
if (!(style & Style::Resize)) if (!(style & Style::Resize))
{ {
m_useSizeHints = true; m_useSizeHints = true;
xcb_icccm_size_hints_set_min_size(&sizeHints, width, height); xcb_icccm_size_hints_set_min_size(&sizeHints, width, height);
xcb_icccm_size_hints_set_max_size(&sizeHints, width, height); xcb_icccm_size_hints_set_max_size(&sizeHints, width, height);
}
} }
// Set the WM hints of the normal state // Set the WM hints of the normal state
@ -1098,18 +1216,9 @@ void WindowImplX11::setVideoMode(const VideoMode& mode)
ScopedXcbPtr<xcb_generic_error_t> error(NULL); ScopedXcbPtr<xcb_generic_error_t> error(NULL);
// Check if the RandR extension is present // Check if the RandR extension is present
static const std::string RANDR = "RANDR"; const xcb_query_extension_reply_t* randrExt = xcb_get_extension_data(m_connection, &xcb_randr_id);
ScopedXcbPtr<xcb_query_extension_reply_t> randr_ext(xcb_query_extension_reply(
m_connection,
xcb_query_extension(
m_connection,
RANDR.size(),
RANDR.c_str()
),
&error
));
if (error || !randr_ext->present) if (!randrExt || !randrExt->present)
{ {
// RandR extension is not supported: we cannot use fullscreen mode // RandR extension is not supported: we cannot use fullscreen mode
err() << "Fullscreen is not supported, switching to window mode" << std::endl; err() << "Fullscreen is not supported, switching to window mode" << std::endl;
@ -1445,21 +1554,27 @@ void WindowImplX11::setMotifHints(unsigned long style)
hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS;
hints.decorations = 0; hints.decorations = 0;
hints.functions = 0; hints.functions = 0;
hints.inputMode = 0;
hints.state = 0;
if (style & Style::Titlebar) // Decorate only if not in fullscreen
if (!(style & Style::Fullscreen))
{ {
hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU; if (style & Style::Titlebar)
hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE; {
} hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MINIMIZE | MWM_DECOR_MENU;
if (style & Style::Resize) hints.functions |= MWM_FUNC_MOVE | MWM_FUNC_MINIMIZE;
{ }
hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH; if (style & Style::Resize)
hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE; {
} hints.decorations |= MWM_DECOR_MAXIMIZE | MWM_DECOR_RESIZEH;
if (style & Style::Close) hints.functions |= MWM_FUNC_MAXIMIZE | MWM_FUNC_RESIZE;
{ }
hints.decorations |= 0; if (style & Style::Close)
hints.functions |= MWM_FUNC_CLOSE; {
hints.decorations |= 0;
hints.functions |= MWM_FUNC_CLOSE;
}
} }
ScopedXcbPtr<xcb_generic_error_t> propertyError(xcb_request_check( ScopedXcbPtr<xcb_generic_error_t> propertyError(xcb_request_check(
@ -2014,6 +2129,79 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
xcb_flush(m_connection); // Discard remaining events xcb_flush(m_connection); // Discard remaining events
break; break;
} }
// The stuff that might pop up but we don't care about
// Whitelist more when necessary
// Window visibility changed (hide/unhide)
case XCB_MAP_NOTIFY:
case XCB_UNMAP_NOTIFY:
{
break;
}
// Handle the rest
default:
{
uint8_t responseType = windowEvent->response_type & ~0x80;
// Handle any extension events first
// DRI2
static xcb_query_extension_reply_t driExtension = getDriExtension();
if (driExtension.present)
{
// Because we are using the XCB event queue instead of the Xlib event
// queue, Mesa breaks a bit (VSync among other things) because DRI2 still
// expects certain Xlib events to come its way. We work around this by
// emulating the old Xlib event queue for these specific wire events.
// Sources (retrieved 27 Mar 2015):
// http://wrl.illest.net/post/45342765813/code-tip-glx-and-xcbownseventqueue
// https://bugs.freedesktop.org/show_bug.cgi?id=42131
// https://bugs.freedesktop.org/show_bug.cgi?id=35945
// Mesa src/glx/dri2.c
// QtBase src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp
// QtBase Commit bb22b4965070409df4658f16fdf549f0362e8a9c
// Qt Change-Id I3b4ef3f6e3efbae25f49f161e229e9b15e951778
// QtBase Commit 13c5c81cfa934c9b610720fe79e07465b00ebc8d
// Qt Change-Id Ia93eb8be1cbbc3d8ae7913a934c195af6b5ec538
// QtBase Commit decb88693c8a7f0c073889b91151f01a850e3adf
// Qt Change-Id Ic466ff26487937b03f072a57e0ee4df335492a5f
if ((responseType == driExtension.first_event + XCB_DRI2_BUFFER_SWAP_COMPLETE) ||
(responseType == driExtension.first_event + XCB_DRI2_INVALIDATE_BUFFERS))
{
// DRI2 BufferSwapComplete and InvalidateBuffers
// We lock/unlock the display to protect against concurrent access
XLockDisplay(m_display);
typedef Bool (*wireEventHandler)(Display*, XEvent*, xEvent*);
// Probe for any handlers that are registered for this event type
wireEventHandler handler = XESetWireToEvent(m_display, responseType, 0);
if (handler)
{
// Restore the previous handler if one was registered
XESetWireToEvent(m_display, responseType, handler);
XEvent event;
windowEvent->sequence = LastKnownRequestProcessed(m_display);
// Pretend to be the Xlib event queue
handler(m_display, &event, reinterpret_cast<xEvent*>(windowEvent));
}
XUnlockDisplay(m_display);
return true;
}
}
// Print any surprises to stderr (would be nice if people report when this happens)
dumpUnhandledEvent(responseType);
break;
}
} }
return true; return true;