Skip to content

Commit

Permalink
Added X11 implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mantognini committed Apr 26, 2017
1 parent f375437 commit 6ba2bb1
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 19 deletions.
23 changes: 14 additions & 9 deletions include/SFML/Window/Cursor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,17 @@ class SFML_WINDOW_API Cursor : NonCopyable
/// ------------------------------------|:-----:|:--------:|:--------:
/// sf::Cursor::Arrow | yes | yes | yes
/// sf::Cursor::ArrowWait | no | no | yes
/// sf::Cursor::Wait | no | no | yes
/// sf::Cursor::Text | no | yes | yes
/// sf::Cursor::Hand | no | yes | yes
/// sf::Cursor::SizeHorizontal | no | yes | yes
/// sf::Cursor::SizeVertical | no | yes | yes
/// sf::Cursor::Wait | yes | no | yes
/// sf::Cursor::Text | yes | yes | yes
/// sf::Cursor::Hand | yes | yes | yes
/// sf::Cursor::SizeHorizontal | yes | yes | yes
/// sf::Cursor::SizeVertical | yes | yes | yes
/// sf::Cursor::SizeTopLeftBottomRight | no | no | yes
/// sf::Cursor::SizeBottomLeftTopRight | no | no | yes
/// sf::Cursor::SizeAll | no | no | yes
/// sf::Cursor::Cross | no | yes | yes
/// sf::Cursor::Help | no | no | yes
/// sf::Cursor::NotAllowed | no | yes | yes
/// sf::Cursor::SizeAll | yes | no | yes
/// sf::Cursor::Cross | yes | yes | yes
/// sf::Cursor::Help | yes | no | yes
/// sf::Cursor::NotAllowed | yes | yes | yes
///
////////////////////////////////////////////////////////////
enum Type
Expand Down Expand Up @@ -126,6 +126,11 @@ class SFML_WINDOW_API Cursor : NonCopyable
/// position is. Any mouse actions that are performed will
/// 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 size Width and height of the image
/// \param hotspot (x,y) location of the hotspot
Expand Down
100 changes: 95 additions & 5 deletions src/SFML/Window/Unix/CursorImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,37 +26,127 @@
// Headers
////////////////////////////////////////////////////////////
#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 priv
{

////////////////////////////////////////////////////////////
CursorImpl::CursorImpl()
CursorImpl::CursorImpl() :
m_display(OpenDisplay()),
m_cursor(None)
{
// TODO
// That's it.
}


////////////////////////////////////////////////////////////
CursorImpl::~CursorImpl()
{
// TODO
release();

CloseDisplay(m_display);
}


////////////////////////////////////////////////////////////
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)
{
// 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;
}
}


Expand Down
11 changes: 10 additions & 1 deletion src/SFML/Window/Unix/CursorImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
#include <SFML/Window/Cursor.hpp>
#include <SFML/System/NonCopyable.hpp>
#include <SFML/System/Vector2.hpp>

#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
#include <X11/Xlib.h>

namespace sf
{
Expand Down Expand Up @@ -82,9 +83,17 @@ class CursorImpl : NonCopyable

friend class WindowImplX11;

////////////////////////////////////////////////////////////
/// \brief Release the cursor, if we have loaded one.
///
////////////////////////////////////////////////////////////
void release();

////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
::Display* m_display;
::Cursor m_cursor;
};

} // namespace priv
Expand Down
31 changes: 28 additions & 3 deletions src/SFML/Window/Unix/WindowImplX11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/WindowStyle.hpp> // important to be included first (conflict with None)
#include <SFML/Window/Unix/WindowImplX11.hpp>
#include <SFML/Window/Unix/Display.hpp>
#include <SFML/Window/Unix/InputImpl.hpp>
Expand Down Expand Up @@ -387,6 +386,7 @@ m_inputContext (NULL),
m_isExternal (true),
m_oldVideoMode (0),
m_hiddenCursor (0),
m_lastCursor (None),
m_keyRepeat (true),
m_previousSize (-1, -1),
m_useSizeHints (false),
Expand Down Expand Up @@ -434,6 +434,7 @@ m_inputContext (NULL),
m_isExternal (false),
m_oldVideoMode (0),
m_hiddenCursor (0),
m_lastCursor (None),
m_keyRepeat (true),
m_previousSize (-1, -1),
m_useSizeHints (false),
Expand Down Expand Up @@ -895,15 +896,16 @@ void WindowImplX11::setVisible(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);
}


////////////////////////////////////////////////////////////
void WindowImplX11::setMouseCursor(const CursorImpl& cursor)
{
// TODO
m_lastCursor = cursor.m_cursor;
XDefineCursor(m_display, m_window, m_lastCursor);
}


Expand Down Expand Up @@ -1313,6 +1315,9 @@ void WindowImplX11::initialize()
// Raise the window and grab input focus
grabFocus();

// Create the hidden cursor
createHiddenCursor();

// Flush the commands queue
XFlush(m_display);

Expand Down Expand Up @@ -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()
{
Expand Down
10 changes: 9 additions & 1 deletion src/SFML/Window/Unix/WindowImplX11.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <SFML/Window/Event.hpp>
#include <SFML/Window/WindowImpl.hpp>
#include <SFML/System/String.hpp>
#include <SFML/Window/WindowStyle.hpp> // Prevent conflict with macro None from Xlib
#include <X11/Xlib.h>
#include <deque>

Expand Down Expand Up @@ -241,6 +242,12 @@ class WindowImplX11 : public WindowImpl
////////////////////////////////////////////////////////////
void initialize();

////////////////////////////////////////////////////////////
/// \brief Create a transparent mouse cursor
///
////////////////////////////////////////////////////////////
void createHiddenCursor();

////////////////////////////////////////////////////////////
/// \brief Cleanup graphical resources attached to the window
///
Expand All @@ -267,7 +274,8 @@ class WindowImplX11 : public WindowImpl
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
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?
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?
Expand Down

0 comments on commit 6ba2bb1

Please sign in to comment.