Ticket #748: hwcursor.diff

File hwcursor.diff, 15.2 KB (added by Zsolt Dollenstein, 12 years ago)

Hardware cursors on unix (with fix for atlas crash)

  • source/lib/sysdep/os/android/android.cpp

     
    2323#include "precompiled.h"
    2424
    2525#include "lib/sysdep/sysdep.h"
     26#include "lib/sysdep/cursor.h"
    2627
     28#include "lib/external_libraries/libsdl.h"
     29
    2730Status sys_clipboard_set(const wchar_t* UNUSED(text))
    2831{
    2932    return INFO::OK;
     
    6164}
    6265
    6366}
     67
     68// stub implementation of sys_cursor* functions
     69
     70// note: do not return ERR_NOT_IMPLEMENTED or similar because that
     71// would result in WARN_ERRs.
     72Status sys_cursor_create(int w, int h, void* bgra_img, int hx, int hy, sys_cursor* cursor)
     73{
     74    UNUSED2(w);
     75    UNUSED2(h);
     76    UNUSED2(hx);
     77    UNUSED2(hy);
     78    UNUSED2(bgra_img);
     79
     80    *cursor = 0;
     81    return INFO::OK;
     82}
     83
     84// returns a dummy value representing an empty cursor
     85Status sys_cursor_create_empty(sys_cursor* cursor)
     86{
     87    *cursor = (void*)1; // any non-zero value, since the cursor NULL has special meaning
     88    return INFO::OK;
     89}
     90
     91// replaces the current system cursor with the one indicated. need only be
     92// called once per cursor; pass 0 to restore the default.
     93Status sys_cursor_set(sys_cursor cursor)
     94{
     95    if (cursor) // dummy empty cursor
     96        SDL_ShowCursor(SDL_DISABLE);
     97    else // restore default cursor
     98        SDL_ShowCursor(SDL_ENABLE);
     99
     100    return INFO::OK;
     101}
     102
     103// destroys the indicated cursor and frees its resources. if it is
     104// currently the system cursor, the default cursor is restored first.
     105Status sys_cursor_free(sys_cursor cursor)
     106{
     107    // bail now to prevent potential confusion below; there's nothing to do.
     108    if(!cursor)
     109        return INFO::OK;
     110
     111    SDL_ShowCursor(SDL_ENABLE);
     112
     113    return INFO::OK;
     114}
     115
     116Status sys_cursor_reset()
     117{
     118    return INFO::OK;
     119}
     120
  • source/lib/sysdep/os/unix/unix.cpp

     
    2626#include <stdio.h>
    2727#include <wchar.h>
    2828
    29 #include "lib/external_libraries/libsdl.h"
    3029#include "lib/utf8.h"
    3130#include "lib/sysdep/sysdep.h"
    32 #include "lib/sysdep/cursor.h"
    3331#include "udbg.h"
    3432
    3533#include <boost/algorithm/string/replace.hpp>
     
    4543#define URL_OPEN_COMMAND "xdg-open"
    4644#endif
    4745
    48 
    4946bool sys_IsDebuggerPresent()
    5047{
    5148    return false;
     
    283280    return ERR::FAIL;
    284281}
    285282
    286 // stub for sys_cursor_create - we don't need to implement this (SDL/X11 only
    287 // has monochrome cursors so we need to use the software cursor anyways)
    288 
    289 // note: do not return ERR_NOT_IMPLEMENTED or similar because that
    290 // would result in WARN_ERRs.
    291 Status sys_cursor_create(size_t w, size_t h, void* bgra_img, size_t hx, size_t hy, sys_cursor* cursor)
    292 {
    293     UNUSED2(w);
    294     UNUSED2(h);
    295     UNUSED2(hx);
    296     UNUSED2(hy);
    297     UNUSED2(bgra_img);
    298 
    299     *cursor = 0;
    300     return INFO::OK;
    301 }
    302 
    303 // returns a dummy value representing an empty cursor
    304 Status sys_cursor_create_empty(sys_cursor* cursor)
    305 {
    306     *cursor = (void*)1; // any non-zero value, since the cursor NULL has special meaning
    307     return INFO::OK;
    308 }
    309 
    310 // replaces the current system cursor with the one indicated. need only be
    311 // called once per cursor; pass 0 to restore the default.
    312 Status sys_cursor_set(sys_cursor cursor)
    313 {
    314     if (cursor) // dummy empty cursor
    315         SDL_ShowCursor(SDL_DISABLE);
    316     else // restore default cursor
    317         SDL_ShowCursor(SDL_ENABLE);
    318 
    319     return INFO::OK;
    320 }
    321 
    322 // destroys the indicated cursor and frees its resources. if it is
    323 // currently the system cursor, the default cursor is restored first.
    324 Status sys_cursor_free(sys_cursor cursor)
    325 {
    326     // bail now to prevent potential confusion below; there's nothing to do.
    327     if(!cursor)
    328         return INFO::OK;
    329 
    330     SDL_ShowCursor(SDL_ENABLE);
    331 
    332     return INFO::OK;
    333 }
    334 
    335 Status sys_cursor_reset()
    336 {
    337     return INFO::OK;
    338 }
    339 
    340283// note: just use the sector size: Linux aio doesn't really care about
    341284// the alignment of buffers/lengths/offsets, so we'll just pick a
    342285// sane value and not bother scanning all drives.
  • source/lib/sysdep/os/unix/x/x.cpp

     
    3434
    3535#include "lib/debug.h"
    3636#include "lib/sysdep/gfx.h"
     37#include "lib/sysdep/cursor.h"
    3738
    3839#include "ps/VideoMode.h"
    3940
     
    4243#include <Xlib.h>
    4344#include <stdlib.h>
    4445#include <Xatom.h>
     46#include <Xcursor/Xcursor.h>
    4547
    4648#include "SDL.h"
    4749#include "SDL_syswm.h"
     
    147149wchar_t *sys_clipboard_get()
    148150{
    149151    Display *disp=XOpenDisplay(NULL);
    150     if (!disp)
     152    if(!disp)
    151153        return NULL;
    152154
    153155    // We use CLIPBOARD as the default, since the CLIPBOARD semantics are much
     
    155157    Atom selSource=XInternAtom(disp, "CLIPBOARD", False);
    156158
    157159    Window selOwner=XGetSelectionOwner(disp, selSource);
    158     if (selOwner == None)
     160    if(selOwner == None)
    159161    {
    160162        // However, since many apps don't use CLIPBOARD, but use PRIMARY instead
    161163        // we use XA_PRIMARY as a fallback clipboard. This is true for xterm,
     
    163165        selSource=XA_PRIMARY;
    164166        selOwner=XGetSelectionOwner(disp, selSource);
    165167    }
    166     if (selOwner != None) {
     168    if(selOwner != None) {
    167169        Atom pty=XInternAtom(disp, "SelectionPropertyTemp", False);
    168170        XConvertSelection(disp, selSource, XA_STRING, pty, selOwner, CurrentTime);
    169171        XFlush(disp);
     
    171173        Atom type;
    172174        int format=0, result=0;
    173175        unsigned long len=0, bytes_left=0, dummy=0;
    174         unsigned char *data=NULL;
     176        u8 *data=NULL;
    175177       
    176178        // Get the length of the property and some attributes
    177179        // bytes_left will contain the length of the selection
     
    183185            &format,        // return format
    184186            &len, &bytes_left,
    185187            &data);
    186         if (result != Success)
     188        if(result != Success)
    187189            debug_printf(L"clipboard_get: result: %d type:%lu len:%lu format:%d bytes_left:%lu\n",
    188190                result, type, len, format, bytes_left);
    189         if (result == Success && bytes_left > 0)
     191        if(result == Success && bytes_left > 0)
    190192        {
    191193            result = XGetWindowProperty (disp, selOwner,
    192194                pty, 0, bytes_left, 0,
    193195                AnyPropertyType, &type, &format,
    194196                &len, &dummy, &data);
    195197           
    196             if (result == Success)
     198            if(result == Success)
    197199            {
    198200                debug_printf(L"clipboard_get: XGetWindowProperty succeeded, returning data\n");
    199201                debug_printf(L"clipboard_get: data was: \"%hs\", type was %lu, XA_STRING atom is %lu\n", data, type, XA_STRING);
    200202               
    201                 if (type == XA_STRING) //Latin-1: Just copy into low byte of wchar_t
     203                if(type == XA_STRING) //Latin-1: Just copy into low byte of wchar_t
    202204                {
    203205                    wchar_t *ret=(wchar_t *)malloc((bytes_left+1)*sizeof(wchar_t));
    204206                    std::copy(data, data+bytes_left, ret);
     
    239241{
    240242    /* Pass on all non-window manager specific events immediately */
    241243    /* And do nothing if we don't actually have a clip-out to send out */
    242     if (event->type != SDL_SYSWMEVENT || !selection_data)
     244    if(event->type != SDL_SYSWMEVENT || !selection_data)
    243245        return 1;
    244246
    245247    /* Handle window-manager specific clipboard events */
     
    250252#else
    251253    XEvent* xevent = &event->syswm.msg->event.xevent;
    252254#endif
    253     switch (xevent->type) {
     255    switch(xevent->type) {
    254256        /* Copy the selection from our buffer to the requested property, and
    255257        convert to the requested target format */
    256258        case SelectionRequest: {
     
    267269            sevent.xselection.time = req->time;
    268270            // Simply strip all non-Latin1 characters and replace with '?'
    269271            // We should support XA_UTF8
    270             if (req->target == XA_STRING)
     272            if(req->target == XA_STRING)
    271273            {
    272274                size_t size = wcslen(selection_data);
    273275                u8* buf = (u8*)alloca(size);
    274276               
    275                 for (size_t i = 0; i < size; i++)
     277                for(size_t i = 0; i < size; i++)
    276278                {
    277279                    buf[i] = selection_data[i] < 0x100 ? selection_data[i] : '?';
    278280                }
     
    302304
    303305    SDL_VERSION(&info.version);
    304306#if SDL_VERSION_ATLEAST(2, 0, 0)
    305     if (SDL_GetWindowWMInfo(g_VideoMode.GetWindow(), &info))
     307    if(SDL_GetWindowWMInfo(g_VideoMode.GetWindow(), &info))
    306308#else
    307     if (SDL_GetWMInfo(&info))
     309    if(SDL_GetWMInfo(&info))
    308310#endif
    309311    {
    310312        /* Save the information for later use */
    311         if (info.subsystem == SDL_SYSWM_X11)
     313        if(info.subsystem == SDL_SYSWM_X11)
    312314        {
    313315            g_SDL_Display = info.info.x11.display;
    314316            g_SDL_Window = info.info.x11.window;
     
    352354
    353355    debug_printf(L"sys_clipboard_set: %ls\n", str);
    354356
    355     if (selection_data)
     357    if(selection_data)
    356358    {
    357359        free(selection_data);
    358360        selection_data = NULL;
     
    383385    return INFO::OK;
    384386}
    385387
     388struct sys_cursor_impl
     389{
     390    XcursorImage* image;
     391    X__Cursor cursor;
     392};
     393
     394static XcursorPixel cursor_pixel_to_x11_format(const XcursorPixel& bgra_pixel)
     395{
     396    BOOST_STATIC_ASSERT(sizeof(XcursorPixel) == 4 * sizeof(u8));
     397    XcursorPixel ret;
     398    u8* dst = reinterpret_cast<u8*>(&ret);
     399    const u8* b = reinterpret_cast<const u8*>(&bgra_pixel);
     400    const u8 a = b[3];
     401
     402    for(size_t i = 0; i < 3; ++i)
     403        *dst++ = (b[i]) * a / 255;
     404    *dst = a;
     405    return ret;
     406}
     407
     408static bool get_wminfo(SDL_SysWMinfo& wminfo)
     409{
     410    SDL_VERSION(&wminfo.version);
     411    const int ret = SDL_GetWMInfo(&wminfo);
     412    if(ret == 1)
     413        return true;
     414
     415    if(ret == -1)
     416    {
     417        debug_printf(L"SDL_GetWMInfo failed\n");
     418        return false;
     419    }
     420    if(ret == 0)
     421    {
     422        debug_printf(L"SDL_GetWMInfo is not implemented on this platform\n");
     423        return false;
     424    }
     425
     426    debug_printf(L"SDL_GetWMInfo returned an unknown value: %d\n", ret);
     427    return false;
     428}
     429
     430Status sys_cursor_create(int w, int h, void* bgra_img, int hx, int hy, sys_cursor* cursor)
     431{
     432    debug_printf(L"Using Xcursor to sys_cursor_create %d x %d cursor\n", w, h);
     433    XcursorImage* image = XcursorImageCreate(w, h);
     434    if(!image)
     435        WARN_RETURN(ERR::FAIL);
     436
     437    const XcursorPixel* bgra_img_begin = reinterpret_cast<XcursorPixel*>(bgra_img);
     438    std::transform(bgra_img_begin, bgra_img_begin + (w*h), image->pixels,
     439                   cursor_pixel_to_x11_format);
     440    image->xhot = hx;
     441    image->yhot = hy;
     442
     443    SDL_SysWMinfo wminfo;
     444    if(!get_wminfo(wminfo))
     445        WARN_RETURN(ERR::FAIL);
     446
     447    sys_cursor_impl* impl = new sys_cursor_impl;
     448    impl->image = image;
     449    impl->cursor = XcursorImageLoadCursor(wminfo.info.x11.display, image);
     450    if(impl->cursor == None)
     451        WARN_RETURN(ERR::FAIL);
     452
     453    *cursor = static_cast<sys_cursor>(impl);
     454    return INFO::OK;
     455}
     456
     457// returns a dummy value representing an empty cursor
     458Status sys_cursor_create_empty(sys_cursor* cursor)
     459{
     460    static u8 transparent_bgra[] = { 0x0, 0x0, 0x0, 0x0 };
     461
     462    return sys_cursor_create(1, 1, static_cast<void*>(transparent_bgra), 0, 0, cursor);
     463}
     464
     465// replaces the current system cursor with the one indicated. need only be
     466// called once per cursor; pass 0 to restore the default.
     467Status sys_cursor_set(sys_cursor cursor)
     468{
     469    if(!cursor) // restore default cursor
     470        SDL_ShowCursor(SDL_DISABLE);
     471    else
     472    {
     473        SDL_SysWMinfo wminfo;
     474        if(!get_wminfo(wminfo))
     475            WARN_RETURN(ERR::FAIL);
     476
     477        wminfo.info.x11.lock_func();
     478        SDL_ShowCursor(SDL_ENABLE);
     479        // wminfo.info.x11.window is sometimes 0, in which case
     480        // it causes a crash; in these cases use fswindow instead
     481        Window& window = wminfo.info.x11.window ? wminfo.info.x11.window : wminfo.info.x11.fswindow;
     482        XDefineCursor(wminfo.info.x11.display, window,
     483                      static_cast<sys_cursor_impl*>(cursor)->cursor);
     484        wminfo.info.x11.unlock_func();
     485    }
     486
     487    return INFO::OK;
     488}
     489
     490// destroys the indicated cursor and frees its resources. if it is
     491// currently the system cursor, the default cursor is restored first.
     492Status sys_cursor_free(sys_cursor cursor)
     493{
     494    // bail now to prevent potential confusion below; there's nothing to do.
     495    if(!cursor)
     496        return INFO::OK;
     497
     498    sys_cursor_set(0); // restore default cursor
     499    sys_cursor_impl* impl = static_cast<sys_cursor_impl*>(cursor);
     500
     501    XcursorImageDestroy(impl->image);
     502
     503    SDL_SysWMinfo wminfo;
     504    if(!get_wminfo(wminfo))
     505        return ERR::FAIL;
     506    XFreeCursor(wminfo.info.x11.display, impl->cursor);
     507
     508    delete impl;
     509
     510    return INFO::OK;
     511}
     512
     513Status sys_cursor_reset()
     514{
     515    return INFO::OK;
     516}
     517
     518
    386519#endif  // #if HAVE_X
  • source/lib/sysdep/os/osx/osx.cpp

     
    2626
    2727#include "lib/sysdep/sysdep.h"
    2828#include "lib/sysdep/gfx.h"
     29#include "lib/sysdep/cursor.h"
    2930#include "osx_bundle.h"
    3031
     32#include "SDL.h"
     33
    3134#include <mach-o/dyld.h>
    3235#include <ApplicationServices/ApplicationServices.h>
    3336
     
    133136
    134137    return path;
    135138}
     139
     140// stub implementation of sys_cursor* functions
     141// TODO: we should probably implement this using NSCursor
     142
     143// note: do not return ERR_NOT_IMPLEMENTED or similar because that
     144// would result in WARN_ERRs.
     145Status sys_cursor_create(int w, int h, void* bgra_img, int hx, int hy, sys_cursor* cursor)
     146{
     147    UNUSED2(w);
     148    UNUSED2(h);
     149    UNUSED2(hx);
     150    UNUSED2(hy);
     151    UNUSED2(bgra_img);
     152
     153    *cursor = 0;
     154    return INFO::OK;
     155}
     156
     157// returns a dummy value representing an empty cursor
     158Status sys_cursor_create_empty(sys_cursor* cursor)
     159{
     160    *cursor = (void*)1; // any non-zero value, since the cursor NULL has special meaning
     161    return INFO::OK;
     162}
     163
     164// replaces the current system cursor with the one indicated. need only be
     165// called once per cursor; pass 0 to restore the default.
     166Status sys_cursor_set(sys_cursor cursor)
     167{
     168    if (cursor) // dummy empty cursor
     169        SDL_ShowCursor(SDL_DISABLE);
     170    else // restore default cursor
     171        SDL_ShowCursor(SDL_ENABLE);
     172
     173    return INFO::OK;
     174}
     175
     176// destroys the indicated cursor and frees its resources. if it is
     177// currently the system cursor, the default cursor is restored first.
     178Status sys_cursor_free(sys_cursor cursor)
     179{
     180    // bail now to prevent potential confusion below; there's nothing to do.
     181    if(!cursor)
     182        return INFO::OK;
     183
     184    SDL_ShowCursor(SDL_ENABLE);
     185
     186    return INFO::OK;
     187}
     188
     189Status sys_cursor_reset()
     190{
     191    return INFO::OK;
     192}
  • source/lib/res/graphics/cursor.cpp

     
    3939// On Windows, allow runtime choice between system cursors and OpenGL
    4040// cursors (Windows = more responsive, OpenGL = more consistent with what
    4141// the game sees)
    42 #if OS_WIN
     42#if OS_WIN || (OS_UNIX && !OS_MACOSX)
    4343# define ALLOW_SYS_CURSOR 1
    4444#else
    4545# define ALLOW_SYS_CURSOR 0
  • build/premake/extern_libs4.lua

     
    587587            })
    588588        end,
    589589    },
     590    xcursor = {
     591        link_settings = function()
     592            add_default_links({
     593                unix_names = { "Xcursor" },
     594            })
     595        end,
     596    },
    590597    zlib = {
    591598        compile_settings = function()
    592599            if os.is("windows") then
  • build/premake/premake4.lua

     
    707707    "valgrind",
    708708}
    709709
    710 if not os.is("windows") and not _OPTIONS["android"] then
     710if not os.is("windows") and not _OPTIONS["android"] and not os.is("macosx") then
    711711    table.insert(used_extern_libs, "x11")
     712    table.insert(used_extern_libs, "xcursor")
    712713end
    713714
    714715if not _OPTIONS["without-audio"] then