Changed: #1034 Implement CCustomMouse for Linux

This commit is contained in:
kervala 2010-11-04 19:35:44 +01:00
parent ce97b8f27b
commit 42b7d0148b
7 changed files with 214 additions and 229 deletions

View file

@ -3932,9 +3932,4 @@ bool CDriverD3D::convertBitmapToIcon(const NLMISC::CBitmap &bitmap, HICON &icon,
return true; return true;
} }
bool CDriverD3D::convertBitmapToCursor(const NLMISC::CBitmap &bitmap, nlCursor &cursor, uint iconWidth, uint iconHeight, uint iconDepth, const NLMISC::CRGBA &col, sint hotSpotX, sint hotSpotY)
{
return convertBitmapToIcon(bitmap, cursor, iconWidth, iconHeight, iconDepth, col, hotSpotX, hotSpotY, true);
}
} // NL3D } // NL3D

View file

@ -177,11 +177,8 @@ void CDriverD3D::addCursor(const std::string &name, const NLMISC::CBitmap &curso
CCursor &curs = _Cursors[name]; CCursor &curs = _Cursors[name];
curs = CCursor(); // erase possible previous cursor curs = CCursor(); // erase possible previous cursor
uint destWidth; uint destWidth = GetSystemMetrics(SM_CXCURSOR);
uint destHeight; uint destHeight = GetSystemMetrics(SM_CYCURSOR);
destWidth = GetSystemMetrics(SM_CXCURSOR);
destHeight = GetSystemMetrics(SM_CYCURSOR);
// build a square bitmap // build a square bitmap
uint tmpSize = std::max(maxX - minX + 1, maxY - minY + 1); uint tmpSize = std::max(maxX - minX + 1, maxY - minY + 1);
@ -198,9 +195,12 @@ void CDriverD3D::addCursor(const std::string &name, const NLMISC::CBitmap &curso
// first resampling, same for all cursors // first resampling, same for all cursors
tmpSize = (uint) (tmpSize * curs.HotspotScale); tmpSize = (uint) (tmpSize * curs.HotspotScale);
if (tmpSize == 0) tmpSize = 1; if (tmpSize == 0) tmpSize = 1;
/*
if (curs.HotspotScale < 1.f)
{
curs.Src.resample(tmpSize, tmpSize); curs.Src.resample(tmpSize, tmpSize);
*/ }
// shrink if necessary // shrink if necessary
if (tmpSize > destWidth || tmpSize > destHeight) // need to shrink ? if (tmpSize > destWidth || tmpSize > destHeight) // need to shrink ?
{ {
@ -305,12 +305,8 @@ nlCursor CDriverD3D::buildCursor(const CBitmap &src, NLMISC::CRGBA col, uint8 ro
{ {
nlassert(isAlphaBlendedCursorSupported()); nlassert(isAlphaBlendedCursorSupported());
uint mouseW; uint mouseW = GetSystemMetrics(SM_CXCURSOR);
uint mouseH; uint mouseH = GetSystemMetrics(SM_CYCURSOR);
// use cursor size from system
mouseW = GetSystemMetrics(SM_CXCURSOR);
mouseH = GetSystemMetrics(SM_CYCURSOR);
CBitmap rotSrc = src; CBitmap rotSrc = src;
if (rot > 3) rot = 3; // mimic behavior of 'CViewRenderer::drawRotFlipBitmapTiled' (why not rot & 3 ??? ...) if (rot > 3) rot = 3; // mimic behavior of 'CViewRenderer::drawRotFlipBitmapTiled' (why not rot & 3 ??? ...)
@ -374,6 +370,7 @@ void CDriverD3D::setMousePos(float x, float y)
if (_HWnd == EmptyWindow) if (_HWnd == EmptyWindow)
return; return;
// convert position size from float to pixels
sint x1 = (sint)((float)_CurrentMode.Width*x); sint x1 = (sint)((float)_CurrentMode.Width*x);
sint y1 = (sint)((float)_CurrentMode.Height*(1.0f-y)); sint y1 = (sint)((float)_CurrentMode.Height*(1.0f-y));
@ -385,6 +382,28 @@ void CDriverD3D::setMousePos(float x, float y)
SetCursorPos(pt.x, pt.y); SetCursorPos(pt.x, pt.y);
} }
// ***************************************************************************
void CDriverD3D::setCapture (bool b)
{
H_AUTO_D3D(CDriverD3D_setCapture);
if (b && isSystemCursorInClientArea() && !isSystemCursorCaptured())
{
SetCapture(_HWnd);
}
else if (!b && isSystemCursorCaptured())
{
// if hardware mouse and not in client area, then force to update its aspect by updating its pos
if (!isSystemCursorInClientArea())
{
// force update
showCursor(true);
}
ReleaseCapture();
}
}
// *************************************************************************** // ***************************************************************************
bool CDriverD3D::isSystemCursorInClientArea() bool CDriverD3D::isSystemCursorInClientArea()
{ {
@ -433,28 +452,6 @@ bool CDriverD3D::isSystemCursorInClientArea()
return true; return true;
} }
// ***************************************************************************
void CDriverD3D::setCapture (bool b)
{
H_AUTO_D3D(CDriverD3D_setCapture);
if (b && isSystemCursorInClientArea() && !isSystemCursorCaptured())
{
SetCapture(_HWnd);
}
else if (!b && isSystemCursorCaptured())
{
// if hardware mouse and not in client area, then force to update its aspect by updating its pos
if (!isSystemCursorInClientArea())
{
// force update
showCursor(true);
}
ReleaseCapture();
}
}
// *************************************************************************** // ***************************************************************************
bool CDriverD3D::isSystemCursorCaptured() bool CDriverD3D::isSystemCursorCaptured()
{ {
@ -578,4 +575,9 @@ uint CDriverD3D::getDoubleClickDelay(bool hardwareMouse)
return res; return res;
} }
bool CDriverD3D::convertBitmapToCursor(const NLMISC::CBitmap &bitmap, nlCursor &cursor, uint iconWidth, uint iconHeight, uint iconDepth, const NLMISC::CRGBA &col, sint hotSpotX, sint hotSpotY)
{
return convertBitmapToIcon(bitmap, cursor, iconWidth, iconHeight, iconDepth, col, hotSpotX, hotSpotY, true);
}
} // NL3D } // NL3D

View file

@ -1002,6 +1002,9 @@ private:
// Convert a NLMISC::CBitmap to nlCursor // Convert a NLMISC::CBitmap to nlCursor
bool convertBitmapToCursor(const NLMISC::CBitmap &bitmap, nlCursor &cursor, uint iconWidth, uint iconHeight, uint iconDepth, const NLMISC::CRGBA &col, sint hotSpotX, sint hotSpotY); bool convertBitmapToCursor(const NLMISC::CBitmap &bitmap, nlCursor &cursor, uint iconWidth, uint iconHeight, uint iconDepth, const NLMISC::CRGBA &col, sint hotSpotX, sint hotSpotY);
// Return the best cursor size depending on specified width and height
bool getBestCursorSize(uint srcWidth, uint srcHeight, uint &dstWidth, uint &dstHeight);
// build a cursor from src, src should have the same size that the hardware cursor // build a cursor from src, src should have the same size that the hardware cursor
// or a assertion is thrown // or a assertion is thrown
nlCursor buildCursor(const NLMISC::CBitmap &src, NLMISC::CRGBA col, uint8 rot, sint hotSpotX, sint hotSpotY); nlCursor buildCursor(const NLMISC::CBitmap &src, NLMISC::CRGBA col, uint8 rot, sint hotSpotX, sint hotSpotY);

View file

@ -205,20 +205,8 @@ void CDriverGL::addCursor(const std::string &name, const NLMISC::CBitmap &cursor
CCursor &curs = _Cursors[name]; CCursor &curs = _Cursors[name];
curs = CCursor(); // erase possible previous cursor curs = CCursor(); // erase possible previous cursor
uint destWidth; uint destWidth = 32, destHeight = 32;
uint destHeight; getBestCursorSize(width, height, destWidth, destHeight);
#ifdef NL_OS_WINDOWS
destWidth = GetSystemMetrics(SM_CXCURSOR);
destHeight = GetSystemMetrics(SM_CYCURSOR);
#elif defined(NL_OS_MAC)
#elif defined(NL_OS_UNIX)
Status res = XQueryBestCursor(_dpy, _win, width, height, &destWidth, &destHeight);
#endif
// build a square bitmap // build a square bitmap
uint tmpSize = std::max(maxX - minX + 1, maxY - minY + 1); uint tmpSize = std::max(maxX - minX + 1, maxY - minY + 1);
@ -384,22 +372,8 @@ nlCursor CDriverGL::buildCursor(const CBitmap &src, NLMISC::CRGBA col, uint8 rot
{ {
nlassert(isAlphaBlendedCursorSupported()); nlassert(isAlphaBlendedCursorSupported());
uint mouseW; uint mouseW = 32, mouseH = 32;
uint mouseH; getBestCursorSize(src.getWidth(), src.getHeight(), mouseW, mouseH);
#ifdef NL_OS_WINDOWS
// use cursor size from system
mouseW = GetSystemMetrics(SM_CXCURSOR);
mouseH = GetSystemMetrics(SM_CYCURSOR);
#elif defined(NL_OS_MAC)
#elif defined(NL_OS_UNIX)
// use best cursor size for bitmap
Status res = XQueryBestCursor(_dpy, _win, src.getWidth(), src.getHeight(), &mouseW, &mouseH);
#endif
CBitmap rotSrc = src; CBitmap rotSrc = src;
if (rot > 3) rot = 3; // mimic behavior of 'CViewRenderer::drawRotFlipBitmapTiled' (why not rot & 3 ??? ...) if (rot > 3) rot = 3; // mimic behavior of 'CViewRenderer::drawRotFlipBitmapTiled' (why not rot & 3 ??? ...)
@ -811,4 +785,161 @@ uint CDriverGL::getDoubleClickDelay(bool hardwareMouse)
return res; return res;
} }
bool CDriverGL::getBestCursorSize(uint srcWidth, uint srcHeight, uint &dstWidth, uint &dstHeight)
{
#ifdef NL_OS_WINDOWS
// Windows provides default size for cursors
dstWidth = (uint)GetSystemMetrics(SM_CXCURSOR);
dstHeight = (uint)GetSystemMetrics(SM_CYCURSOR);
#elif defined(NL_OS_MAC)
#elif defined(NL_OS_UNIX)
Status res = XQueryBestCursor(_dpy, _win, srcWidth, srcHeight, &dstWidth, &dstHeight);
nlwarning("XQueryBestCursor returned %d", (sint)res);
#endif
return true;
}
bool CDriverGL::convertBitmapToCursor(const NLMISC::CBitmap &bitmap, nlCursor &cursor, uint iconWidth, uint iconHeight, uint iconDepth, const NLMISC::CRGBA &col, sint hotSpotX, sint hotSpotY)
{
#if defined(NL_OS_WINDOWS)
return convertBitmapToIcon(bitmap, cursor, iconWidth, iconHeight, iconDepth, col, hotSpotX, hotSpotY, true);
#elif defined(NL_OS_UNIX) && defined(HAVE_XRENDER) && !defined(NL_OS_MAC)
CBitmap src = bitmap;
// resample bitmap if necessary
if (src.getWidth() != iconWidth || src.getHeight() != iconHeight)
{
src.resample(iconWidth, iconHeight);
}
CBitmap colorBm;
colorBm.resize(iconWidth, iconHeight, CBitmap::RGBA);
const CRGBA *srcColorPtr = (CRGBA *) &(src.getPixels()[0]);
const CRGBA *srcColorPtrLast = srcColorPtr + (iconWidth * iconHeight);
CRGBA *destColorPtr = (CRGBA *) &(colorBm.getPixels()[0]);
do
{
// colorize icon
destColorPtr->modulateFromColor(*srcColorPtr, col);
// X11 wants BGRA pixels : swap red and blue channels
std::swap(destColorPtr->R, destColorPtr->B);
// premultiplied alpha
if (destColorPtr->A < 255)
{
destColorPtr->R = (destColorPtr->R * destColorPtr->A) / 255;
destColorPtr->G = (destColorPtr->G * destColorPtr->A) / 255;
destColorPtr->B = (destColorPtr->B * destColorPtr->A) / 255;
}
++ srcColorPtr;
++ destColorPtr;
}
while (srcColorPtr != srcColorPtrLast);
// use malloc() because X will free() data itself
CRGBA *src32 = (CRGBA*)malloc(colorBm.getSize()*4);
memcpy(src32, &colorBm.getPixels(0)[0], colorBm.getSize()*4);
uint size = iconWidth * iconHeight;
// Create the icon pixmap
sint screen = DefaultScreen(_dpy);
Visual *visual = DefaultVisual(_dpy, screen);
if (!visual)
{
nlwarning("Failed to get a default visual for screen %d", screen);
return false;
}
// create the icon pixmap
XImage* image = XCreateImage(_dpy, visual, 32, ZPixmap, 0, (char*)src32, iconWidth, iconHeight, 32, 0);
if (!image)
{
nlwarning("Failed to set the window's icon");
return false;
}
Pixmap pixmap = XCreatePixmap(_dpy, _win, iconWidth, iconHeight, 32 /* defDepth */);
if (!pixmap)
{
nlwarning("Failed to create a pixmap %ux%ux%d", iconWidth, iconHeight, 32);
return false;
}
GC gc = XCreateGC(_dpy, pixmap, 0, NULL);
if (!gc)
{
nlwarning("Failed to create a GC");
return false;
}
sint res = XPutImage(_dpy, pixmap, gc, image, 0, 0, 0, 0, iconWidth, iconHeight);
// should return 0
nlwarning("XPutImage returned %d", res);
res = XFreeGC(_dpy, gc);
// should return 1
nlwarning("XFreeGC returned %d", res);
if (image->data)
{
free(image->data);
image->data = NULL;
}
XDestroyImage(image);
XRenderPictFormat *format = XRenderFindStandardFormat(_dpy, PictStandardARGB32);
if (!format)
{
nlwarning("Failed to find a standard format");
return false;
}
Picture picture = XRenderCreatePicture(_dpy, pixmap, format, 0, 0);
if (!picture)
{
nlwarning("Failed to create picture");
return false;
}
cursor = XRenderCreateCursor(_dpy, picture, (uint)hotSpotX, (uint)hotSpotY);
if (!cursor)
{
nlwarning("Failed to create cursor");
return false;
}
XRenderFreePicture(_dpy, picture);
res = XFreePixmap(_dpy, pixmap);
// should return 1
nlwarning("XFreePixmap returned %d", res);
return true;
#else
return false;
#endif
}
} // NL3D } // NL3D

View file

@ -2646,7 +2646,7 @@ bool CDriverGL::convertBitmapToIcon(const NLMISC::CBitmap &bitmap, HICON &icon,
const CRGBA *srcColorPtr = (CRGBA *) &(src.getPixels()[0]); const CRGBA *srcColorPtr = (CRGBA *) &(src.getPixels()[0]);
const CRGBA *srcColorPtrLast = srcColorPtr + (iconWidth * iconHeight); const CRGBA *srcColorPtrLast = srcColorPtr + (iconWidth * iconHeight);
CRGBA *destColorPtr = (CRGBA *) &(colorBm.getPixels()[0]); CRGBA *destColorPtr = (CRGBA *) &(colorBm.getPixels()[0]);
static volatile uint8 alphaThreshold = 127; static uint8 alphaThreshold = 127;
do do
{ {
destColorPtr->modulateFromColor(*srcColorPtr, col); destColorPtr->modulateFromColor(*srcColorPtr, col);
@ -2674,7 +2674,7 @@ bool CDriverGL::convertBitmapToIcon(const NLMISC::CBitmap &bitmap, HICON &icon,
for (uint k = 0;k < colorBm16.size(); ++k) for (uint k = 0;k < colorBm16.size(); ++k)
{ {
if (src32[k].A <= 120) if (src32[k].A <= alphaThreshold)
{ {
bitMask[k / 8] |= (0x80 >> (k & 7)); bitMask[k / 8] |= (0x80 >> (k & 7));
} }
@ -2707,18 +2707,8 @@ bool CDriverGL::convertBitmapToIcon(const NLMISC::CBitmap &bitmap, HICON &icon,
return true; return true;
} }
bool CDriverGL::convertBitmapToCursor(const NLMISC::CBitmap &bitmap, nlCursor &cursor, uint iconWidth, uint iconHeight, uint iconDepth, const NLMISC::CRGBA &col, sint hotSpotX, sint hotSpotY)
{
return convertBitmapToIcon(bitmap, cursor, iconWidth, iconHeight, iconDepth, col, hotSpotX, hotSpotY, true);
}
#elif defined(NL_OS_MAC) #elif defined(NL_OS_MAC)
bool CDriverGL::convertBitmapToCursor(const NLMISC::CBitmap &bitmap, nlCursor &cursor, uint iconWidth, uint iconHeight, uint iconDepth, const NLMISC::CRGBA &col, sint hotSpotX, sint hotSpotY)
{
return false;
}
#elif defined(NL_OS_UNIX) #elif defined(NL_OS_UNIX)
bool CDriverGL::convertBitmapToIcon(const NLMISC::CBitmap &bitmap, std::vector<long> &icon) bool CDriverGL::convertBitmapToIcon(const NLMISC::CBitmap &bitmap, std::vector<long> &icon)
@ -2745,140 +2735,6 @@ bool CDriverGL::convertBitmapToIcon(const NLMISC::CBitmap &bitmap, std::vector<l
return true; return true;
} }
bool CDriverGL::convertBitmapToCursor(const NLMISC::CBitmap &bitmap, nlCursor &cursor, uint iconWidth, uint iconHeight, uint iconDepth, const NLMISC::CRGBA &col, sint hotSpotX, sint hotSpotY)
{
#ifdef HAVE_XRENDER
CBitmap src = bitmap;
// resample bitmap if necessary
if (src.getWidth() != iconWidth || src.getHeight() != iconHeight)
{
src.resample(iconWidth, iconHeight);
}
CBitmap colorBm;
colorBm.resize(iconWidth, iconHeight, CBitmap::RGBA);
const CRGBA *srcColorPtr = (CRGBA *) &(src.getPixels()[0]);
const CRGBA *srcColorPtrLast = srcColorPtr + (iconWidth * iconHeight);
CRGBA *destColorPtr = (CRGBA *) &(colorBm.getPixels()[0]);
do
{
// colorize icon
destColorPtr->modulateFromColor(*srcColorPtr, col);
// X11 wants BGRA pixels : swap red and blue channels
std::swap(destColorPtr->R, destColorPtr->B);
// premultiplied alpha
if (destColorPtr->A < 255)
{
destColorPtr->R = (destColorPtr->R * destColorPtr->A) / 255;
destColorPtr->G = (destColorPtr->G * destColorPtr->A) / 255;
destColorPtr->B = (destColorPtr->B * destColorPtr->A) / 255;
}
++ srcColorPtr;
++ destColorPtr;
}
while (srcColorPtr != srcColorPtrLast);
// use malloc() because X will free() data itself
CRGBA *src32 = (CRGBA*)malloc(colorBm.getSize()*4);
memcpy(src32, &colorBm.getPixels(0)[0], colorBm.getSize()*4);
uint size = iconWidth * iconHeight;
// Create the icon pixmap
sint screen = DefaultScreen(_dpy);
Visual *visual = DefaultVisual(_dpy, screen);
if (!visual)
{
nlwarning("Failed to get a default visual for screen %d", screen);
return false;
}
// create the icon pixmap
XImage* image = XCreateImage(_dpy, visual, 32, ZPixmap, 0, (char*)src32, iconWidth, iconHeight, 32, 0);
if (!image)
{
nlwarning("Failed to set the window's icon");
return false;
}
Pixmap pixmap = XCreatePixmap(_dpy, _win, iconWidth, iconHeight, 32 /* defDepth */);
if (!pixmap)
{
nlwarning("Failed to create a pixmap %ux%ux%d", iconWidth, iconHeight, 32);
return false;
}
GC gc = XCreateGC(_dpy, pixmap, 0, NULL);
if (!gc)
{
nlwarning("Failed to create a GC");
return false;
}
sint res = XPutImage(_dpy, pixmap, gc, image, 0, 0, 0, 0, iconWidth, iconHeight);
// should return 0
nlwarning("XPutImage returned %d", res);
res = XFreeGC(_dpy, gc);
// should return 1
nlwarning("XFreeGC returned %d", res);
if (image->data)
{
free(image->data);
image->data = NULL;
}
XDestroyImage(image);
XRenderPictFormat *format = XRenderFindStandardFormat(_dpy, PictStandardARGB32);
if (!format)
{
nlwarning("Failed to find a standard format");
return false;
}
Picture picture = XRenderCreatePicture(_dpy, pixmap, format, 0, 0);
if (!picture)
{
nlwarning("Failed to create picture");
return false;
}
cursor = XRenderCreateCursor(_dpy, picture, (uint)hotSpotX, (uint)hotSpotY);
if (!cursor)
{
nlwarning("Failed to create cursor");
return false;
}
XRenderFreePicture(_dpy, picture);
res = XFreePixmap(_dpy, pixmap);
// should return 1
nlwarning("XFreePixmap returned %d", res);
return true;
#else
return false;
#endif
}
#endif #endif
} // NL3D } // NL3D

View file

@ -64,7 +64,6 @@ CInputHandlerManager::CInputHandlerManager()
_MouseButtonsState = noButton; _MouseButtonsState = noButton;
_MouseX = _MouseY = _MouseLastX = _MouseLastY = 0; _MouseX = _MouseY = _MouseLastX = _MouseLastY = 0;
_Focus = true; _Focus = true;
// Driver->setFocus(true);
_MouseWheel = 0; _MouseWheel = 0;
_SkipInterfaceManager=false; _SkipInterfaceManager=false;
_RecoverFocusLost = false; _RecoverFocusLost = false;
@ -184,7 +183,6 @@ void CInputHandlerManager::operator ()(const NLMISC::CEvent &event)
_RecoverFocusLost = true; // force to update mouse pos on next click or move _RecoverFocusLost = true; // force to update mouse pos on next click or move
Driver->showCursor(IsMouseCursorHardware()); Driver->showCursor(IsMouseCursorHardware());
_Focus = true; _Focus = true;
// Driver->setFocus(true);
} }
if(!_SkipInterfaceManager) if(!_SkipInterfaceManager)