Added X11 implementation

This commit is contained in:
Marco Antognini 2017-03-04 20:46:26 +01:00 committed by Lukas Dürrenberger
parent 219c14b0c2
commit 34ea68bd1d
5 changed files with 156 additions and 19 deletions

View File

@ -57,17 +57,17 @@ public:
/// ------------------------------------|:-----:|:--------:|:--------: /// ------------------------------------|:-----:|:--------:|:--------:
/// sf::Cursor::Arrow | yes | yes | yes /// sf::Cursor::Arrow | yes | yes | yes
/// sf::Cursor::ArrowWait | no | no | yes /// sf::Cursor::ArrowWait | no | no | yes
/// sf::Cursor::Wait | no | no | yes /// sf::Cursor::Wait | yes | no | yes
/// sf::Cursor::Text | no | yes | yes /// sf::Cursor::Text | yes | yes | yes
/// sf::Cursor::Hand | no | yes | yes /// sf::Cursor::Hand | yes | yes | yes
/// sf::Cursor::SizeHorizontal | no | yes | yes /// sf::Cursor::SizeHorizontal | yes | yes | yes
/// sf::Cursor::SizeVertical | no | yes | yes /// sf::Cursor::SizeVertical | yes | yes | yes
/// sf::Cursor::SizeTopLeftBottomRight | no | no | yes /// sf::Cursor::SizeTopLeftBottomRight | no | no | yes
/// sf::Cursor::SizeBottomLeftTopRight | no | no | yes /// sf::Cursor::SizeBottomLeftTopRight | no | no | yes
/// sf::Cursor::SizeAll | no | no | yes /// sf::Cursor::SizeAll | yes | no | yes
/// sf::Cursor::Cross | no | yes | yes /// sf::Cursor::Cross | yes | yes | yes
/// sf::Cursor::Help | no | no | yes /// sf::Cursor::Help | yes | no | yes
/// sf::Cursor::NotAllowed | no | yes | yes /// sf::Cursor::NotAllowed | yes | yes | yes
/// ///
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
enum Type enum Type
@ -126,6 +126,11 @@ public:
/// position is. Any mouse actions that are performed will /// position is. Any mouse actions that are performed will
/// return the window/screen location of the hotspot. /// return the window/screen location of the hotspot.
/// ///
/// \warning On Unix, the pixels are mapped into a monochrome
/// bitmap: pixels with an alpha channel to 0 are
/// transparent, black if the RGB channel are close
/// to zero, and white otherwise.
///
/// \param pixels Array of pixels of the image /// \param pixels Array of pixels of the image
/// \param size Width and height of the image /// \param size Width and height of the image
/// \param hotspot (x,y) location of the hotspot /// \param hotspot (x,y) location of the hotspot

View File

@ -26,6 +26,12 @@
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/Unix/CursorImpl.hpp> #include <SFML/Window/Unix/CursorImpl.hpp>
#include <SFML/Window/Unix/Display.hpp>
#include <X11/cursorfont.h>
#include <X11/Xutil.h>
#include <cassert>
#include <cstdlib>
#include <vector>
namespace sf namespace sf
{ {
@ -33,30 +39,114 @@ namespace priv
{ {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
CursorImpl::CursorImpl() CursorImpl::CursorImpl() :
m_display(OpenDisplay()),
m_cursor(None)
{ {
// TODO // That's it.
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
CursorImpl::~CursorImpl() CursorImpl::~CursorImpl()
{ {
// TODO release();
CloseDisplay(m_display);
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot) bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot)
{ {
// TODO release();
// Convert the image into a bitmap (monochrome!).
std::size_t bytes = (size.x + 7) / 8 * size.y;
std::vector<Uint8> mask(bytes, 0); // Defines which pixel is transparent.
std::vector<Uint8> data(bytes, 1); // Defines which pixel is white/black.
for (std::size_t j = 0; j < size.y; ++j)
{
for (std::size_t i = 0; i < size.x; ++i)
{
std::size_t pixelIndex = i + j * size.x;
std::size_t byteIndex = pixelIndex / 8;
std::size_t bitIndex = i % 8;
// Turn on pixel that are not transparent
Uint8 opacity = pixels[pixelIndex * 4 + 3] > 0 ? 1 : 0;
mask[byteIndex] |= opacity << bitIndex;
// Choose between black/background & white/foreground color for each pixel,
// based on the pixel color intensity: on average, if a channel is "active"
// at 25%, the bit is white.
int intensity = pixels[pixelIndex * 4 + 0] + pixels[pixelIndex * 4 + 1] + pixels[pixelIndex * 4 + 2];
Uint8 bit = intensity > 64 ? 1 : 0;
data[byteIndex] |= bit << bitIndex;
}
}
Pixmap maskPixmap = XCreateBitmapFromData(m_display, XDefaultRootWindow(m_display),
(char*)&mask[0], size.x, size.y);
Pixmap dataPixmap = XCreateBitmapFromData(m_display, XDefaultRootWindow(m_display),
(char*)&data[0], size.x, size.y);
// Define the foreground color as white and the background as black.
XColor fg, bg;
fg.red = fg.blue = fg.green = -1;
bg.red = bg.blue = bg.green = 0;
// Create the monochrome cursor.
m_cursor = XCreatePixmapCursor(m_display,
dataPixmap, maskPixmap,
&fg, &bg,
hotspot.x, hotspot.y);
// Free the resources
XFreePixmap(m_display, dataPixmap);
XFreePixmap(m_display, maskPixmap);
// We assume everything went fine...
return true;
} }
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
bool CursorImpl::loadFromSystem(Cursor::Type type) bool CursorImpl::loadFromSystem(Cursor::Type type)
{ {
// TODO release();
unsigned int shape;
switch (type)
{
default: return false;
case Cursor::Arrow: shape = XC_arrow; break;
case Cursor::Wait: shape = XC_watch; break;
case Cursor::Text: shape = XC_xterm; break;
case Cursor::Hand: shape = XC_hand1; break;
case Cursor::SizeHorizontal: shape = XC_sb_h_double_arrow; break;
case Cursor::SizeVertical: shape = XC_sb_v_double_arrow; break;
case Cursor::SizeAll: shape = XC_fleur; break;
case Cursor::Cross: shape = XC_crosshair; break;
case Cursor::Help: shape = XC_question_arrow; break;
case Cursor::NotAllowed: shape = XC_X_cursor; break;
}
m_cursor = XCreateFontCursor(m_display, shape);
return true;
}
////////////////////////////////////////////////////////////
void CursorImpl::release()
{
if (m_cursor != None)
{
XFreeCursor(m_display, m_cursor);
m_cursor = None;
}
} }

View File

@ -31,7 +31,8 @@
#include <SFML/Window/Cursor.hpp> #include <SFML/Window/Cursor.hpp>
#include <SFML/System/NonCopyable.hpp> #include <SFML/System/NonCopyable.hpp>
#include <SFML/System/Vector2.hpp> #include <SFML/System/Vector2.hpp>
#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
#include <X11/Xlib.h>
namespace sf namespace sf
{ {
@ -82,9 +83,17 @@ private:
friend class WindowImplX11; friend class WindowImplX11;
////////////////////////////////////////////////////////////
/// \brief Release the cursor, if we have loaded one.
///
////////////////////////////////////////////////////////////
void release();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
::Display* m_display;
::Cursor m_cursor;
}; };
} // namespace priv } // namespace priv

View File

@ -25,7 +25,6 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Headers // Headers
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
#include <SFML/Window/WindowStyle.hpp> // important to be included first (conflict with None)
#include <SFML/Window/Unix/WindowImplX11.hpp> #include <SFML/Window/Unix/WindowImplX11.hpp>
#include <SFML/Window/Unix/Display.hpp> #include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/InputImpl.hpp> #include <SFML/Window/Unix/InputImpl.hpp>
@ -387,6 +386,7 @@ m_inputContext (NULL),
m_isExternal (true), m_isExternal (true),
m_oldVideoMode (0), m_oldVideoMode (0),
m_hiddenCursor (0), m_hiddenCursor (0),
m_lastCursor (None),
m_keyRepeat (true), m_keyRepeat (true),
m_previousSize (-1, -1), m_previousSize (-1, -1),
m_useSizeHints (false), m_useSizeHints (false),
@ -434,6 +434,7 @@ m_inputContext (NULL),
m_isExternal (false), m_isExternal (false),
m_oldVideoMode (0), m_oldVideoMode (0),
m_hiddenCursor (0), m_hiddenCursor (0),
m_lastCursor (None),
m_keyRepeat (true), m_keyRepeat (true),
m_previousSize (-1, -1), m_previousSize (-1, -1),
m_useSizeHints (false), m_useSizeHints (false),
@ -895,7 +896,7 @@ void WindowImplX11::setVisible(bool visible)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::setMouseCursorVisible(bool visible) void WindowImplX11::setMouseCursorVisible(bool visible)
{ {
XDefineCursor(m_display, m_window, visible ? None : m_hiddenCursor); XDefineCursor(m_display, m_window, visible ? m_lastCursor : m_hiddenCursor);
XFlush(m_display); XFlush(m_display);
} }
@ -903,7 +904,8 @@ void WindowImplX11::setMouseCursorVisible(bool visible)
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::setMouseCursor(const CursorImpl& cursor) void WindowImplX11::setMouseCursor(const CursorImpl& cursor)
{ {
// TODO m_lastCursor = cursor.m_cursor;
XDefineCursor(m_display, m_window, m_lastCursor);
} }
@ -1313,6 +1315,9 @@ void WindowImplX11::initialize()
// Raise the window and grab input focus // Raise the window and grab input focus
grabFocus(); grabFocus();
// Create the hidden cursor
createHiddenCursor();
// Flush the commands queue // Flush the commands queue
XFlush(m_display); XFlush(m_display);
@ -1346,6 +1351,26 @@ void WindowImplX11::updateLastInputTime(::Time time)
} }
////////////////////////////////////////////////////////////
void WindowImplX11::createHiddenCursor()
{
// Create the cursor's pixmap (1x1 pixels)
Pixmap cursorPixmap = XCreatePixmap(m_display, m_window, 1, 1, 1);
GC graphicsContext = XCreateGC(m_display, cursorPixmap, 0, NULL);
XDrawPoint(m_display, cursorPixmap, graphicsContext, 0, 0);
XFreeGC(m_display, graphicsContext);
// Create the cursor, using the pixmap as both the shape and the mask of the cursor
XColor color;
color.flags = DoRed | DoGreen | DoBlue;
color.red = color.blue = color.green = 0;
m_hiddenCursor = XCreatePixmapCursor(m_display, cursorPixmap, cursorPixmap, &color, &color, 0, 0);
// We don't need the pixmap any longer, free it
XFreePixmap(m_display, cursorPixmap);
}
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void WindowImplX11::cleanup() void WindowImplX11::cleanup()
{ {

View File

@ -31,6 +31,7 @@
#include <SFML/Window/Event.hpp> #include <SFML/Window/Event.hpp>
#include <SFML/Window/WindowImpl.hpp> #include <SFML/Window/WindowImpl.hpp>
#include <SFML/System/String.hpp> #include <SFML/System/String.hpp>
#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <deque> #include <deque>
@ -241,6 +242,12 @@ private:
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void initialize(); void initialize();
////////////////////////////////////////////////////////////
/// \brief Create a transparent mouse cursor
///
////////////////////////////////////////////////////////////
void createHiddenCursor();
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
/// \brief Cleanup graphical resources attached to the window /// \brief Cleanup graphical resources attached to the window
/// ///
@ -267,7 +274,8 @@ private:
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
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
int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen int m_oldVideoMode; ///< Video mode in use before we switch to fullscreen
::Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hidding, we must create a transparent one ::Cursor m_hiddenCursor; ///< As X11 doesn't provide cursor hiding, we must create a transparent one
::Cursor m_lastCursor; ///< Last cursor used -- this data is not owned by the window and is required to be always valid
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?