Adjusted WindowImplX11.
* Replaced Xlib event names by XCB equivalents. * Removed XCB_CW_OVERRIDE_REDIRECT in order to let the WM handle mapping the window to the full screen. * Fixed mouse grabbing in fullscreen mode. Removed keyboard grabbing to allow the user to "alt+tab" out of the window. * Completely revised fullscreen handling: The screen's resolution is not changed at all anymore. Instead the WM is asked for going fullscreen and the view is scaled.
This commit is contained in:
parent
20f213bfac
commit
c08a56bf9f
@ -35,7 +35,6 @@
|
|||||||
#include <xcb/xcb_icccm.h>
|
#include <xcb/xcb_icccm.h>
|
||||||
#include <xcb/xcb_image.h>
|
#include <xcb/xcb_image.h>
|
||||||
#include <xcb/xcb_util.h>
|
#include <xcb/xcb_util.h>
|
||||||
#include <xcb/randr.h>
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -63,9 +62,11 @@ namespace
|
|||||||
{
|
{
|
||||||
sf::priv::WindowImplX11* fullscreenWindow = NULL;
|
sf::priv::WindowImplX11* fullscreenWindow = NULL;
|
||||||
std::vector<sf::priv::WindowImplX11*> allWindows;
|
std::vector<sf::priv::WindowImplX11*> allWindows;
|
||||||
unsigned long eventMask = FocusChangeMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask |
|
unsigned long eventMask = XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_BUTTON_PRESS |
|
||||||
PointerMotionMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask |
|
XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_BUTTON_MOTION |
|
||||||
EnterWindowMask | LeaveWindowMask;
|
XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_KEY_PRESS |
|
||||||
|
XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
|
||||||
|
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()
|
||||||
@ -103,7 +104,8 @@ m_oldVideoMode(-1),
|
|||||||
m_hiddenCursor(0),
|
m_hiddenCursor(0),
|
||||||
m_keyRepeat (true),
|
m_keyRepeat (true),
|
||||||
m_previousSize(-1, -1),
|
m_previousSize(-1, -1),
|
||||||
m_useSizeHints(false)
|
m_useSizeHints(false),
|
||||||
|
m_fullscreen (false)
|
||||||
{
|
{
|
||||||
// Open a connection with the X server
|
// Open a connection with the X server
|
||||||
m_display = OpenDisplay();
|
m_display = OpenDisplay();
|
||||||
@ -150,7 +152,8 @@ m_oldVideoMode(-1),
|
|||||||
m_hiddenCursor(0),
|
m_hiddenCursor(0),
|
||||||
m_keyRepeat (true),
|
m_keyRepeat (true),
|
||||||
m_previousSize(-1, -1),
|
m_previousSize(-1, -1),
|
||||||
m_useSizeHints(false)
|
m_useSizeHints(false),
|
||||||
|
m_fullscreen ((style & Style::Fullscreen) != 0)
|
||||||
{
|
{
|
||||||
// Open a connection with the X server
|
// Open a connection with the X server
|
||||||
m_display = OpenDisplay();
|
m_display = OpenDisplay();
|
||||||
@ -166,23 +169,18 @@ m_useSizeHints(false)
|
|||||||
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
|
XSetEventQueueOwner(m_display, XCBOwnsEventQueue);
|
||||||
|
|
||||||
// Compute position and size
|
// Compute position and size
|
||||||
bool fullscreen = (style & Style::Fullscreen) != 0;
|
int left = m_fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2;
|
||||||
int left = fullscreen ? 0 : (m_screen->width_in_pixels - mode.width) / 2;
|
int top = m_fullscreen ? 0 : (m_screen->height_in_pixels - mode.height) / 2;
|
||||||
int top = fullscreen ? 0 : (m_screen->height_in_pixels - mode.height) / 2;
|
|
||||||
int width = mode.width;
|
int width = mode.width;
|
||||||
int height = mode.height;
|
int height = mode.height;
|
||||||
|
|
||||||
// Switch to fullscreen if necessary
|
|
||||||
if (fullscreen)
|
|
||||||
switchToFullscreen(mode);
|
|
||||||
|
|
||||||
// Choose the visual according to the context settings
|
// Choose the visual according to the context settings
|
||||||
XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings);
|
XVisualInfo visualInfo = ContextType::selectBestVisual(m_display, mode.bitsPerPixel, settings);
|
||||||
|
|
||||||
// Define the window attributes
|
// Define the window attributes
|
||||||
xcb_colormap_t colormap = xcb_generate_id(m_connection);
|
xcb_colormap_t colormap = xcb_generate_id(m_connection);
|
||||||
xcb_create_colormap(m_connection, XCB_COLORMAP_ALLOC_NONE, colormap, m_screen->root, visualInfo.visualid);
|
xcb_create_colormap(m_connection, XCB_COLORMAP_ALLOC_NONE, colormap, m_screen->root, visualInfo.visualid);
|
||||||
const uint32_t value_list[] = {fullscreen, static_cast<uint32_t>(eventMask), colormap};
|
const uint32_t value_list[] = {static_cast<uint32_t>(eventMask), colormap};
|
||||||
|
|
||||||
// Create the window
|
// Create the window
|
||||||
m_window = xcb_generate_id(m_connection);
|
m_window = xcb_generate_id(m_connection);
|
||||||
@ -199,7 +197,7 @@ m_useSizeHints(false)
|
|||||||
0,
|
0,
|
||||||
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
XCB_WINDOW_CLASS_INPUT_OUTPUT,
|
||||||
visualInfo.visualid,
|
visualInfo.visualid,
|
||||||
XCB_CW_EVENT_MASK | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_COLORMAP,
|
XCB_CW_EVENT_MASK | XCB_CW_COLORMAP,
|
||||||
value_list
|
value_list
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
@ -214,7 +212,7 @@ m_useSizeHints(false)
|
|||||||
setTitle(title);
|
setTitle(title);
|
||||||
|
|
||||||
// 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 (!fullscreen)
|
if (!m_fullscreen)
|
||||||
{
|
{
|
||||||
static const std::string MOTIF_WM_HINTS = "_MOTIF_WM_HINTS";
|
static const std::string MOTIF_WM_HINTS = "_MOTIF_WM_HINTS";
|
||||||
ScopedXcbPtr<xcb_intern_atom_reply_t> hintsAtomReply(xcb_intern_atom_reply(
|
ScopedXcbPtr<xcb_intern_atom_reply_t> hintsAtomReply(xcb_intern_atom_reply(
|
||||||
@ -309,30 +307,9 @@ m_useSizeHints(false)
|
|||||||
// Do some common initializations
|
// Do some common initializations
|
||||||
initialize();
|
initialize();
|
||||||
|
|
||||||
// In fullscreen mode, we must grab keyboard and mouse inputs
|
// Switch to fullscreen.
|
||||||
if (fullscreen)
|
if (m_fullscreen)
|
||||||
{
|
switchToFullscreen();
|
||||||
xcb_grab_pointer(
|
|
||||||
m_connection,
|
|
||||||
True,
|
|
||||||
m_window,
|
|
||||||
0,
|
|
||||||
XCB_GRAB_MODE_ASYNC,
|
|
||||||
XCB_GRAB_MODE_ASYNC,
|
|
||||||
m_window,
|
|
||||||
XCB_NONE,
|
|
||||||
XCB_CURRENT_TIME
|
|
||||||
);
|
|
||||||
|
|
||||||
xcb_grab_keyboard(
|
|
||||||
m_connection,
|
|
||||||
True,
|
|
||||||
m_window,
|
|
||||||
XCB_CURRENT_TIME,
|
|
||||||
XCB_GRAB_MODE_ASYNC,
|
|
||||||
XCB_GRAB_MODE_ASYNC
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -376,6 +353,44 @@ WindowHandle WindowImplX11::getSystemHandle() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
void WindowImplX11::setPointerGrabbed(bool grabbed)
|
||||||
|
{
|
||||||
|
// NOTE: This only works when the window is mapped and visible!
|
||||||
|
|
||||||
|
if (grabbed)
|
||||||
|
{
|
||||||
|
ScopedXcbPtr<xcb_grab_pointer_reply_t> grabReply(xcb_grab_pointer_reply(
|
||||||
|
m_connection,
|
||||||
|
xcb_grab_pointer(
|
||||||
|
m_connection,
|
||||||
|
1,
|
||||||
|
m_screen->root,
|
||||||
|
XCB_NONE,
|
||||||
|
XCB_GRAB_MODE_ASYNC,
|
||||||
|
XCB_GRAB_MODE_ASYNC,
|
||||||
|
m_window,
|
||||||
|
XCB_NONE,
|
||||||
|
XCB_CURRENT_TIME
|
||||||
|
),
|
||||||
|
NULL
|
||||||
|
));
|
||||||
|
|
||||||
|
if (grabReply && grabReply->status != 0)
|
||||||
|
sf::err() << "Grabbing the pointer failed." << std::endl
|
||||||
|
<< " Status: "
|
||||||
|
<< static_cast<int>(grabReply->status) << std::endl;
|
||||||
|
else if (!grabReply)
|
||||||
|
sf::err() << "Grabbing the pointer failed." << std::endl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
xcb_ungrab_pointer(m_connection, XCB_CURRENT_TIME);
|
||||||
|
xcb_flush(m_connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void WindowImplX11::processEvents()
|
void WindowImplX11::processEvents()
|
||||||
{
|
{
|
||||||
@ -736,77 +751,85 @@ bool WindowImplX11::hasFocus() const
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void WindowImplX11::switchToFullscreen(const VideoMode& mode)
|
void WindowImplX11::switchToFullscreen()
|
||||||
{
|
{
|
||||||
// Check if the XRandR extension is present
|
// Create atom for _NET_WM_STATE.
|
||||||
static const std::string RANDR = "RANDR";
|
static const std::string netWmState = "_NET_WM_STATE";
|
||||||
ScopedXcbPtr<xcb_query_extension_reply_t> randr_ext(xcb_query_extension_reply(
|
ScopedXcbPtr<xcb_intern_atom_reply_t> stateReply(xcb_intern_atom_reply(
|
||||||
m_connection,
|
m_connection,
|
||||||
xcb_query_extension(
|
xcb_intern_atom(
|
||||||
m_connection,
|
m_connection,
|
||||||
RANDR.size(),
|
0,
|
||||||
RANDR.c_str()
|
netWmState.size(),
|
||||||
),
|
netWmState.c_str()
|
||||||
NULL
|
),
|
||||||
|
0
|
||||||
));
|
));
|
||||||
|
|
||||||
if (randr_ext->present)
|
// Create atom for _NET_WM_STATE_FULLSCREEN.
|
||||||
{
|
static const std::string netWmStateFullscreen = "_NET_WM_STATE_FULLSCREEN";
|
||||||
// Get the current configuration
|
ScopedXcbPtr<xcb_intern_atom_reply_t> fullscreenReply(xcb_intern_atom_reply(
|
||||||
ScopedXcbPtr<xcb_generic_error_t> error(NULL);
|
m_connection,
|
||||||
ScopedXcbPtr<xcb_randr_get_screen_info_reply_t> config(xcb_randr_get_screen_info_reply(
|
xcb_intern_atom(
|
||||||
m_connection,
|
m_connection,
|
||||||
xcb_randr_get_screen_info(
|
0,
|
||||||
m_connection,
|
netWmStateFullscreen.size(),
|
||||||
m_screen->root
|
netWmStateFullscreen.c_str()
|
||||||
),
|
),
|
||||||
&error
|
0
|
||||||
));
|
));
|
||||||
|
|
||||||
if (!error)
|
// Set fullscreen property.
|
||||||
{
|
ScopedXcbPtr<xcb_generic_error_t> fullscreenError(xcb_request_check(
|
||||||
// Save the current video mode before we switch to fullscreen
|
m_connection,
|
||||||
m_oldVideoMode = config->sizeID;
|
xcb_change_property_checked(
|
||||||
|
m_connection,
|
||||||
|
XCB_PROP_MODE_REPLACE,
|
||||||
|
m_window,
|
||||||
|
stateReply->atom,
|
||||||
|
XCB_ATOM_ATOM,
|
||||||
|
32,
|
||||||
|
1,
|
||||||
|
&fullscreenReply->atom
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
// Get the available screen sizes
|
if (fullscreenError)
|
||||||
xcb_randr_screen_size_t* sizes = xcb_randr_get_screen_info_sizes(config.get());
|
|
||||||
if (sizes && (config->nSizes > 0))
|
|
||||||
{
|
|
||||||
// Search a matching size
|
|
||||||
for (int i = 0; i < config->nSizes; ++i)
|
|
||||||
{
|
|
||||||
if ((sizes[i].width == static_cast<int>(mode.width)) &&
|
|
||||||
(sizes[i].height == static_cast<int>(mode.height)))
|
|
||||||
{
|
|
||||||
// Switch to fullscreen mode
|
|
||||||
xcb_randr_set_screen_config(
|
|
||||||
m_connection,
|
|
||||||
m_screen->root,
|
|
||||||
config->timestamp,
|
|
||||||
config->config_timestamp,
|
|
||||||
i,
|
|
||||||
config->rotation,
|
|
||||||
config->rate
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set "this" as the current fullscreen window
|
|
||||||
fullscreenWindow = this;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Failed to get the screen configuration
|
|
||||||
err() << "Failed to get the current screen configuration for fullscreen mode, switching to window mode" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// XRandR extension is not supported: we cannot use fullscreen mode
|
sf::err() << "Setting fullscreen failed." << std::endl;
|
||||||
err() << "Fullscreen is not supported, switching to window mode" << std::endl;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create atom for _NET_WM_BYPASS_COMPOSITOR.
|
||||||
|
static const std::string netWmStateBypassCompositor = "_NET_WM_BYPASS_COMPOSITOR";
|
||||||
|
ScopedXcbPtr<xcb_intern_atom_reply_t> compReply(xcb_intern_atom_reply(
|
||||||
|
m_connection,
|
||||||
|
xcb_intern_atom(
|
||||||
|
m_connection,
|
||||||
|
0,
|
||||||
|
netWmStateBypassCompositor.size(),
|
||||||
|
netWmStateBypassCompositor.c_str()
|
||||||
|
),
|
||||||
|
0
|
||||||
|
));
|
||||||
|
|
||||||
|
// Disable compositor.
|
||||||
|
ScopedXcbPtr<xcb_generic_error_t> compositorError(xcb_request_check(
|
||||||
|
m_connection,
|
||||||
|
xcb_change_property_checked(
|
||||||
|
m_connection,
|
||||||
|
XCB_PROP_MODE_REPLACE,
|
||||||
|
m_window,
|
||||||
|
stateReply->atom,
|
||||||
|
XCB_ATOM_ATOM,
|
||||||
|
32,
|
||||||
|
1,
|
||||||
|
&compReply->atom
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
if (compositorError)
|
||||||
|
sf::err() << "xcb_change_property failed, setting fullscreen not possible." << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -926,30 +949,6 @@ void WindowImplX11::cleanup()
|
|||||||
// Restore the previous video mode (in case we were running in fullscreen)
|
// Restore the previous video mode (in case we were running in fullscreen)
|
||||||
if (fullscreenWindow == this)
|
if (fullscreenWindow == this)
|
||||||
{
|
{
|
||||||
// Get current screen info
|
|
||||||
ScopedXcbPtr<xcb_generic_error_t> error(NULL);
|
|
||||||
ScopedXcbPtr<xcb_randr_get_screen_info_reply_t> config(xcb_randr_get_screen_info_reply(
|
|
||||||
m_connection,
|
|
||||||
xcb_randr_get_screen_info(
|
|
||||||
m_connection,
|
|
||||||
m_screen->root
|
|
||||||
),
|
|
||||||
&error
|
|
||||||
));
|
|
||||||
|
|
||||||
if (!error)
|
|
||||||
{
|
|
||||||
// Reset the video mode
|
|
||||||
xcb_randr_set_screen_config(
|
|
||||||
m_connection,
|
|
||||||
m_screen->root,
|
|
||||||
CurrentTime,
|
|
||||||
config->config_timestamp,
|
|
||||||
m_oldVideoMode,
|
|
||||||
config->rotation,
|
|
||||||
config->rate
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the fullscreen window
|
// Reset the fullscreen window
|
||||||
fullscreenWindow = NULL;
|
fullscreenWindow = NULL;
|
||||||
@ -1001,12 +1000,20 @@ bool WindowImplX11::processEvent(xcb_generic_event_t* windowEvent)
|
|||||||
hints.flags &= ~XUrgencyHint;
|
hints.flags &= ~XUrgencyHint;
|
||||||
xcb_icccm_set_wm_hints_checked(m_connection, m_window, &hints);
|
xcb_icccm_set_wm_hints_checked(m_connection, m_window, &hints);
|
||||||
|
|
||||||
|
// Grab pointer if necessary.
|
||||||
|
if (m_fullscreen)
|
||||||
|
setPointerGrabbed(true);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lost focus event
|
// Lost focus event
|
||||||
case XCB_FOCUS_OUT:
|
case XCB_FOCUS_OUT:
|
||||||
{
|
{
|
||||||
|
// Ungrab pointer if necessary.
|
||||||
|
if (m_fullscreen)
|
||||||
|
setPointerGrabbed(false);
|
||||||
|
|
||||||
// Update the input context
|
// Update the input context
|
||||||
if (m_inputContext)
|
if (m_inputContext)
|
||||||
XUnsetICFocus(m_inputContext);
|
XUnsetICFocus(m_inputContext);
|
||||||
|
@ -182,10 +182,16 @@ private:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Switch to fullscreen mode
|
/// \brief Switch to fullscreen mode
|
||||||
///
|
///
|
||||||
/// \param Mode video mode to switch to
|
////////////////////////////////////////////////////////////
|
||||||
|
void switchToFullscreen();
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Grab or ungrab mouse pointer.
|
||||||
|
///
|
||||||
|
/// \param grabbed True to grab, false to ungrab.
|
||||||
///
|
///
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void switchToFullscreen(const VideoMode& mode);
|
void setPointerGrabbed(bool grabbed);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Do some common initializations after the window has been created
|
/// \brief Do some common initializations after the window has been created
|
||||||
@ -241,6 +247,7 @@ private:
|
|||||||
bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?
|
bool m_keyRepeat; ///< Is the KeyRepeat feature enabled?
|
||||||
Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only)
|
Vector2i m_previousSize; ///< Previous size of the window, to find if a ConfigureNotify event is a resize event (could be a move event only)
|
||||||
bool m_useSizeHints; ///< Is the size of the window fixed with size hints?
|
bool m_useSizeHints; ///< Is the size of the window fixed with size hints?
|
||||||
|
bool m_fullscreen; ///< Is window in fullscreen?
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace priv
|
} // namespace priv
|
||||||
|
Loading…
x
Reference in New Issue
Block a user