Change Encyclo button name and macros icon
[ryzomcore.git] / nel / src / 3d / driver / opengl / driver_opengl_inputs.cpp
blob685a94aa1f68a9ef41c756010f19ae06b07c6ac8
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdopengl.h"
18 #include "driver_opengl.h"
20 #if defined(NL_OS_UNIX) && !defined(NL_OS_MAC)
21 # include <X11/Xatom.h>
22 # ifdef HAVE_XRENDER
23 # include <X11/extensions/Xrender.h>
24 # endif // HAVE_XRENDER
25 # ifdef HAVE_XCURSOR
26 # include <X11/Xcursor/Xcursor.h>
27 # endif // HAVE_XCURSOR
28 #endif // defined(NL_OS_UNIX) && !defined(NL_OS_MAC)
30 #include "nel/3d/u_driver.h"
31 #include "nel/misc/file.h"
33 using namespace std;
34 using namespace NLMISC;
36 #ifdef DEBUG_NEW
37 #define new DEBUG_NEW
38 #endif
40 namespace NL3D {
42 #ifdef NL_STATIC
43 #ifdef USE_OPENGLES
44 namespace NLDRIVERGLES {
45 #else
46 namespace NLDRIVERGL {
47 #endif
48 #endif
50 // *************************************************************************************
51 CDriverGL::CCursor::CCursor() : ColorDepth(CDriverGL::ColorDepth32),
52 OrigHeight(32),
53 HotspotScale(1.f),
54 HotspotOffsetX(0),
55 HotspotOffsetY(0),
56 HotSpotX(0),
57 HotSpotY(0),
58 Cursor(EmptyCursor),
59 Col(CRGBA::White),
60 Rot(0)
62 #if defined(NL_OS_UNIX) && !defined(NL_OS_MAC)
63 Dpy = NULL;
64 #endif
67 // *************************************************************************************
68 CDriverGL::CCursor::~CCursor()
70 reset();
73 // *************************************************************************************
74 void CDriverGL::CCursor::reset()
76 if (Cursor != EmptyCursor)
78 #ifdef NL_OS_WINDOWS
79 DestroyIcon(Cursor);
80 #elif defined(NL_OS_MAC)
81 #elif defined(NL_OS_UNIX)
82 XFreeCursor(Dpy, Cursor);
83 XSync(Dpy, False);
84 #endif
88 // *************************************************************************************
89 CDriverGL::CCursor& CDriverGL::CCursor::operator= (const CDriverGL::CCursor& from)
91 if (&from == this)
92 return *this;
93 Src = from.Src; // requires more than a surface copy
94 OrigHeight = from.OrigHeight;
95 HotspotScale = from.HotspotScale;
96 HotspotOffsetX = from.HotspotOffsetX;
97 HotspotOffsetY = from.HotspotOffsetY;
98 HotSpotX = from.HotSpotX;
99 HotSpotY = from.HotSpotY;
100 Cursor = from.Cursor;
101 Col = from.Col;
102 Rot = from.Rot;
103 #if defined(NL_OS_UNIX) && !defined(NL_OS_MAC)
104 Dpy = from.Dpy;
105 #endif
106 return *this;
109 // *************************************************************************************
110 bool CDriverGL::isAlphaBlendedCursorSupported()
112 if (!_AlphaBlendedCursorSupportRetrieved)
114 #ifdef NL_OS_WINDOWS
115 // Support starts with windows 2000 (not only from XP as seen in most docs)
116 // NB : Additionnaly, could query D3D caps to know if
117 // color hardware cursor is supported, not only emulated,
118 // but can't be sure that using the win32 api 'SetCursor' uses the same resources
119 // So far, seems to be supported on any modern card used by the game anyway ...
120 OSVERSIONINFO osvi;
121 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
122 if (GetVersionEx(&osvi))
124 _AlphaBlendedCursorSupported = (osvi.dwMajorVersion >= 5);
126 #elif defined(NL_OS_MAC)
127 #elif defined(NL_OS_UNIX)
129 _AlphaBlendedCursorSupported = false;
131 #ifdef HAVE_XCURSOR
132 if (!_AlphaBlendedCursorSupported && XcursorSupportsARGB(_dpy))
133 _AlphaBlendedCursorSupported = true;
134 #endif // HAVE_XCURSOR
136 if (!_AlphaBlendedCursorSupported && _xrender_version > 0)
137 _AlphaBlendedCursorSupported = true;
139 #endif
141 _AlphaBlendedCursorSupportRetrieved = true;
144 return _AlphaBlendedCursorSupported;
147 // *************************************************************************************
148 void CDriverGL::addCursor(const std::string &name, const NLMISC::CBitmap &cursorBitmap)
150 if (!isAlphaBlendedCursorSupported()) return;
152 nlassert(cursorBitmap.getWidth() != 0);
153 nlassert(cursorBitmap.getHeight() != 0);
155 // find used part base on alpha, to avoid too much shrinking
156 const CRGBA *pixels = (const CRGBA *) &cursorBitmap.getPixels()[0];
157 uint minX, maxX, minY, maxY;
158 uint width = cursorBitmap.getWidth();
159 uint height = cursorBitmap.getHeight();
161 minX = 0;
162 for (uint x = 0; x < width; ++x)
164 bool stop = false;
165 minX = x;
166 for (uint y = 0; y < height; ++y)
168 if(pixels[x + y * width].A != 0)
170 stop = true;
171 break;
174 if (stop) break;
177 maxX = width - 1;
178 for (sint x = width - 1; x >= 0; --x)
180 bool stop = false;
181 maxX = (uint) x;
182 for (uint y = 0; y < height; ++y)
184 if(pixels[x + y * width].A != 0)
186 stop = true;
187 break;
190 if (stop) break;
193 minY = 0;
194 for (uint y = 0; y < height; ++y)
196 bool stop = false;
197 minY = y;
198 for (uint x = 0; x < width; ++x)
200 if(pixels[x + y * width].A != 0)
202 stop = true;
203 break;
206 if (stop) break;
209 maxY = height - 1;
210 for (sint y = height - 1; y >= 0; --y)
212 bool stop = false;
213 maxY = (uint) y;
214 for (uint x = 0; x < width; ++x)
216 if(pixels[x + y * width].A != 0)
218 stop = true;
219 break;
222 if (stop) break;
225 CCursor &curs = _Cursors[name];
226 curs = CCursor(); // erase possible previous cursor
228 uint destWidth = 32, destHeight = 32;
229 getBestCursorSize(width, height, destWidth, destHeight);
231 // build a square bitmap
232 uint tmpSize = std::max(maxX - minX + 1, maxY - minY + 1);
233 curs.Src.resize(tmpSize, tmpSize);
234 // blit at top left corner
235 curs.Src.blit(cursorBitmap, minX, minY, maxX - minX + 1, maxY - minY + 1, 0, 0);
237 curs.OrigHeight = cursorBitmap.getHeight();
238 curs.HotspotOffsetX = minX;
239 curs.HotspotOffsetY = minY;
241 curs.HotspotScale = _CursorScale;
242 clamp(curs.HotspotScale, 0.f, 1.f);
243 // first resampling, same for all cursors
244 tmpSize = (uint) (tmpSize * curs.HotspotScale);
245 if (tmpSize == 0) tmpSize = 1;
247 if (curs.HotspotScale < 1.f)
249 curs.Src.resample(tmpSize, tmpSize);
252 // shrink if necessary
253 if (tmpSize > destWidth || tmpSize > destHeight) // need to shrink ?
255 // constraint proportions
256 curs.HotspotScale *= std::min(float(destWidth) / tmpSize, float(destHeight) / tmpSize);
257 curs.Src.resample(destWidth, destHeight);
259 else
261 CBitmap final;
262 final.resize(destWidth, destHeight);
263 final.blit(&curs.Src, 0, 0);
264 curs.Src.swap(final);
267 if (name == _CurrName)
269 updateCursor();
273 // *************************************************************************************
274 void CDriverGL::createCursors()
276 #ifdef NL_OS_WINDOWS
277 _DefaultCursor = LoadCursor(NULL, IDC_ARROW);
278 _BlankCursor = NULL;
279 #elif defined(NL_OS_MAC)
280 #elif defined(NL_OS_UNIX)
281 _DefaultCursor = None;
283 if (_dpy && _win && _BlankCursor == EmptyCursor)
285 // create blank cursor
286 char bm_no_data[] = { 0,0,0,0,0,0,0,0 };
287 Pixmap pixmap_no_data = XCreateBitmapFromData (_dpy, _win, bm_no_data, 8, 8);
288 XColor black;
289 memset(&black, 0, sizeof (XColor));
290 black.flags = DoRed | DoGreen | DoBlue;
291 _BlankCursor = XCreatePixmapCursor (_dpy, pixmap_no_data, pixmap_no_data, &black, &black, 0, 0);
292 XFreePixmap(_dpy, pixmap_no_data);
294 #endif
297 // *************************************************************************************
298 void CDriverGL::releaseCursors()
300 #ifdef NL_OS_WINDOWS
301 SetClassLongPtr(_win, GCLP_HCURSOR, 0);
302 #elif defined(NL_OS_MAC)
303 #elif defined(NL_OS_UNIX)
304 XUndefineCursor(_dpy, _win);
305 XFreeCursor(_dpy, _BlankCursor);
306 #endif
308 _Cursors.clear();
311 // *************************************************************************************
312 void CDriverGL::updateCursor(bool forceRebuild)
314 setCursor(_CurrName, _CurrCol, _CurrRot, _CurrHotSpotX, _CurrHotSpotY, forceRebuild);
317 // *************************************************************************************
318 void CDriverGL::setCursor(const std::string &name, NLMISC::CRGBA col, uint8 rot, sint hotSpotX, sint hotSpotY, bool forceRebuild)
320 // don't update cursor if it's hidden or if custom cursors are not suppported
321 if (!isAlphaBlendedCursorSupported() || _CurrName == "none") return;
323 _CurrName = name;
324 _CurrCol = col;
325 _CurrRot = rot;
326 _CurrHotSpotX = hotSpotX;
327 _CurrHotSpotY = hotSpotY;
329 // cursor has to be changed next time
330 if (_CurrName.empty()) return;
332 if (rot > 3) rot = 3; // same than 'CViewRenderer::drawRotFlipBitmapTiled
334 TCursorMap::iterator it = _Cursors.find(name);
336 nlCursor cursorHandle = _DefaultCursor;
338 if (it != _Cursors.end())
340 // Update cursor if modified or not already built
341 CCursor &curs = it->second;
342 hotSpotX = (sint) (curs.HotspotScale * (hotSpotX - curs.HotspotOffsetX));
343 hotSpotY = (sint) (curs.HotspotScale * ((curs.OrigHeight - hotSpotY) - curs.HotspotOffsetY));
344 if (curs.Cursor == EmptyCursor ||
345 curs.HotSpotX != hotSpotX ||
346 curs.HotSpotY != hotSpotY ||
347 curs.Col != col ||
348 curs.Rot != rot ||
349 curs.ColorDepth != _ColorDepth ||
350 forceRebuild
353 curs.reset();
354 curs.Cursor = buildCursor(curs.Src, col, rot, hotSpotX, hotSpotY);
355 curs.Col = col;
356 curs.Rot = rot;
357 curs.HotSpotX = hotSpotX;
358 curs.HotSpotY = hotSpotY;
359 curs.ColorDepth = _ColorDepth;
360 #if defined(NL_OS_UNIX) && !defined(NL_OS_MAC)
361 curs.Dpy = _dpy;
362 #endif
364 cursorHandle = curs.Cursor ? curs.Cursor : _DefaultCursor;
367 if (isSystemCursorInClientArea() || isSystemCursorCaptured() || forceRebuild)
369 // if (CInputHandlerManager::getInstance()->hasFocus())
370 #ifdef NL_OS_WINDOWS
372 ::SetCursor(cursorHandle);
373 SetClassLongPtr(_win, GCLP_HCURSOR, (LONG_PTR) cursorHandle); // set default mouse icon to the last one
375 #elif defined(NL_OS_MAC)
376 #elif defined(NL_OS_UNIX)
377 if (cursorHandle == _DefaultCursor)
379 XUndefineCursor(_dpy, _win);
381 else
383 XDefineCursor(_dpy, _win, cursorHandle);
385 #endif
390 // *************************************************************************************
391 void CDriverGL::setCursorScale(float scale)
393 _CursorScale = scale;
396 // *************************************************************************************
397 nlCursor CDriverGL::buildCursor(const CBitmap &src, NLMISC::CRGBA col, uint8 rot, sint hotSpotX, sint hotSpotY)
399 nlassert(isAlphaBlendedCursorSupported());
401 uint mouseW = 32, mouseH = 32;
402 getBestCursorSize(src.getWidth(), src.getHeight(), mouseW, mouseH);
404 CBitmap rotSrc = src;
405 if (rot > 3) rot = 3; // mimic behavior of 'CViewRenderer::drawRotFlipBitmapTiled' (why not rot & 3 ??? ...)
406 switch(rot)
408 case 0: break;
409 case 1: rotSrc.rot90CW(); break;
410 case 2: rotSrc.rot90CW(); rotSrc.rot90CW(); break;
411 case 3: rotSrc.rot90CCW(); break;
414 // create a cursor from bitmap
415 nlCursor result = EmptyCursor;
416 convertBitmapToCursor(rotSrc, result, mouseW, mouseH, _ColorDepth == ColorDepth16 ? 16:32, col, hotSpotX, hotSpotY);
417 return result;
421 // *************************************************************************************
422 void CDriverGL::setSystemArrow()
424 H_AUTO_OGL(CDriverGL_setSystemArrow);
426 #ifdef NL_OS_WINDOWS
427 if (isSystemCursorInClientArea() || isSystemCursorCaptured())
429 SetCursor(_DefaultCursor);
432 // set default mouse icon to the default one
433 SetClassLongPtr(_win, GCLP_HCURSOR, (LONG_PTR) _DefaultCursor);
434 #elif defined(NL_OS_MAC)
435 #elif defined(NL_OS_UNIX)
436 XUndefineCursor(_dpy, _win);
437 #endif
440 // ***************************************************************************
441 void CDriverGL::showCursor(bool b)
443 H_AUTO_OGL(CDriverGL_showCursor);
445 if (_win == EmptyWindow)
446 return;
448 #ifdef NL_OS_WINDOWS
450 if (b)
452 // update current hardware icon to avoid to have the plain arrow
453 updateCursor(true);
455 while (ShowCursor(b) < 0)
458 else
460 while (ShowCursor(b) >= 0)
464 #elif defined(NL_OS_MAC)
466 // Mac OS manages a show/hide counter for the cursor, so hiding the cursor
467 // twice requires two calls to "show" to make the cursor visible again.
468 // Since other platforms seem to not do this, the functionality is masked here
469 // by only calling hide if the cursor is visible and only calling show if
470 // the cursor was hidden.
472 CGDisplayErr error = kCGErrorSuccess;
473 static bool visible = true;
475 if(b && !visible)
477 error = CGDisplayShowCursor(kCGDirectMainDisplay);
478 visible = true;
480 else if(!b && visible)
482 error = CGDisplayHideCursor(kCGDirectMainDisplay);
483 visible = false;
486 if(error != kCGErrorSuccess)
487 nlerror("cannot show / hide cursor");
489 #elif defined (NL_OS_UNIX)
491 if (!b)
493 XDefineCursor(_dpy, _win, _BlankCursor);
494 _CurrName = "none";
496 else
498 _CurrName.clear();
501 // update current hardware icon to avoid to have the plain arrow
502 updateCursor(true);
504 #endif // NL_OS_UNIX
507 // ***************************************************************************
508 void CDriverGL::setMousePos(float x, float y)
510 H_AUTO_OGL(CDriverGL_setMousePos)
512 if (_win == EmptyWindow || !_WindowFocus)
513 return;
515 sint x1 = (sint)((float)_CurrentMode.Width*x);
516 sint y1 = (sint)((float)_CurrentMode.Height*(1.0f-y));
518 #ifdef NL_OS_WINDOWS
520 // NeL window coordinate to MSWindows coordinates
521 POINT pt;
522 pt.x = x1;
523 pt.y = y1;
524 ClientToScreen (_win, &pt);
525 SetCursorPos(pt.x, pt.y);
527 #elif defined(NL_OS_MAC)
529 // CG wants absolute coordinates related to first screen's top left
531 // get the first screen's (conaints menubar) rect (this is not mainScreen)
532 NSRect firstScreenRect = [[[NSScreen screens] objectAtIndex:0] frame];
534 // get the rect (position, size) of the window
535 NSRect windowRect;
536 if([containerView() isInFullScreenMode])
537 windowRect = [[[containerView() window] screen] frame];
538 else
539 windowRect = [[containerView() window] frame];
541 // get the view's rect for height and width
542 NSRect viewRect = [containerView() frame];
544 // set the cursor position
545 CGDisplayErr error = CGDisplayMoveCursorToPoint(
546 kCGDirectMainDisplay, CGPointMake(
547 windowRect.origin.x + (viewRect.size.width * x),
548 firstScreenRect.size.height - windowRect.origin.y -
549 viewRect.size.height + ((1.0 - y) * viewRect.size.height)));
551 if(error != kCGErrorSuccess)
552 nlerror("cannot set mouse position");
554 #elif defined (NL_OS_UNIX)
556 XWarpPointer (_dpy, None, _win, None, None, None, None, x1, y1);
558 #endif // NL_OS_UNIX
561 // ***************************************************************************
562 void CDriverGL::setCapture (bool b)
564 H_AUTO_OGL(CDriverGL_setCapture);
566 #ifdef NL_OS_WINDOWS
568 if (b && isSystemCursorInClientArea() && !isSystemCursorCaptured())
570 SetCapture(_win);
572 else if (!b && isSystemCursorCaptured())
574 // if hardware mouse and not in client area, then force to update its aspect by updating its pos
575 if (!isSystemCursorInClientArea())
577 // force update
578 showCursor(true);
581 ReleaseCapture();
584 #elif defined(NL_OS_MAC)
586 // no need to capture
587 _MouseCaptured = b;
589 #elif defined (NL_OS_UNIX)
591 if(b /* && isSystemCursorInClientArea() && !isSystemCursorCaptured()*/) // capture the cursor.
593 // capture the cursor
594 XGrabPointer(_dpy, _win, True, 0, GrabModeAsync, GrabModeAsync, _win, None, CurrentTime);
595 _MouseCaptured = true;
597 else if (!b/* && isSystemCursorCaptured()*/)
599 // release the cursor
600 XUngrabPointer(_dpy, CurrentTime);
601 _MouseCaptured = false;
604 #endif // NL_OS_UNIX
607 // ***************************************************************************
608 bool CDriverGL::isSystemCursorInClientArea()
610 if (!_CurrentMode.Windowed)
612 #ifdef NL_OS_WINDOWS
613 return IsWindowVisible(_win) != FALSE;
614 #endif
615 return _WindowFocus;
617 else
619 #ifdef NL_OS_WINDOWS
620 POINT cursPos;
621 // the mouse should be in the client area of the window
622 if (!GetCursorPos(&cursPos))
624 return false;
626 HWND wnd = WindowFromPoint(cursPos);
627 if (wnd != _win)
629 return false; // not the same window
631 // want that the mouse be in the client area
632 RECT clientRect;
633 if (!GetClientRect(_win, &clientRect))
635 return false;
637 POINT tl, br;
638 tl.x = clientRect.left;
639 tl.y = clientRect.top;
640 br.x = clientRect.right;
641 br.y = clientRect.bottom;
642 if (!ClientToScreen(_win, &tl))
644 return false;
646 if (!ClientToScreen(_win, &br))
648 return false;
650 if ((cursPos.x < tl.x) || (cursPos.x >= br.x) || (cursPos.y < tl.y) || (cursPos.y >= br.y))
652 return false;
654 #elif defined(NL_OS_MAC)
655 // TODO: implement this
656 #elif defined (NL_OS_UNIX)
657 // TODO: implement this
658 #endif
659 // TODO: probably wrong if NeL window is docked inside parent (ie QT widget)
660 return _WindowFocus;
663 return true;
666 // ***************************************************************************
667 bool CDriverGL::isSystemCursorCaptured()
669 H_AUTO_OGL(CDriverGL_isSystemCursorCaptured);
671 #ifdef NL_OS_WINDOWS
672 return GetCapture() == _win;
673 #else
674 return _MouseCaptured;
675 #endif
678 bool CDriverGL::getBestCursorSize(uint srcWidth, uint srcHeight, uint &dstWidth, uint &dstHeight)
680 #ifdef NL_OS_WINDOWS
682 // Windows provides default size for cursors
683 dstWidth = (uint)GetSystemMetrics(SM_CXCURSOR);
684 dstHeight = (uint)GetSystemMetrics(SM_CYCURSOR);
686 #elif defined(NL_OS_MAC)
687 #elif defined(NL_OS_UNIX)
689 Status status = XQueryBestCursor(_dpy, _win, srcWidth, srcHeight, &dstWidth, &dstHeight);
691 if (!status)
693 nlwarning("XQueryBestCursor failed");
696 #endif
698 return true;
701 bool CDriverGL::convertBitmapToCursor(const NLMISC::CBitmap &bitmap, nlCursor &cursor, uint iconWidth, uint iconHeight, uint iconDepth, const NLMISC::CRGBA &col, sint hotSpotX, sint hotSpotY)
703 #if defined(NL_OS_WINDOWS)
705 return convertBitmapToIcon(bitmap, cursor, iconWidth, iconHeight, iconDepth, col, hotSpotX, hotSpotY, true);
707 #elif defined(NL_OS_UNIX) && !defined(NL_OS_MAC)
709 CBitmap src = bitmap;
711 // resample bitmap if necessary
712 if (src.getWidth() != iconWidth || src.getHeight() != iconHeight)
714 src.resample(iconWidth, iconHeight);
717 CBitmap colorBm;
718 colorBm.resize(iconWidth, iconHeight, CBitmap::RGBA);
719 const CRGBA *srcColorPtr = (CRGBA *) &(src.getPixels()[0]);
720 const CRGBA *srcColorPtrLast = srcColorPtr + (iconWidth * iconHeight);
721 CRGBA *destColorPtr = (CRGBA *) &(colorBm.getPixels()[0]);
725 // colorize icon
726 destColorPtr->modulateFromColor(*srcColorPtr, col);
728 // X11 wants BGRA pixels : swap red and blue channels
729 std::swap(destColorPtr->R, destColorPtr->B);
731 // premultiplied alpha
732 if (destColorPtr->A < 255)
734 destColorPtr->R = (destColorPtr->R * destColorPtr->A) / 255;
735 destColorPtr->G = (destColorPtr->G * destColorPtr->A) / 255;
736 destColorPtr->B = (destColorPtr->B * destColorPtr->A) / 255;
739 ++ srcColorPtr;
740 ++ destColorPtr;
742 while (srcColorPtr != srcColorPtrLast);
744 #ifdef HAVE_XCURSOR
746 if (XcursorSupportsARGB(_dpy))
748 XcursorImage *image = XcursorImageCreate(iconWidth, iconHeight);
750 if (!image)
752 nlwarning("Failed to create a XcusorImage with size %ux%u", iconWidth, iconHeight);
754 else
756 image->xhot = (uint)hotSpotX;
757 image->yhot = (uint)hotSpotY;
759 memcpy(image->pixels, &colorBm.getPixels(0)[0], colorBm.getSize()*4);
761 cursor = XcursorImageLoadCursor(_dpy, image);
763 XcursorImageDestroy(image);
767 #endif // HAVE_XCURSOR
769 #ifdef HAVE_XRENDER
771 if (_xrender_version > 0)
773 // use malloc() because X will free() data itself
774 CRGBA *src32 = (CRGBA*)malloc(colorBm.getSize()*4);
775 memcpy(src32, &colorBm.getPixels(0)[0], colorBm.getSize()*4);
777 uint size = iconWidth * iconHeight;
779 sint screen = DefaultScreen(_dpy);
780 Visual *visual = DefaultVisual(_dpy, screen);
782 if (!visual)
784 nlwarning("Failed to get a default visual for screen %d", screen);
785 return false;
788 // Create the icon image
789 XImage* image = XCreateImage(_dpy, visual, 32, ZPixmap, 0, (char*)src32, iconWidth, iconHeight, 32, 0);
791 if (!image)
793 nlwarning("Failed to set the window's icon");
794 return false;
797 // Create the icon pixmap
798 Pixmap pixmap = XCreatePixmap(_dpy, _win, iconWidth, iconHeight, 32 /* defDepth */);
800 if (!pixmap)
802 nlwarning("Failed to create a pixmap %ux%ux%d", iconWidth, iconHeight, 32);
803 return false;
806 // Create the icon graphic contest
807 GC gc = XCreateGC(_dpy, pixmap, 0, NULL);
809 if (!gc)
811 nlwarning("Failed to create a GC");
812 return false;
815 sint res = XPutImage(_dpy, pixmap, gc, image, 0, 0, 0, 0, iconWidth, iconHeight);
817 if (res)
819 nlwarning("XPutImage failed with code %d", res);
822 if (!XFreeGC(_dpy, gc))
824 nlwarning("XFreeGC failed");
827 if (image->data)
829 free(image->data);
830 image->data = NULL;
833 XDestroyImage(image);
835 XRenderPictFormat *format = XRenderFindStandardFormat(_dpy, PictStandardARGB32);
837 if (!format)
839 nlwarning("Failed to find a standard format");
840 return false;
843 Picture picture = XRenderCreatePicture(_dpy, pixmap, format, 0, 0);
845 if (!picture)
847 nlwarning("Failed to create picture");
848 return false;
851 cursor = XRenderCreateCursor(_dpy, picture, (uint)hotSpotX, (uint)hotSpotY);
853 if (!cursor)
855 nlwarning("Failed to create cursor");
856 return false;
859 XRenderFreePicture(_dpy, picture);
861 if (!XFreePixmap(_dpy, pixmap))
863 nlwarning("XFreePixmap failed");
866 return true;
869 #endif // HAVE_XRENDER
871 return false;
873 #else
875 return false;
877 #endif
880 #ifdef NL_STATIC
881 } // NLDRIVERGL/ES
882 #endif
884 } // NL3D