mirror of
https://github.com/SFML/SFML.git
synced 2024-11-28 22:31:09 +08:00
Added X11 implementation
This commit is contained in:
parent
219c14b0c2
commit
34ea68bd1d
@ -57,17 +57,17 @@ public:
|
||||
/// ------------------------------------|:-----:|:--------:|:--------:
|
||||
/// 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
|
||||
@ -126,6 +126,11 @@ public:
|
||||
/// 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
|
||||
|
@ -26,6 +26,12 @@
|
||||
// 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
|
||||
{
|
||||
@ -33,30 +39,114 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
@ -82,9 +83,17 @@ private:
|
||||
|
||||
friend class WindowImplX11;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Release the cursor, if we have loaded one.
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void release();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Member data
|
||||
////////////////////////////////////////////////////////////
|
||||
::Display* m_display;
|
||||
::Cursor m_cursor;
|
||||
};
|
||||
|
||||
} // namespace priv
|
||||
|
@ -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>
|
||||
@ -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),
|
||||
@ -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),
|
||||
@ -895,7 +896,7 @@ 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);
|
||||
}
|
||||
|
||||
@ -903,7 +904,8 @@ void WindowImplX11::setMouseCursorVisible(bool visible)
|
||||
////////////////////////////////////////////////////////////
|
||||
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
|
||||
grabFocus();
|
||||
|
||||
// Create the hidden cursor
|
||||
createHiddenCursor();
|
||||
|
||||
// Flush the commands queue
|
||||
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()
|
||||
{
|
||||
|
@ -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>
|
||||
|
||||
@ -241,6 +242,12 @@ private:
|
||||
////////////////////////////////////////////////////////////
|
||||
void initialize();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \brief Create a transparent mouse cursor
|
||||
///
|
||||
////////////////////////////////////////////////////////////
|
||||
void createHiddenCursor();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// \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
|
||||
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?
|
||||
|
Loading…
Reference in New Issue
Block a user