Results 1 to 3 of 3

Thread: X11 Cursor

  1. #1
    Lesser Knight
    Join Date
    Jan 2011
    Location
    Vienna, Austria
    Posts
    30

    Default X11 Cursor

    Hello,

    currently, ClanLib is missing support for setting Cursors on X11. I created some sample code on how to set a simple, static cursor. As far as I could see, animated cursors do not work the same as in Windows (or I did not understand the minimalistic docs I found correctly), so I just did static ones.

    I did not really see through the way clanlib's platform independence is achieved (providers everywhere ), so I just post the basic code here and hope that maybe someone with more insight than me can fit the pieces into clanlib.

    Code:
    #include <X11/Xlib.h>
    #include <X11/Xcursor/Xcursor.h>
    
    Cursor createCursor(Display* disp, const CL_PixelBuffer& inputImage, const CL_Point& hotspot) {
        int desired_width = inputImage.get_width();
        int desired_height = inputImage.get_height();
    
        XcursorImage* cursorImage = XcursorImageCreate(desired_width, desired_height);
        cursorImage->xhot = hotspot.x;
        cursorImage->yhot = hotspot.y;
    
        // X11 expects cursor image pixels to be 32bit in argb8 format
        CL_PixelBuffer convertedBuffer = CL_PixelBuffer(desired_width, desired_height, cl_argb8);
        inputImage.convert(convertedBuffer);
    
        int byteCount = desired_width * desired_height * sizeof(XcursorPixel);
        memcpy(cursorImage->pixels, convertedBuffer.get_data(), byteCount);
    
        return XcursorImageLoadCursor(disp, cursorImage);
    }
    
    void setCursor(Display* disp, Window wnd, Cursor curs) {
        XDefineCursor(disp, wnd, curs);
    }
    
    void freeCursor(Display* disp, Cursor curs) {
        XFreeCursor(disp, curs);
    }
    Cheers,
    spin

  2. #2
    ClanLib Developer
    Join Date
    May 2007
    Posts
    1,824

    Default

    Looks good. It just needs adding to Display/X11 code. Should be simple to do.

    I'll add it to the todo http://clanlib.org/wiki/TODO

  3. #3
    ClanLib Developer
    Join Date
    May 2007
    Posts
    1,824

    Default

    I created the patch.

    But it still has a couple of issues
    1) It does not deallocate the cursor correctly. A bit more thought is required, ideally, the cursor should be destroyed when the window is destroyed.
    2) It uses XCursor (that uses XRender). This is an extra dependency. "configure.ac" should detect it's presence, and allow ClanLib to compile even if it's not found.
    3) It should support animated cursors. Looking at the source code to XRender, it should be possible. XCursor docs hint at it, but I have not looked at the source.

    I am not convinced if it is worth the effort to fix these problems.

    We can emulate animated cursors in our application by hiding the cursor, and drawing an image in the display window at the mouse X,Y position.

    The disadvantage is that the cursor will be inside the display window frame (and cannot overlay it)

    The following patch works with Tests/Display/AnimCursor (but without animation)

    Code:
    Index: Sources/GL1/GLX/gl1_window_provider_glx.cpp
    ===================================================================
    --- Sources/GL1/GLX/gl1_window_provider_glx.cpp	(revision 5773)
    +++ Sources/GL1/GLX/gl1_window_provider_glx.cpp	(working copy)
    @@ -542,7 +542,7 @@
     
     CL_CursorProvider *CL_GL1WindowProvider_GLX::create_cursor(const CL_SpriteDescription &sprite_description, const CL_Point &hotspot)
     {
    -	return new CL_CursorProvider_X11(sprite_description, hotspot);
    +	return new CL_CursorProvider_X11(x11_window.get_display(), sprite_description, hotspot);
     }
     
     void CL_GL1WindowProvider_GLX::set_cursor(CL_CursorProvider *cursor)
    Index: Sources/SWRender/swr_display_window_provider.cpp
    ===================================================================
    --- Sources/SWRender/swr_display_window_provider.cpp	(revision 5773)
    +++ Sources/SWRender/swr_display_window_provider.cpp	(working copy)
    @@ -202,7 +202,7 @@
     #ifdef WIN32
     	return new CL_CursorProvider_Win32(sprite_description, hotspot);
     #elif !defined(__APPLE__)
    -	return new CL_CursorProvider_X11(sprite_description, hotspot);
    +	return new CL_CursorProvider_X11(window.get_display(), sprite_description, hotspot);
     #endif
     }
     
    Index: Sources/GL/GLX/opengl_window_provider_glx.cpp
    ===================================================================
    --- Sources/GL/GLX/opengl_window_provider_glx.cpp	(revision 5773)
    +++ Sources/GL/GLX/opengl_window_provider_glx.cpp	(working copy)
    @@ -800,7 +800,7 @@
     
     CL_CursorProvider *CL_OpenGLWindowProvider_GLX::create_cursor(const CL_SpriteDescription &sprite_description, const CL_Point &hotspot)
     {
    -	return new CL_CursorProvider_X11(sprite_description, hotspot);
    +	return new CL_CursorProvider_X11(x11_window.get_display(), sprite_description, hotspot);
     }
     
     void CL_OpenGLWindowProvider_GLX::set_cursor(CL_CursorProvider *cursor)
    Index: Sources/Display/X11/x11_window.cpp
    ===================================================================
    --- Sources/Display/X11/x11_window.cpp	(revision 5774)
    +++ Sources/Display/X11/x11_window.cpp	(working copy)
    @@ -54,6 +54,8 @@
     #include <X11/XKBlib.h>
     #include <dlfcn.h>
     
    +#include "cursor_provider_x11.h"
    +
     #define _NET_WM_STATE_REMOVE  0
     #define _NET_WM_STATE_ADD     1
     #define _NET_WM_STATE_TOGGLE  2
    @@ -1232,7 +1234,8 @@
     
     void CL_X11Window::set_cursor(CL_CursorProvider_X11 *cursor)
     {
    -	//TODO:
    +	if (cursor && cursor->handle)
    +		XDefineCursor(disp, window, cursor->handle);
     }
     
     // Note, This function does not search the cache, this is intentional, as the event should never be in the cache when this function is used
    Index: Sources/Display/X11/cursor_provider_x11.cpp
    ===================================================================
    --- Sources/Display/X11/cursor_provider_x11.cpp	(revision 5773)
    +++ Sources/Display/X11/cursor_provider_x11.cpp	(working copy)
    @@ -36,14 +36,18 @@
     /////////////////////////////////////////////////////////////////////////////
     // CL_CursorProvider_X11 Construction:
     
    -CL_CursorProvider_X11::CL_CursorProvider_X11(const CL_SpriteDescription &sprite_description, const CL_Point &hotspot)
    -: handle(0)
    +CL_CursorProvider_X11::CL_CursorProvider_X11(Display *new_disp, const CL_SpriteDescription &sprite_description, const CL_Point &hotspot) : disp(new_disp), handle(0)
     {
     	handle = create_cursor(sprite_description, hotspot);
     }
     
     CL_CursorProvider_X11::~CL_CursorProvider_X11()
     {
    +	// FIXME: This class should be a made into a disposable object. "disp" may not longer exist
    +	//if (disp && handle)
    +	//	XFreeCursor(disp, handle);
    +
    +	// XcursorImageDestroy
     }
     
     /////////////////////////////////////////////////////////////////////////////
    @@ -55,10 +59,33 @@
     /////////////////////////////////////////////////////////////////////////////
     // CL_CursorProvider_X11 Implementation:
     
    -int CL_CursorProvider_X11::create_cursor(const CL_SpriteDescription &sprite_description, const CL_Point &hotspot) const
    +Cursor CL_CursorProvider_X11::create_cursor(const CL_SpriteDescription &sprite_description, const CL_Point &hotspot) const
     {
    -	// TODO: Implement me :)
    -	return 0;
    +	const std::vector<CL_SpriteDescriptionFrame> &frames = sprite_description.get_frames();
    +
    +	if (frames.empty())
    +		throw CL_Exception("Cannot create cursor with no image frames");
    +
    +	const CL_SpriteDescriptionFrame &frame = frames[0];
    +
    +	if (frame.type != CL_SpriteDescriptionFrame::type_pixelbuffer)
    +		throw CL_Exception("Only pixel buffer sprite frames currently supported for cursors");
    +
    +	int desired_width = frame.rect.get_width();
    +	int desired_height = frame.rect.get_height();
    +
    +	XcursorImage* cursorImage = XcursorImageCreate(desired_width, desired_height);
    +	cursorImage->xhot = hotspot.x;
    +	cursorImage->yhot = hotspot.y;
    +
    +	// X11 expects cursor image pixels to be 32bit in argb8 format
    +	CL_PixelBuffer convertedBuffer = CL_PixelBuffer(desired_width, desired_height, cl_argb8);
    +	frame.pixelbuffer.convert(convertedBuffer);
    +
    +	int byteCount = desired_width * desired_height * sizeof(XcursorPixel);
    +	memcpy(cursorImage->pixels, convertedBuffer.get_data(), byteCount);
    +
    +	return XcursorImageLoadCursor(disp, cursorImage);
     }
     
     
    Index: Sources/Display/X11/cursor_provider_x11.h
    ===================================================================
    --- Sources/Display/X11/cursor_provider_x11.h	(revision 5773)
    +++ Sources/Display/X11/cursor_provider_x11.h	(working copy)
    @@ -34,6 +34,8 @@
     #include "API/Core/System/databuffer.h"
     #include <vector>
     
    +#include <X11/Xcursor/Xcursor.h>
    +
     class CL_PixelBufferRef;
     class CL_Point;
     class CL_DataBuffer;
    @@ -45,7 +47,7 @@
     /// \{
     
     public:
    -	CL_CursorProvider_X11(const CL_SpriteDescription &sprite_description, const CL_Point &hotspot);
    +	CL_CursorProvider_X11(Display *disp, const CL_SpriteDescription &sprite_description, const CL_Point &hotspot);
     
     	~CL_CursorProvider_X11();
     
    @@ -55,7 +57,7 @@
     /// \{
     
     public:
    -	int handle;
    +	Cursor handle;
     
     
     /// \}
    @@ -72,8 +74,9 @@
     /// \{
     
     private:
    -	int create_cursor(const CL_SpriteDescription &sprite_description, const CL_Point &hotspot) const;
    +	Cursor create_cursor(const CL_SpriteDescription &sprite_description, const CL_Point &hotspot) const;
     
    +	Display *disp;
     /// \}
     };
     
    Index: configure.ac
    ===================================================================
    --- configure.ac	(revision 5773)
    +++ configure.ac	(working copy)
    @@ -156,6 +156,7 @@
     
     extra_LIBS_clanRegExp="-lpcre"
     extra_LIBS_clanSqlite="-ldl"
    +extra_LIBS_clanDisplay="-lXcursor"
     
     dnl ----------------------------------------
     dnl Additional include and library paths:
    Attached Files Attached Files

Similar Threads

  1. [PATCH] Win32 animated cursor
    By huntercool in forum Official ClanLib SDK Forums
    Replies: 2
    Last Post: 06-18-2010, 10:53 AM
  2. Cursor and Sprite question.
    By Eng C. Born in forum Official ClanLib SDK Forums
    Replies: 4
    Last Post: 04-18-2009, 02:05 PM
  3. CL_Sprite mouse cursor
    By AlfaRed in forum Official ClanLib SDK Forums
    Replies: 2
    Last Post: 02-11-2009, 09:29 AM
  4. Disable mouse cursor movement
    By TheQuantumMechanic in forum Official ClanLib SDK Forums
    Replies: 2
    Last Post: 07-30-2008, 08:23 PM
  5. resolution, mouse cursor, etc
    By Uhfgood in forum Novashell Game Creation System
    Replies: 1
    Last Post: 09-06-2007, 12:40 AM

Bookmarks

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •