1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #include "CIrrDeviceLinux.h"
\r
7 #ifdef _IRR_COMPILE_WITH_X11_DEVICE_
\r
11 #include <sys/utsname.h>
\r
14 #include "IEventReceiver.h"
\r
15 #include "ISceneManager.h"
\r
16 #include "IGUIEnvironment.h"
\r
19 #include "irrString.h"
\r
20 #include "Keycodes.h"
\r
21 #include "COSOperator.h"
\r
22 #include "CColorConverter.h"
\r
23 #include "SIrrCreationParameters.h"
\r
24 #include "SExposedVideoData.h"
\r
25 #include "IGUISpriteBank.h"
\r
26 #include <X11/XKBlib.h>
\r
27 #include <X11/Xatom.h>
\r
29 #if defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)
\r
30 #include "CEGLManager.h"
\r
33 #if defined(_IRR_COMPILE_WITH_OPENGL_)
\r
34 #include "CGLXManager.h"
\r
37 #ifdef _IRR_LINUX_XCURSOR_
\r
38 #include <X11/Xcursor/Xcursor.h>
\r
41 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
46 #include <sys/joystick.h>
\r
49 // linux/joystick.h includes linux/input.h, which #defines values for various KEY_FOO keys.
\r
50 // These override the irr::KEY_FOO equivalents, which stops key handling from working.
\r
51 // As a workaround, defining _INPUT_H stops linux/input.h from being included; it
\r
52 // doesn't actually seem to be necessary except to pull in sys/ioctl.h.
\r
54 #include <sys/ioctl.h> // Would normally be included in linux/input.h
\r
55 #include <linux/joystick.h>
\r
59 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
65 #ifdef _IRR_COMPILE_WITH_OPENGL_
\r
66 IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
\r
69 #ifdef _IRR_COMPILE_WITH_OGLES1_
\r
70 IVideoDriver* createOGLES1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
\r
73 #ifdef _IRR_COMPILE_WITH_OGLES2_
\r
74 IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
\r
77 #ifdef _IRR_COMPILE_WITH_WEBGL1_
\r
78 IVideoDriver* createWebGL1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
\r
81 } // end namespace irr
\r
85 Atom X_ATOM_CLIPBOARD;
\r
86 Atom X_ATOM_TARGETS;
\r
87 Atom X_ATOM_UTF8_STRING;
\r
89 Atom X_ATOM_NETWM_MAXIMIZE_VERT;
\r
90 Atom X_ATOM_NETWM_MAXIMIZE_HORZ;
\r
91 Atom X_ATOM_NETWM_STATE;
\r
93 Atom X_ATOM_WM_DELETE_WINDOW;
\r
99 CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters& param)
\r
100 : CIrrDeviceStub(param),
\r
101 #ifdef _IRR_COMPILE_WITH_X11_
\r
102 XDisplay(0), VisualInfo(0), Screennr(0), XWindow(0), StdHints(0), SoftwareImage(0),
\r
103 XInputMethod(0), XInputContext(0),
\r
106 Width(param.WindowSize.Width), Height(param.WindowSize.Height),
\r
107 WindowHasFocus(false), WindowMinimized(false),
\r
108 UseXVidMode(false), UseXRandR(false),
\r
109 ExternalWindow(false), AutorepeatSupport(0)
\r
112 setDebugName("CIrrDeviceLinux");
\r
115 // print version, distribution etc.
\r
116 // thx to LynxLuna for pointing me to the uname function
\r
117 core::stringc linuxversion;
\r
118 struct utsname LinuxInfo;
\r
121 linuxversion += LinuxInfo.sysname;
\r
122 linuxversion += " ";
\r
123 linuxversion += LinuxInfo.release;
\r
124 linuxversion += " ";
\r
125 linuxversion += LinuxInfo.version;
\r
126 linuxversion += " ";
\r
127 linuxversion += LinuxInfo.machine;
\r
129 Operator = new COSOperator(linuxversion, this);
\r
130 os::Printer::log(linuxversion.c_str(), ELL_INFORMATION);
\r
136 if (CreationParams.DriverType != video::EDT_NULL)
\r
138 // create the window, only if we do not use the null device
\r
139 if (!createWindow())
\r
141 setResizable(param.WindowResizable);
\r
144 // create cursor control
\r
145 CursorControl = new CCursorControl(this, CreationParams.DriverType == video::EDT_NULL);
\r
153 #ifdef _IRR_COMPILE_WITH_X11_
\r
154 createInputContext();
\r
157 createGUIAndScene();
\r
162 CIrrDeviceLinux::~CIrrDeviceLinux()
\r
164 #ifdef _IRR_COMPILE_WITH_X11_
\r
167 // Disable cursor (it is drop'ed in stub)
\r
170 CursorControl->setVisible(false);
\r
171 static_cast<CCursorControl*>(CursorControl)->clearCursors();
\r
174 // Must free OpenGL textures etc before destroying context, so can't wait for stub destructor
\r
175 if ( GUIEnvironment )
\r
177 GUIEnvironment->drop();
\r
178 GUIEnvironment = NULL;
\r
180 if ( SceneManager )
\r
182 SceneManager->drop();
\r
183 SceneManager = NULL;
\r
187 VideoDriver->drop();
\r
188 VideoDriver = NULL;
\r
191 destroyInputContext();
\r
195 if (ContextManager)
\r
197 ContextManager->destroyContext();
\r
198 ContextManager->destroySurface();
\r
201 // Reset fullscreen resolution change
\r
202 switchToFullscreen(true);
\r
205 XDestroyImage(SoftwareImage);
\r
207 if (!ExternalWindow)
\r
209 XDestroyWindow(XDisplay,XWindow);
\r
210 XCloseDisplay(XDisplay);
\r
216 #endif // #ifdef _IRR_COMPILE_WITH_X11_
\r
218 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
\r
219 for (u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
\r
221 if (ActiveJoysticks[joystick].fd >= 0)
\r
223 close(ActiveJoysticks[joystick].fd);
\r
230 #if defined(_IRR_COMPILE_WITH_X11_) && defined(_DEBUG)
\r
231 int IrrPrintXError(Display *display, XErrorEvent *event)
\r
236 snprintf_irr(msg, 256, "%d", event->request_code);
\r
237 XGetErrorDatabaseText(display, "XRequest", msg, "unknown", msg2, 256);
\r
238 XGetErrorText(display, event->error_code, msg, 256);
\r
239 os::Printer::log("X Error", msg, ELL_WARNING);
\r
240 os::Printer::log("From call ", msg2, ELL_WARNING);
\r
246 bool CIrrDeviceLinux::switchToFullscreen(bool reset)
\r
248 if (!CreationParams.Fullscreen)
\r
252 #ifdef _IRR_LINUX_X11_VIDMODE_
\r
253 if (UseXVidMode && CreationParams.Fullscreen)
\r
255 XF86VidModeSwitchToMode(XDisplay, Screennr, &OldVideoMode);
\r
256 XF86VidModeSetViewPort(XDisplay, Screennr, 0, 0);
\r
259 #ifdef _IRR_LINUX_X11_RANDR_
\r
260 if (UseXRandR && CreationParams.Fullscreen)
\r
262 XRRScreenConfiguration *config=XRRGetScreenInfo(XDisplay,DefaultRootWindow(XDisplay));
\r
263 XRRSetScreenConfig(XDisplay,config,DefaultRootWindow(XDisplay),OldRandrMode,OldRandrRotation,CurrentTime);
\r
264 XRRFreeScreenConfigInfo(config);
\r
270 getVideoModeList();
\r
271 #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)
\r
272 s32 eventbase, errorbase;
\r
276 #ifdef _IRR_LINUX_X11_VIDMODE_
\r
277 if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase))
\r
279 // enumerate video modes
\r
281 XF86VidModeModeInfo** modes;
\r
283 XF86VidModeGetAllModeLines(XDisplay, Screennr, &modeCount, &modes);
\r
285 // find fitting mode
\r
286 for (s32 i = 0; i<modeCount; ++i)
\r
288 if (bestMode==-1 && modes[i]->hdisplay >= Width && modes[i]->vdisplay >= Height)
\r
290 else if (bestMode!=-1 &&
\r
291 modes[i]->hdisplay >= Width &&
\r
292 modes[i]->vdisplay >= Height &&
\r
293 modes[i]->hdisplay <= modes[bestMode]->hdisplay &&
\r
294 modes[i]->vdisplay <= modes[bestMode]->vdisplay)
\r
297 if (bestMode != -1)
\r
299 os::Printer::log("Starting vidmode fullscreen mode...", ELL_INFORMATION);
\r
300 os::Printer::log("hdisplay: ", core::stringc(modes[bestMode]->hdisplay).c_str(), ELL_INFORMATION);
\r
301 os::Printer::log("vdisplay: ", core::stringc(modes[bestMode]->vdisplay).c_str(), ELL_INFORMATION);
\r
303 XF86VidModeSwitchToMode(XDisplay, Screennr, modes[bestMode]);
\r
304 XF86VidModeSetViewPort(XDisplay, Screennr, 0, 0);
\r
309 os::Printer::log("Could not find specified video mode, running windowed.", ELL_WARNING);
\r
310 CreationParams.Fullscreen = false;
\r
317 #ifdef _IRR_LINUX_X11_RANDR_
\r
318 if (XRRQueryExtension(XDisplay, &eventbase, &errorbase))
\r
321 XRRScreenConfiguration *config=XRRGetScreenInfo(XDisplay,DefaultRootWindow(XDisplay));
\r
322 XRRScreenSize *modes=XRRConfigSizes(config,&modeCount);
\r
323 for (s32 i = 0; i<modeCount; ++i)
\r
325 if (bestMode==-1 && (u32)modes[i].width >= Width && (u32)modes[i].height >= Height)
\r
327 else if (bestMode!=-1 &&
\r
328 (u32)modes[i].width >= Width &&
\r
329 (u32)modes[i].height >= Height &&
\r
330 modes[i].width <= modes[bestMode].width &&
\r
331 modes[i].height <= modes[bestMode].height)
\r
334 if (bestMode != -1)
\r
336 os::Printer::log("Starting randr fullscreen mode...", ELL_INFORMATION);
\r
337 os::Printer::log("width: ", core::stringc(modes[bestMode].width).c_str(), ELL_INFORMATION);
\r
338 os::Printer::log("height: ", core::stringc(modes[bestMode].height).c_str(), ELL_INFORMATION);
\r
340 XRRSetScreenConfig(XDisplay,config,DefaultRootWindow(XDisplay),bestMode,OldRandrRotation,CurrentTime);
\r
343 XRRFreeScreenConfigInfo(config);
\r
348 os::Printer::log("VidMode or RandR extension must be installed to allow Irrlicht "
\r
349 "to switch to fullscreen mode. Running in windowed mode instead.", ELL_WARNING);
\r
350 CreationParams.Fullscreen = false;
\r
352 return CreationParams.Fullscreen;
\r
356 #if defined(_IRR_COMPILE_WITH_X11_)
\r
357 void IrrPrintXGrabError(int grabResult, const c8 * grabCommand )
\r
359 if ( grabResult == GrabSuccess )
\r
361 // os::Printer::log(grabCommand, ": GrabSuccess", ELL_INFORMATION);
\r
365 switch ( grabResult )
\r
367 case AlreadyGrabbed:
\r
368 os::Printer::log(grabCommand, ": AlreadyGrabbed", ELL_WARNING);
\r
370 case GrabNotViewable:
\r
371 os::Printer::log(grabCommand, ": GrabNotViewable", ELL_WARNING);
\r
374 os::Printer::log(grabCommand, ": GrabFrozen", ELL_WARNING);
\r
376 case GrabInvalidTime:
\r
377 os::Printer::log(grabCommand, ": GrabInvalidTime", ELL_WARNING);
\r
380 os::Printer::log(grabCommand, ": grab failed with unknown problem", ELL_WARNING);
\r
387 bool CIrrDeviceLinux::createWindow()
\r
389 #ifdef _IRR_COMPILE_WITH_X11_
\r
391 os::Printer::log("Creating X window...", ELL_INFORMATION);
\r
392 XSetErrorHandler(IrrPrintXError);
\r
395 XDisplay = XOpenDisplay(0);
\r
398 os::Printer::log("Error: Need running XServer to start Irrlicht Engine.", ELL_ERROR);
\r
399 if (XDisplayName(0)[0])
\r
400 os::Printer::log("Could not open display", XDisplayName(0), ELL_ERROR);
\r
402 os::Printer::log("Could not open display, set DISPLAY variable", ELL_ERROR);
\r
406 Screennr = DefaultScreen(XDisplay);
\r
408 switchToFullscreen();
\r
410 #if defined(_IRR_COMPILE_WITH_OPENGL_)
\r
411 // don't use the XVisual with OpenGL, because it ignores all requested
\r
412 // properties of the CreationParams
\r
413 if (CreationParams.DriverType == video::EDT_OPENGL)
\r
415 video::SExposedVideoData data;
\r
416 data.OpenGLLinux.X11Display = XDisplay;
\r
417 ContextManager = new video::CGLXManager(CreationParams, data, Screennr);
\r
418 VisualInfo = ((video::CGLXManager*)ContextManager)->getVisual();
\r
424 // create visual with standard X methods
\r
425 os::Printer::log("Using plain X visual");
\r
426 XVisualInfo visTempl; //Template to hold requested values
\r
427 int visNumber; // Return value of available visuals
\r
429 visTempl.screen = Screennr;
\r
430 // ARGB visuals should be avoided for usual applications
\r
431 visTempl.depth = CreationParams.WithAlphaChannel?32:24;
\r
432 while ((!VisualInfo) && (visTempl.depth>=16))
\r
434 VisualInfo = XGetVisualInfo(XDisplay, VisualScreenMask|VisualDepthMask,
\r
435 &visTempl, &visNumber);
\r
436 visTempl.depth -= 8;
\r
442 os::Printer::log("Fatal error, could not get visual.", ELL_ERROR);
\r
443 XCloseDisplay(XDisplay);
\r
449 os::Printer::log("Visual chosen: ", core::stringc(static_cast<u32>(VisualInfo->visualid)).c_str(), ELL_DEBUG);
\r
452 // create color map
\r
454 colormap = XCreateColormap(XDisplay,
\r
455 RootWindow(XDisplay, VisualInfo->screen),
\r
456 VisualInfo->visual, AllocNone);
\r
458 WndAttributes.colormap = colormap;
\r
459 WndAttributes.border_pixel = 0;
\r
460 WndAttributes.event_mask = StructureNotifyMask | FocusChangeMask | ExposureMask;
\r
461 if (!CreationParams.IgnoreInput)
\r
462 WndAttributes.event_mask |= PointerMotionMask |
\r
463 ButtonPressMask | KeyPressMask |
\r
464 ButtonReleaseMask | KeyReleaseMask;
\r
466 if (!CreationParams.WindowId)
\r
471 if (!CreationParams.Fullscreen)
\r
473 if (CreationParams.WindowPosition.X > 0)
\r
474 x = CreationParams.WindowPosition.X;
\r
475 if (CreationParams.WindowPosition.Y > 0)
\r
476 y = CreationParams.WindowPosition.Y;
\r
479 // create new Window
\r
480 // Remove window manager decoration in fullscreen
\r
481 WndAttributes.override_redirect = CreationParams.Fullscreen;
\r
482 XWindow = XCreateWindow(XDisplay,
\r
483 RootWindow(XDisplay, VisualInfo->screen),
\r
484 x, y, Width, Height, 0, VisualInfo->depth,
\r
485 InputOutput, VisualInfo->visual,
\r
486 CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect,
\r
489 XMapRaised(XDisplay, XWindow);
\r
490 CreationParams.WindowId = (void*)XWindow;
\r
491 X_ATOM_WM_DELETE_WINDOW = XInternAtom(XDisplay, "WM_DELETE_WINDOW", True);
\r
492 XSetWMProtocols(XDisplay, XWindow, &X_ATOM_WM_DELETE_WINDOW, 1);
\r
493 if (CreationParams.Fullscreen)
\r
495 XSetInputFocus(XDisplay, XWindow, RevertToParent, CurrentTime);
\r
496 int grabKb = XGrabKeyboard(XDisplay, XWindow, True, GrabModeAsync,
\r
497 GrabModeAsync, CurrentTime);
\r
498 IrrPrintXGrabError(grabKb, "XGrabKeyboard");
\r
499 int grabPointer = XGrabPointer(XDisplay, XWindow, True, ButtonPressMask,
\r
500 GrabModeAsync, GrabModeAsync, XWindow, None, CurrentTime);
\r
501 IrrPrintXGrabError(grabPointer, "XGrabPointer");
\r
502 XWarpPointer(XDisplay, None, XWindow, 0, 0, 0, 0, 0, 0);
\r
504 else if (CreationParams.WindowPosition.X >= 0 || CreationParams.WindowPosition.Y >= 0) // default is -1, -1
\r
506 // Window managers are free to ignore positions above, so give it another shot
\r
507 XMoveWindow(XDisplay,XWindow,x,y);
\r
512 // attach external window
\r
513 XWindow = (Window)CreationParams.WindowId;
\r
514 if (!CreationParams.IgnoreInput)
\r
516 XCreateWindow(XDisplay,
\r
518 0, 0, Width, Height, 0, VisualInfo->depth,
\r
519 InputOutput, VisualInfo->visual,
\r
520 CWBorderPixel | CWColormap | CWEventMask,
\r
523 XWindowAttributes wa;
\r
524 XGetWindowAttributes(XDisplay, XWindow, &wa);
\r
525 CreationParams.WindowSize.Width = wa.width;
\r
526 CreationParams.WindowSize.Height = wa.height;
\r
527 CreationParams.Fullscreen = false;
\r
528 ExternalWindow = true;
\r
531 WindowMinimized=false;
\r
532 // Currently broken in X, see Bug ID 2795321
\r
533 // XkbSetDetectableAutoRepeat(XDisplay, True, &AutorepeatSupport);
\r
540 XGetGeometry(XDisplay, XWindow, &tmp, &x, &y, &Width, &Height, &borderWidth, &bits);
\r
541 CreationParams.Bits = bits;
\r
542 CreationParams.WindowSize.Width = Width;
\r
543 CreationParams.WindowSize.Height = Height;
\r
545 StdHints = XAllocSizeHints();
\r
547 XGetWMNormalHints(XDisplay, XWindow, StdHints, &num);
\r
549 // create an XImage for the software renderer
\r
550 //(thx to Nadav for some clues on how to do that!)
\r
552 if (CreationParams.DriverType == video::EDT_SOFTWARE || CreationParams.DriverType == video::EDT_BURNINGSVIDEO)
\r
554 SoftwareImage = XCreateImage(XDisplay,
\r
555 VisualInfo->visual, VisualInfo->depth,
\r
556 ZPixmap, 0, 0, Width, Height,
\r
557 BitmapPad(XDisplay), 0);
\r
559 // use malloc because X will free it later on
\r
561 SoftwareImage->data = (char*) malloc(SoftwareImage->bytes_per_line * SoftwareImage->height * sizeof(char));
\r
566 // check netwm support
\r
567 Atom WMCheck = XInternAtom(XDisplay, "_NET_SUPPORTING_WM_CHECK", true);
\r
568 if (WMCheck != None)
\r
571 #endif // #ifdef _IRR_COMPILE_WITH_X11_
\r
576 //! create the driver
\r
577 void CIrrDeviceLinux::createDriver()
\r
579 switch(CreationParams.DriverType)
\r
581 #ifdef _IRR_COMPILE_WITH_X11_
\r
582 case video::EDT_SOFTWARE:
\r
583 #ifdef _IRR_COMPILE_WITH_SOFTWARE_
\r
584 VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);
\r
586 os::Printer::log("No Software driver support compiled in.", ELL_ERROR);
\r
589 case video::EDT_BURNINGSVIDEO:
\r
590 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r
591 VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);
\r
593 os::Printer::log("Burning's video driver was not compiled in.", ELL_ERROR);
\r
596 case video::EDT_OPENGL:
\r
597 #ifdef _IRR_COMPILE_WITH_OPENGL_
\r
599 video::SExposedVideoData data;
\r
600 data.OpenGLLinux.X11Window = XWindow;
\r
601 data.OpenGLLinux.X11Display = XDisplay;
\r
603 ContextManager->initialize(CreationParams, data);
\r
605 VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager);
\r
608 os::Printer::log("No OpenGL support compiled in.", ELL_ERROR);
\r
611 case video::EDT_OGLES1:
\r
612 #ifdef _IRR_COMPILE_WITH_OGLES1_
\r
614 video::SExposedVideoData data;
\r
615 data.OpenGLLinux.X11Window = XWindow;
\r
616 data.OpenGLLinux.X11Display = XDisplay;
\r
618 ContextManager = new video::CEGLManager();
\r
619 ContextManager->initialize(CreationParams, data);
\r
621 VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager);
\r
624 os::Printer::log("No OpenGL-ES1 support compiled in.", ELL_ERROR);
\r
627 case video::EDT_OGLES2:
\r
628 #ifdef _IRR_COMPILE_WITH_OGLES2_
\r
630 video::SExposedVideoData data;
\r
631 data.OpenGLLinux.X11Window = XWindow;
\r
632 data.OpenGLLinux.X11Display = XDisplay;
\r
634 ContextManager = new video::CEGLManager();
\r
635 ContextManager->initialize(CreationParams, data);
\r
637 VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager);
\r
640 os::Printer::log("No OpenGL-ES2 support compiled in.", ELL_ERROR);
\r
643 case video::EDT_WEBGL1:
\r
644 #ifdef _IRR_COMPILE_WITH_WEBGL1_
\r
646 video::SExposedVideoData data;
\r
647 data.OpenGLLinux.X11Window = XWindow;
\r
648 data.OpenGLLinux.X11Display = XDisplay;
\r
650 ContextManager = new video::CEGLManager();
\r
651 ContextManager->initialize(CreationParams, data);
\r
653 VideoDriver = video::createWebGL1Driver(CreationParams, FileSystem, ContextManager);
\r
656 os::Printer::log("No WebGL1 support compiled in.", ELL_ERROR);
\r
659 case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS:
\r
660 case video::EDT_DIRECT3D9:
\r
661 os::Printer::log("This driver is not available in Linux. Try OpenGL or Software renderer.",
\r
664 case video::EDT_NULL:
\r
665 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
\r
668 os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
\r
671 case video::EDT_NULL:
\r
672 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
\r
675 os::Printer::log("No X11 support compiled in. Only Null driver available.", ELL_ERROR);
\r
681 #ifdef _IRR_COMPILE_WITH_X11_
\r
682 bool CIrrDeviceLinux::createInputContext()
\r
684 // One one side it would be nicer to let users do that - on the other hand
\r
685 // not setting the environment locale will not work when using i18n X11 functions.
\r
686 // So users would have to call it always or their input is broken badly.
\r
687 // We can restore immediately - so won't mess with anything in users apps.
\r
688 core::stringc oldLocale(setlocale(LC_CTYPE, NULL));
\r
689 setlocale(LC_CTYPE, ""); // use environment locale
\r
691 if ( !XSupportsLocale() )
\r
693 os::Printer::log("Locale not supported. Falling back to non-i18n input.", ELL_WARNING);
\r
694 setlocale(LC_CTYPE, oldLocale.c_str());
\r
698 XInputMethod = XOpenIM(XDisplay, NULL, NULL, NULL);
\r
699 if ( !XInputMethod )
\r
701 setlocale(LC_CTYPE, oldLocale.c_str());
\r
702 os::Printer::log("XOpenIM failed to create an input method. Falling back to non-i18n input.", ELL_WARNING);
\r
706 XIMStyles *im_supported_styles;
\r
707 XGetIMValues(XInputMethod, XNQueryInputStyle, &im_supported_styles, (char*)NULL);
\r
708 XIMStyle bestStyle = 0;
\r
709 // TODO: If we want to support languages like chinese or japanese as well we probably have to work with callbacks here.
\r
710 XIMStyle supportedStyle = XIMPreeditNone | XIMStatusNone;
\r
711 for(int i=0; i < im_supported_styles->count_styles; ++i)
\r
713 XIMStyle style = im_supported_styles->supported_styles[i];
\r
714 if ((style & supportedStyle) == style) /* if we can handle it */
\r
720 XFree(im_supported_styles);
\r
724 XDestroyIC(XInputContext);
\r
727 os::Printer::log("XInputMethod has no input style we can use. Falling back to non-i18n input.", ELL_WARNING);
\r
728 setlocale(LC_CTYPE, oldLocale.c_str());
\r
732 XInputContext = XCreateIC(XInputMethod,
\r
733 XNInputStyle, bestStyle,
\r
734 XNClientWindow, XWindow,
\r
736 if (!XInputContext )
\r
738 os::Printer::log("XInputContext failed to create an input context. Falling back to non-i18n input.", ELL_WARNING);
\r
739 setlocale(LC_CTYPE, oldLocale.c_str());
\r
742 XSetICFocus(XInputContext);
\r
743 setlocale(LC_CTYPE, oldLocale.c_str());
\r
747 void CIrrDeviceLinux::destroyInputContext()
\r
749 if ( XInputContext )
\r
751 XUnsetICFocus(XInputContext);
\r
752 XDestroyIC(XInputContext);
\r
755 if ( XInputMethod )
\r
757 XCloseIM(XInputMethod);
\r
762 EKEY_CODE CIrrDeviceLinux::getKeyCode(XEvent &event)
\r
764 EKEY_CODE keyCode = (EKEY_CODE)0;
\r
767 mp.X11Key = XkbKeycodeToKeysym(XDisplay, event.xkey.keycode, 0, 0);
\r
768 // mp.X11Key = XKeycodeToKeysym(XDisplay, event.xkey.keycode, 0); // deprecated, if we still find platforms which need that we have to use some define
\r
769 const s32 idx = KeyMap.binary_search(mp);
\r
772 keyCode = (EKEY_CODE)KeyMap[idx].Win32Key;
\r
776 // Any value is better than none, that allows at least using the keys.
\r
777 // Worst case is that some keys will be identical, still better than _all_
\r
778 // unknown keys being identical.
\r
781 keyCode = (EKEY_CODE)event.xkey.keycode;
\r
782 os::Printer::log("No such X11Key, using event keycode", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION);
\r
784 else if (idx == -1)
\r
786 keyCode = (EKEY_CODE)mp.X11Key;
\r
787 os::Printer::log("EKEY_CODE not found, using orig. X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION);
\r
791 keyCode = (EKEY_CODE)mp.X11Key;
\r
792 os::Printer::log("EKEY_CODE is 0, using orig. X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION);
\r
799 //! runs the device. Returns false if device wants to be deleted
\r
800 bool CIrrDeviceLinux::run()
\r
804 #ifdef _IRR_COMPILE_WITH_X11_
\r
806 if ( CursorControl )
\r
807 static_cast<CCursorControl*>(CursorControl)->update();
\r
809 if ((CreationParams.DriverType != video::EDT_NULL) && XDisplay)
\r
812 irrevent.MouseInput.ButtonStates = 0xffffffff;
\r
814 while (XPending(XDisplay) > 0 && !Close)
\r
817 XNextEvent(XDisplay, &event);
\r
819 switch (event.type)
\r
821 case ConfigureNotify:
\r
822 // check for changed window size
\r
823 if ((event.xconfigure.width != (int) Width) ||
\r
824 (event.xconfigure.height != (int) Height))
\r
826 Width = event.xconfigure.width;
\r
827 Height = event.xconfigure.height;
\r
829 // resize image data
\r
832 XDestroyImage(SoftwareImage);
\r
834 SoftwareImage = XCreateImage(XDisplay,
\r
835 VisualInfo->visual, VisualInfo->depth,
\r
836 ZPixmap, 0, 0, Width, Height,
\r
837 BitmapPad(XDisplay), 0);
\r
839 // use malloc because X will free it later on
\r
841 SoftwareImage->data = (char*) malloc(SoftwareImage->bytes_per_line * SoftwareImage->height * sizeof(char));
\r
845 VideoDriver->OnResize(core::dimension2d<u32>(Width, Height));
\r
850 WindowMinimized=false;
\r
854 WindowMinimized=true;
\r
858 WindowHasFocus=true;
\r
862 WindowHasFocus=false;
\r
866 irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;
\r
867 irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
\r
868 irrevent.MouseInput.X = event.xbutton.x;
\r
869 irrevent.MouseInput.Y = event.xbutton.y;
\r
870 irrevent.MouseInput.Control = (event.xkey.state & ControlMask) != 0;
\r
871 irrevent.MouseInput.Shift = (event.xkey.state & ShiftMask) != 0;
\r
873 // mouse button states
\r
874 irrevent.MouseInput.ButtonStates = (event.xbutton.state & Button1Mask) ? irr::EMBSM_LEFT : 0;
\r
875 irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button3Mask) ? irr::EMBSM_RIGHT : 0;
\r
876 irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button2Mask) ? irr::EMBSM_MIDDLE : 0;
\r
878 postEventFromUser(irrevent);
\r
882 case ButtonRelease:
\r
884 irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;
\r
885 irrevent.MouseInput.X = event.xbutton.x;
\r
886 irrevent.MouseInput.Y = event.xbutton.y;
\r
887 irrevent.MouseInput.Control = (event.xkey.state & ControlMask) != 0;
\r
888 irrevent.MouseInput.Shift = (event.xkey.state & ShiftMask) != 0;
\r
890 // mouse button states
\r
891 // This sets the state which the buttons had _prior_ to the event.
\r
892 // So unlike on Windows the button which just got changed has still the old state here.
\r
893 // We handle that below by flipping the corresponding bit later.
\r
894 irrevent.MouseInput.ButtonStates = (event.xbutton.state & Button1Mask) ? irr::EMBSM_LEFT : 0;
\r
895 irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button3Mask) ? irr::EMBSM_RIGHT : 0;
\r
896 irrevent.MouseInput.ButtonStates |= (event.xbutton.state & Button2Mask) ? irr::EMBSM_MIDDLE : 0;
\r
898 irrevent.MouseInput.Event = irr::EMIE_COUNT;
\r
900 switch(event.xbutton.button)
\r
903 irrevent.MouseInput.Event =
\r
904 (event.type == ButtonPress) ? irr::EMIE_LMOUSE_PRESSED_DOWN : irr::EMIE_LMOUSE_LEFT_UP;
\r
905 irrevent.MouseInput.ButtonStates ^= irr::EMBSM_LEFT;
\r
909 irrevent.MouseInput.Event =
\r
910 (event.type == ButtonPress) ? irr::EMIE_RMOUSE_PRESSED_DOWN : irr::EMIE_RMOUSE_LEFT_UP;
\r
911 irrevent.MouseInput.ButtonStates ^= irr::EMBSM_RIGHT;
\r
915 irrevent.MouseInput.Event =
\r
916 (event.type == ButtonPress) ? irr::EMIE_MMOUSE_PRESSED_DOWN : irr::EMIE_MMOUSE_LEFT_UP;
\r
917 irrevent.MouseInput.ButtonStates ^= irr::EMBSM_MIDDLE;
\r
921 if (event.type == ButtonPress)
\r
923 irrevent.MouseInput.Event = EMIE_MOUSE_WHEEL;
\r
924 irrevent.MouseInput.Wheel = 1.0f;
\r
929 if (event.type == ButtonPress)
\r
931 irrevent.MouseInput.Event = EMIE_MOUSE_WHEEL;
\r
932 irrevent.MouseInput.Wheel = -1.0f;
\r
937 if (irrevent.MouseInput.Event != irr::EMIE_COUNT)
\r
939 postEventFromUser(irrevent);
\r
941 if ( irrevent.MouseInput.Event >= EMIE_LMOUSE_PRESSED_DOWN && irrevent.MouseInput.Event <= EMIE_MMOUSE_PRESSED_DOWN )
\r
943 u32 clicks = checkSuccessiveClicks(irrevent.MouseInput.X, irrevent.MouseInput.Y, irrevent.MouseInput.Event);
\r
946 irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_DOUBLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN);
\r
947 postEventFromUser(irrevent);
\r
949 else if ( clicks == 3 )
\r
951 irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_TRIPLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN);
\r
952 postEventFromUser(irrevent);
\r
958 case MappingNotify:
\r
959 XRefreshKeyboardMapping (&event.xmapping) ;
\r
963 if (0 == AutorepeatSupport && (XPending( XDisplay ) > 0) )
\r
965 // check for Autorepeat manually
\r
966 // We'll do the same as Windows does: Only send KeyPressed
\r
967 // So every KeyRelease is a real release
\r
969 XPeekEvent (event.xkey.display, &next_event);
\r
970 if ((next_event.type == KeyPress) &&
\r
971 (next_event.xkey.keycode == event.xkey.keycode) &&
\r
972 (next_event.xkey.time - event.xkey.time) < 2) // usually same time, but on some systems a difference of 1 is possible
\r
974 // Ignore the key release event
\r
979 irrevent.EventType = irr::EET_KEY_INPUT_EVENT;
\r
980 irrevent.KeyInput.PressedDown = false;
\r
981 irrevent.KeyInput.Char = 0; // on release that's undefined
\r
982 irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0;
\r
983 irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0;
\r
984 irrevent.KeyInput.Key = getKeyCode(event);
\r
986 postEventFromUser(irrevent);
\r
992 if ( XInputContext )
\r
994 wchar_t buf[8]={0};
\r
996 int strLen = XwcLookupString(XInputContext, &event.xkey, buf, sizeof(buf), &mp.X11Key, &status);
\r
997 if ( status == XBufferOverflow )
\r
999 os::Printer::log("XwcLookupString needs a larger buffer", ELL_INFORMATION);
\r
1001 if ( strLen > 0 && (status == XLookupChars || status == XLookupBoth) )
\r
1004 os::Printer::log("Additional returned characters dropped", ELL_INFORMATION);
\r
1005 irrevent.KeyInput.Char = buf[0];
\r
1009 #if 0 // Most of those are fine - but useful to have the info when debugging Irrlicht itself.
\r
1010 if ( status == XLookupNone )
\r
1011 os::Printer::log("XLookupNone", ELL_INFORMATION);
\r
1012 else if ( status == XLookupKeySym )
\r
1013 // Getting this also when user did not set setlocale(LC_ALL, ""); and using an unknown locale
\r
1014 // XSupportsLocale doesn't seeem to catch that unfortunately - any other ideas to catch it are welcome.
\r
1015 os::Printer::log("XLookupKeySym", ELL_INFORMATION);
\r
1016 else if ( status == XBufferOverflow )
\r
1017 os::Printer::log("XBufferOverflow", ELL_INFORMATION);
\r
1018 else if ( strLen == 0 )
\r
1019 os::Printer::log("no string", ELL_INFORMATION);
\r
1021 irrevent.KeyInput.Char = 0;
\r
1024 else // Old version without InputContext. Does not support i18n, but good to have as fallback.
\r
1031 XLookupString(&event.xkey, tmp.buf, sizeof(tmp.buf), &mp.X11Key, NULL);
\r
1032 irrevent.KeyInput.Char = tmp.wbuf[0];
\r
1035 irrevent.EventType = irr::EET_KEY_INPUT_EVENT;
\r
1036 irrevent.KeyInput.PressedDown = true;
\r
1037 irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0;
\r
1038 irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0;
\r
1039 irrevent.KeyInput.Key = getKeyCode(event);
\r
1041 postEventFromUser(irrevent);
\r
1045 case ClientMessage:
\r
1047 if (static_cast<Atom>(event.xclient.data.l[0]) == X_ATOM_WM_DELETE_WINDOW && X_ATOM_WM_DELETE_WINDOW != None)
\r
1049 os::Printer::log("Quit message received.", ELL_INFORMATION);
\r
1054 // we assume it's a user message
\r
1055 irrevent.EventType = irr::EET_USER_EVENT;
\r
1056 irrevent.UserEvent.UserData1 = static_cast<size_t>(event.xclient.data.l[0]);
\r
1057 irrevent.UserEvent.UserData2 = static_cast<size_t>(event.xclient.data.l[1]);
\r
1058 postEventFromUser(irrevent);
\r
1063 case SelectionRequest:
\r
1066 XSelectionRequestEvent *req = &(event.xselectionrequest);
\r
1067 if ( req->target == XA_STRING)
\r
1069 XChangeProperty (XDisplay,
\r
1071 req->property, req->target,
\r
1074 (unsigned char*) Clipboard.c_str(),
\r
1075 Clipboard.size());
\r
1076 respond.xselection.property = req->property;
\r
1078 else if ( req->target == X_ATOM_TARGETS )
\r
1082 data[0] = X_ATOM_TEXT;
\r
1083 data[1] = XA_STRING;
\r
1085 XChangeProperty (XDisplay, req->requestor,
\r
1086 req->property, req->target,
\r
1087 8, PropModeReplace,
\r
1088 (unsigned char *) &data,
\r
1090 respond.xselection.property = req->property;
\r
1094 respond.xselection.property= None;
\r
1096 respond.xselection.type= SelectionNotify;
\r
1097 respond.xselection.display= req->display;
\r
1098 respond.xselection.requestor= req->requestor;
\r
1099 respond.xselection.selection=req->selection;
\r
1100 respond.xselection.target= req->target;
\r
1101 respond.xselection.time = req->time;
\r
1102 XSendEvent (XDisplay, req->requestor,0,0,&respond);
\r
1103 XFlush (XDisplay);
\r
1113 #endif //_IRR_COMPILE_WITH_X11_
\r
1122 //! Pause the current process for the minimum time allowed only to allow other processes to execute
\r
1123 void CIrrDeviceLinux::yield()
\r
1125 struct timespec ts = {0,1};
\r
1126 nanosleep(&ts, NULL);
\r
1130 //! Pause execution and let other processes to run for a specified amount of time.
\r
1131 void CIrrDeviceLinux::sleep(u32 timeMs, bool pauseTimer=false)
\r
1133 const bool wasStopped = Timer ? Timer->isStopped() : true;
\r
1135 struct timespec ts;
\r
1136 ts.tv_sec = (time_t) (timeMs / 1000);
\r
1137 ts.tv_nsec = (long) (timeMs % 1000) * 1000000;
\r
1139 if (pauseTimer && !wasStopped)
\r
1142 nanosleep(&ts, NULL);
\r
1144 if (pauseTimer && !wasStopped)
\r
1149 //! sets the caption of the window
\r
1150 void CIrrDeviceLinux::setWindowCaption(const wchar_t* text)
\r
1152 #ifdef _IRR_COMPILE_WITH_X11_
\r
1153 if (CreationParams.DriverType == video::EDT_NULL)
\r
1156 XTextProperty txt;
\r
1157 if (Success==XwcTextListToTextProperty(XDisplay, const_cast<wchar_t**>(&text),
\r
1158 1, XStdICCTextStyle, &txt))
\r
1160 XSetWMName(XDisplay, XWindow, &txt);
\r
1161 XSetWMIconName(XDisplay, XWindow, &txt);
\r
1168 //! presents a surface in the client area
\r
1169 bool CIrrDeviceLinux::present(video::IImage* image, void* windowId, core::rect<s32>* srcRect)
\r
1171 #ifdef _IRR_COMPILE_WITH_X11_
\r
1172 // this is only necessary for software drivers.
\r
1173 if (!SoftwareImage)
\r
1176 // thx to Nadav, who send me some clues of how to display the image
\r
1177 // to the X Server.
\r
1179 const u32 destwidth = SoftwareImage->width;
\r
1180 const u32 minWidth = core::min_(image->getDimension().Width, destwidth);
\r
1181 const u32 destPitch = SoftwareImage->bytes_per_line;
\r
1183 video::ECOLOR_FORMAT destColor;
\r
1184 switch (SoftwareImage->bits_per_pixel)
\r
1187 if (SoftwareImage->depth==16)
\r
1188 destColor = video::ECF_R5G6B5;
\r
1190 destColor = video::ECF_A1R5G5B5;
\r
1192 case 24: destColor = video::ECF_R8G8B8; break;
\r
1193 case 32: destColor = video::ECF_A8R8G8B8; break;
\r
1195 os::Printer::log("Unsupported screen depth.");
\r
1199 u8* srcdata = reinterpret_cast<u8*>(image->getData());
\r
1200 u8* destData = reinterpret_cast<u8*>(SoftwareImage->data);
\r
1202 const u32 destheight = SoftwareImage->height;
\r
1203 const u32 srcheight = core::min_(image->getDimension().Height, destheight);
\r
1204 const u32 srcPitch = image->getPitch();
\r
1205 for (u32 y=0; y!=srcheight; ++y)
\r
1207 video::CColorConverter::convert_viaFormat(srcdata,image->getColorFormat(), minWidth, destData, destColor);
\r
1208 srcdata+=srcPitch;
\r
1209 destData+=destPitch;
\r
1212 GC gc = DefaultGC(XDisplay, DefaultScreen(XDisplay));
\r
1213 Window myWindow=XWindow;
\r
1215 myWindow = reinterpret_cast<Window>(windowId);
\r
1216 XPutImage(XDisplay, myWindow, gc, SoftwareImage, 0, 0, 0, 0, destwidth, destheight);
\r
1222 //! notifies the device that it should close itself
\r
1223 void CIrrDeviceLinux::closeDevice()
\r
1229 //! returns if window is active. if not, nothing need to be drawn
\r
1230 bool CIrrDeviceLinux::isWindowActive() const
\r
1232 return (WindowHasFocus && !WindowMinimized);
\r
1236 //! returns if window has focus.
\r
1237 bool CIrrDeviceLinux::isWindowFocused() const
\r
1239 return WindowHasFocus;
\r
1243 //! returns if window is minimized.
\r
1244 bool CIrrDeviceLinux::isWindowMinimized() const
\r
1246 return WindowMinimized;
\r
1250 //! returns color format of the window.
\r
1251 video::ECOLOR_FORMAT CIrrDeviceLinux::getColorFormat() const
\r
1253 #ifdef _IRR_COMPILE_WITH_X11_
\r
1254 if (VisualInfo && (VisualInfo->depth != 16))
\r
1255 return video::ECF_R8G8B8;
\r
1258 return video::ECF_R5G6B5;
\r
1262 //! Sets if the window should be resizable in windowed mode.
\r
1263 void CIrrDeviceLinux::setResizable(bool resize)
\r
1265 #ifdef _IRR_COMPILE_WITH_X11_
\r
1266 if (CreationParams.DriverType == video::EDT_NULL || CreationParams.Fullscreen )
\r
1271 // Must be heap memory because data size depends on X Server
\r
1272 XSizeHints *hints = XAllocSizeHints();
\r
1273 hints->flags=PSize|PMinSize|PMaxSize;
\r
1274 hints->min_width=hints->max_width=hints->base_width=Width;
\r
1275 hints->min_height=hints->max_height=hints->base_height=Height;
\r
1276 XSetWMNormalHints(XDisplay, XWindow, hints);
\r
1281 XSetWMNormalHints(XDisplay, XWindow, StdHints);
\r
1284 #endif // #ifdef _IRR_COMPILE_WITH_X11_
\r
1287 //! Resize the render window.
\r
1288 void CIrrDeviceLinux::setWindowSize(const irr::core::dimension2d<u32>& size)
\r
1290 #ifdef _IRR_COMPILE_WITH_X11_
\r
1291 if (CreationParams.DriverType == video::EDT_NULL || CreationParams.Fullscreen )
\r
1294 XWindowChanges values;
\r
1295 values.width = size.Width;
\r
1296 values.height = size.Height;
\r
1297 XConfigureWindow(XDisplay, XWindow, CWWidth | CWHeight, &values);
\r
1299 #endif // #ifdef _IRR_COMPILE_WITH_X11_
\r
1302 //! Return pointer to a list with all video modes supported by the gfx adapter.
\r
1303 video::IVideoModeList* CIrrDeviceLinux::getVideoModeList()
\r
1305 #ifdef _IRR_COMPILE_WITH_X11_
\r
1306 if (!VideoModeList->getVideoModeCount())
\r
1308 bool temporaryDisplay = false;
\r
1312 XDisplay = XOpenDisplay(0);
\r
1313 temporaryDisplay=true;
\r
1317 #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)
\r
1318 s32 eventbase, errorbase;
\r
1319 s32 defaultDepth=DefaultDepth(XDisplay,Screennr);
\r
1322 #ifdef _IRR_LINUX_X11_VIDMODE_
\r
1323 if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase))
\r
1325 // enumerate video modes
\r
1327 XF86VidModeModeInfo** modes;
\r
1329 XF86VidModeGetAllModeLines(XDisplay, Screennr, &modeCount, &modes);
\r
1331 // save current video mode
\r
1332 OldVideoMode = *modes[0];
\r
1334 // find fitting mode
\r
1336 VideoModeList->setDesktop(defaultDepth, core::dimension2d<u32>(
\r
1337 modes[0]->hdisplay, modes[0]->vdisplay));
\r
1338 for (int i = 0; i<modeCount; ++i)
\r
1340 VideoModeList->addMode(core::dimension2d<u32>(
\r
1341 modes[i]->hdisplay, modes[i]->vdisplay), defaultDepth);
\r
1347 #ifdef _IRR_LINUX_X11_RANDR_
\r
1348 if (XRRQueryExtension(XDisplay, &eventbase, &errorbase))
\r
1351 XRRScreenConfiguration *config=XRRGetScreenInfo(XDisplay,DefaultRootWindow(XDisplay));
\r
1352 OldRandrMode=XRRConfigCurrentConfiguration(config,&OldRandrRotation);
\r
1353 XRRScreenSize *modes=XRRConfigSizes(config,&modeCount);
\r
1354 VideoModeList->setDesktop(defaultDepth, core::dimension2d<u32>(
\r
1355 modes[OldRandrMode].width, modes[OldRandrMode].height));
\r
1356 for (int i = 0; i<modeCount; ++i)
\r
1358 VideoModeList->addMode(core::dimension2d<u32>(
\r
1359 modes[i].width, modes[i].height), defaultDepth);
\r
1361 XRRFreeScreenConfigInfo(config);
\r
1366 os::Printer::log("VidMode or RandR X11 extension requireed for VideoModeList." , ELL_WARNING);
\r
1369 if (XDisplay && temporaryDisplay)
\r
1371 XCloseDisplay(XDisplay);
\r
1377 return VideoModeList;
\r
1381 //! Minimize window
\r
1382 void CIrrDeviceLinux::minimizeWindow()
\r
1384 #ifdef _IRR_COMPILE_WITH_X11_
\r
1385 XIconifyWindow(XDisplay, XWindow, Screennr);
\r
1390 //! Maximize window
\r
1391 void CIrrDeviceLinux::maximizeWindow()
\r
1393 #ifdef _IRR_COMPILE_WITH_X11_
\r
1394 // Maximize is not implemented in bare X, it's a WM construct.
\r
1399 ev.type = ClientMessage;
\r
1400 ev.xclient.window = XWindow;
\r
1401 ev.xclient.message_type = X_ATOM_NETWM_STATE;
\r
1402 ev.xclient.format = 32;
\r
1403 ev.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD
\r
1404 ev.xclient.data.l[1] = X_ATOM_NETWM_MAXIMIZE_VERT;
\r
1405 ev.xclient.data.l[2] = X_ATOM_NETWM_MAXIMIZE_HORZ;
\r
1407 XSendEvent(XDisplay, DefaultRootWindow(XDisplay), false,
\r
1408 SubstructureNotifyMask|SubstructureRedirectMask, &ev);
\r
1411 XMapWindow(XDisplay, XWindow);
\r
1416 //! Restore original window size
\r
1417 void CIrrDeviceLinux::restoreWindow()
\r
1419 #ifdef _IRR_COMPILE_WITH_X11_
\r
1420 // Maximize is not implemented in bare X, it's a WM construct.
\r
1425 ev.type = ClientMessage;
\r
1426 ev.xclient.window = XWindow;
\r
1427 ev.xclient.message_type = X_ATOM_NETWM_STATE;
\r
1428 ev.xclient.format = 32;
\r
1429 ev.xclient.data.l[0] = 0; // _NET_WM_STATE_REMOVE
\r
1430 ev.xclient.data.l[1] = X_ATOM_NETWM_MAXIMIZE_VERT;
\r
1431 ev.xclient.data.l[2] = X_ATOM_NETWM_MAXIMIZE_HORZ;
\r
1433 XSendEvent(XDisplay, DefaultRootWindow(XDisplay), false,
\r
1434 SubstructureNotifyMask|SubstructureRedirectMask, &ev);
\r
1437 XMapWindow(XDisplay, XWindow);
\r
1441 core::position2di CIrrDeviceLinux::getWindowPosition()
\r
1443 int wx = 0, wy = 0;
\r
1444 #ifdef _IRR_COMPILE_WITH_X11_
\r
1446 XTranslateCoordinates(XDisplay, XWindow, DefaultRootWindow(XDisplay), 0, 0, &wx, &wy, &child);
\r
1448 return core::position2di(wx, wy);
\r
1451 void CIrrDeviceLinux::createKeyMap()
\r
1453 // I don't know if this is the best method to create
\r
1454 // the lookuptable, but I'll leave it like that until
\r
1455 // I find a better version.
\r
1456 // Search for missing numbers in keysymdef.h
\r
1458 #ifdef _IRR_COMPILE_WITH_X11_
\r
1459 KeyMap.reallocate(190);
\r
1460 KeyMap.push_back(SKeyMap(XK_BackSpace, KEY_BACK));
\r
1461 KeyMap.push_back(SKeyMap(XK_Tab, KEY_TAB));
\r
1462 KeyMap.push_back(SKeyMap(XK_ISO_Left_Tab, KEY_TAB));
\r
1463 KeyMap.push_back(SKeyMap(XK_Linefeed, 0)); // ???
\r
1464 KeyMap.push_back(SKeyMap(XK_Clear, KEY_CLEAR));
\r
1465 KeyMap.push_back(SKeyMap(XK_Return, KEY_RETURN));
\r
1466 KeyMap.push_back(SKeyMap(XK_Pause, KEY_PAUSE));
\r
1467 KeyMap.push_back(SKeyMap(XK_Scroll_Lock, KEY_SCROLL));
\r
1468 KeyMap.push_back(SKeyMap(XK_Sys_Req, 0)); // ???
\r
1469 KeyMap.push_back(SKeyMap(XK_Escape, KEY_ESCAPE));
\r
1470 KeyMap.push_back(SKeyMap(XK_Insert, KEY_INSERT));
\r
1471 KeyMap.push_back(SKeyMap(XK_Delete, KEY_DELETE));
\r
1472 KeyMap.push_back(SKeyMap(XK_Home, KEY_HOME));
\r
1473 KeyMap.push_back(SKeyMap(XK_Left, KEY_LEFT));
\r
1474 KeyMap.push_back(SKeyMap(XK_Up, KEY_UP));
\r
1475 KeyMap.push_back(SKeyMap(XK_Right, KEY_RIGHT));
\r
1476 KeyMap.push_back(SKeyMap(XK_Down, KEY_DOWN));
\r
1477 KeyMap.push_back(SKeyMap(XK_Prior, KEY_PRIOR));
\r
1478 KeyMap.push_back(SKeyMap(XK_Page_Up, KEY_PRIOR));
\r
1479 KeyMap.push_back(SKeyMap(XK_Next, KEY_NEXT));
\r
1480 KeyMap.push_back(SKeyMap(XK_Page_Down, KEY_NEXT));
\r
1481 KeyMap.push_back(SKeyMap(XK_End, KEY_END));
\r
1482 KeyMap.push_back(SKeyMap(XK_Begin, KEY_HOME));
\r
1483 KeyMap.push_back(SKeyMap(XK_Num_Lock, KEY_NUMLOCK));
\r
1484 KeyMap.push_back(SKeyMap(XK_KP_Space, KEY_SPACE));
\r
1485 KeyMap.push_back(SKeyMap(XK_KP_Tab, KEY_TAB));
\r
1486 KeyMap.push_back(SKeyMap(XK_KP_Enter, KEY_RETURN));
\r
1487 KeyMap.push_back(SKeyMap(XK_KP_F1, KEY_F1));
\r
1488 KeyMap.push_back(SKeyMap(XK_KP_F2, KEY_F2));
\r
1489 KeyMap.push_back(SKeyMap(XK_KP_F3, KEY_F3));
\r
1490 KeyMap.push_back(SKeyMap(XK_KP_F4, KEY_F4));
\r
1491 KeyMap.push_back(SKeyMap(XK_KP_Home, KEY_HOME));
\r
1492 KeyMap.push_back(SKeyMap(XK_KP_Left, KEY_LEFT));
\r
1493 KeyMap.push_back(SKeyMap(XK_KP_Up, KEY_UP));
\r
1494 KeyMap.push_back(SKeyMap(XK_KP_Right, KEY_RIGHT));
\r
1495 KeyMap.push_back(SKeyMap(XK_KP_Down, KEY_DOWN));
\r
1496 KeyMap.push_back(SKeyMap(XK_Print, KEY_PRINT));
\r
1497 KeyMap.push_back(SKeyMap(XK_KP_Prior, KEY_PRIOR));
\r
1498 KeyMap.push_back(SKeyMap(XK_KP_Page_Up, KEY_PRIOR));
\r
1499 KeyMap.push_back(SKeyMap(XK_KP_Next, KEY_NEXT));
\r
1500 KeyMap.push_back(SKeyMap(XK_KP_Page_Down, KEY_NEXT));
\r
1501 KeyMap.push_back(SKeyMap(XK_KP_End, KEY_END));
\r
1502 KeyMap.push_back(SKeyMap(XK_KP_Begin, KEY_HOME));
\r
1503 KeyMap.push_back(SKeyMap(XK_KP_Insert, KEY_INSERT));
\r
1504 KeyMap.push_back(SKeyMap(XK_KP_Delete, KEY_DELETE));
\r
1505 KeyMap.push_back(SKeyMap(XK_KP_Equal, 0)); // ???
\r
1506 KeyMap.push_back(SKeyMap(XK_KP_Multiply, KEY_MULTIPLY));
\r
1507 KeyMap.push_back(SKeyMap(XK_KP_Add, KEY_ADD));
\r
1508 KeyMap.push_back(SKeyMap(XK_KP_Separator, KEY_SEPARATOR));
\r
1509 KeyMap.push_back(SKeyMap(XK_KP_Subtract, KEY_SUBTRACT));
\r
1510 KeyMap.push_back(SKeyMap(XK_KP_Decimal, KEY_DECIMAL));
\r
1511 KeyMap.push_back(SKeyMap(XK_KP_Divide, KEY_DIVIDE));
\r
1512 KeyMap.push_back(SKeyMap(XK_KP_0, KEY_NUMPAD0));
\r
1513 KeyMap.push_back(SKeyMap(XK_KP_1, KEY_NUMPAD1));
\r
1514 KeyMap.push_back(SKeyMap(XK_KP_2, KEY_NUMPAD2));
\r
1515 KeyMap.push_back(SKeyMap(XK_KP_3, KEY_NUMPAD3));
\r
1516 KeyMap.push_back(SKeyMap(XK_KP_4, KEY_NUMPAD4));
\r
1517 KeyMap.push_back(SKeyMap(XK_KP_5, KEY_NUMPAD5));
\r
1518 KeyMap.push_back(SKeyMap(XK_KP_6, KEY_NUMPAD6));
\r
1519 KeyMap.push_back(SKeyMap(XK_KP_7, KEY_NUMPAD7));
\r
1520 KeyMap.push_back(SKeyMap(XK_KP_8, KEY_NUMPAD8));
\r
1521 KeyMap.push_back(SKeyMap(XK_KP_9, KEY_NUMPAD9));
\r
1522 KeyMap.push_back(SKeyMap(XK_F1, KEY_F1));
\r
1523 KeyMap.push_back(SKeyMap(XK_F2, KEY_F2));
\r
1524 KeyMap.push_back(SKeyMap(XK_F3, KEY_F3));
\r
1525 KeyMap.push_back(SKeyMap(XK_F4, KEY_F4));
\r
1526 KeyMap.push_back(SKeyMap(XK_F5, KEY_F5));
\r
1527 KeyMap.push_back(SKeyMap(XK_F6, KEY_F6));
\r
1528 KeyMap.push_back(SKeyMap(XK_F7, KEY_F7));
\r
1529 KeyMap.push_back(SKeyMap(XK_F8, KEY_F8));
\r
1530 KeyMap.push_back(SKeyMap(XK_F9, KEY_F9));
\r
1531 KeyMap.push_back(SKeyMap(XK_F10, KEY_F10));
\r
1532 KeyMap.push_back(SKeyMap(XK_F11, KEY_F11));
\r
1533 KeyMap.push_back(SKeyMap(XK_F12, KEY_F12));
\r
1534 KeyMap.push_back(SKeyMap(XK_Shift_L, KEY_LSHIFT));
\r
1535 KeyMap.push_back(SKeyMap(XK_Shift_R, KEY_RSHIFT));
\r
1536 KeyMap.push_back(SKeyMap(XK_Control_L, KEY_LCONTROL));
\r
1537 KeyMap.push_back(SKeyMap(XK_Control_R, KEY_RCONTROL));
\r
1538 KeyMap.push_back(SKeyMap(XK_Caps_Lock, KEY_CAPITAL));
\r
1539 KeyMap.push_back(SKeyMap(XK_Shift_Lock, KEY_CAPITAL));
\r
1540 KeyMap.push_back(SKeyMap(XK_Meta_L, KEY_LWIN));
\r
1541 KeyMap.push_back(SKeyMap(XK_Meta_R, KEY_RWIN));
\r
1542 KeyMap.push_back(SKeyMap(XK_Alt_L, KEY_LMENU));
\r
1543 KeyMap.push_back(SKeyMap(XK_Alt_R, KEY_RMENU));
\r
1544 KeyMap.push_back(SKeyMap(XK_ISO_Level3_Shift, KEY_RMENU));
\r
1545 KeyMap.push_back(SKeyMap(XK_Menu, KEY_MENU));
\r
1546 KeyMap.push_back(SKeyMap(XK_space, KEY_SPACE));
\r
1547 KeyMap.push_back(SKeyMap(XK_exclam, 0)); //?
\r
1548 KeyMap.push_back(SKeyMap(XK_quotedbl, 0)); //?
\r
1549 KeyMap.push_back(SKeyMap(XK_section, 0)); //?
\r
1550 KeyMap.push_back(SKeyMap(XK_numbersign, KEY_OEM_2));
\r
1551 KeyMap.push_back(SKeyMap(XK_dollar, 0)); //?
\r
1552 KeyMap.push_back(SKeyMap(XK_percent, 0)); //?
\r
1553 KeyMap.push_back(SKeyMap(XK_ampersand, 0)); //?
\r
1554 KeyMap.push_back(SKeyMap(XK_apostrophe, KEY_OEM_7));
\r
1555 KeyMap.push_back(SKeyMap(XK_parenleft, 0)); //?
\r
1556 KeyMap.push_back(SKeyMap(XK_parenright, 0)); //?
\r
1557 KeyMap.push_back(SKeyMap(XK_asterisk, 0)); //?
\r
1558 KeyMap.push_back(SKeyMap(XK_plus, KEY_PLUS)); //?
\r
1559 KeyMap.push_back(SKeyMap(XK_comma, KEY_COMMA)); //?
\r
1560 KeyMap.push_back(SKeyMap(XK_minus, KEY_MINUS)); //?
\r
1561 KeyMap.push_back(SKeyMap(XK_period, KEY_PERIOD)); //?
\r
1562 KeyMap.push_back(SKeyMap(XK_slash, KEY_OEM_2)); //?
\r
1563 KeyMap.push_back(SKeyMap(XK_0, KEY_KEY_0));
\r
1564 KeyMap.push_back(SKeyMap(XK_1, KEY_KEY_1));
\r
1565 KeyMap.push_back(SKeyMap(XK_2, KEY_KEY_2));
\r
1566 KeyMap.push_back(SKeyMap(XK_3, KEY_KEY_3));
\r
1567 KeyMap.push_back(SKeyMap(XK_4, KEY_KEY_4));
\r
1568 KeyMap.push_back(SKeyMap(XK_5, KEY_KEY_5));
\r
1569 KeyMap.push_back(SKeyMap(XK_6, KEY_KEY_6));
\r
1570 KeyMap.push_back(SKeyMap(XK_7, KEY_KEY_7));
\r
1571 KeyMap.push_back(SKeyMap(XK_8, KEY_KEY_8));
\r
1572 KeyMap.push_back(SKeyMap(XK_9, KEY_KEY_9));
\r
1573 KeyMap.push_back(SKeyMap(XK_colon, 0)); //?
\r
1574 KeyMap.push_back(SKeyMap(XK_semicolon, KEY_OEM_1));
\r
1575 KeyMap.push_back(SKeyMap(XK_less, KEY_OEM_102));
\r
1576 KeyMap.push_back(SKeyMap(XK_equal, KEY_PLUS));
\r
1577 KeyMap.push_back(SKeyMap(XK_greater, 0)); //?
\r
1578 KeyMap.push_back(SKeyMap(XK_question, 0)); //?
\r
1579 KeyMap.push_back(SKeyMap(XK_at, KEY_KEY_2)); //?
\r
1580 KeyMap.push_back(SKeyMap(XK_mu, 0)); //?
\r
1581 KeyMap.push_back(SKeyMap(XK_EuroSign, 0)); //?
\r
1582 KeyMap.push_back(SKeyMap(XK_A, KEY_KEY_A));
\r
1583 KeyMap.push_back(SKeyMap(XK_B, KEY_KEY_B));
\r
1584 KeyMap.push_back(SKeyMap(XK_C, KEY_KEY_C));
\r
1585 KeyMap.push_back(SKeyMap(XK_D, KEY_KEY_D));
\r
1586 KeyMap.push_back(SKeyMap(XK_E, KEY_KEY_E));
\r
1587 KeyMap.push_back(SKeyMap(XK_F, KEY_KEY_F));
\r
1588 KeyMap.push_back(SKeyMap(XK_G, KEY_KEY_G));
\r
1589 KeyMap.push_back(SKeyMap(XK_H, KEY_KEY_H));
\r
1590 KeyMap.push_back(SKeyMap(XK_I, KEY_KEY_I));
\r
1591 KeyMap.push_back(SKeyMap(XK_J, KEY_KEY_J));
\r
1592 KeyMap.push_back(SKeyMap(XK_K, KEY_KEY_K));
\r
1593 KeyMap.push_back(SKeyMap(XK_L, KEY_KEY_L));
\r
1594 KeyMap.push_back(SKeyMap(XK_M, KEY_KEY_M));
\r
1595 KeyMap.push_back(SKeyMap(XK_N, KEY_KEY_N));
\r
1596 KeyMap.push_back(SKeyMap(XK_O, KEY_KEY_O));
\r
1597 KeyMap.push_back(SKeyMap(XK_P, KEY_KEY_P));
\r
1598 KeyMap.push_back(SKeyMap(XK_Q, KEY_KEY_Q));
\r
1599 KeyMap.push_back(SKeyMap(XK_R, KEY_KEY_R));
\r
1600 KeyMap.push_back(SKeyMap(XK_S, KEY_KEY_S));
\r
1601 KeyMap.push_back(SKeyMap(XK_T, KEY_KEY_T));
\r
1602 KeyMap.push_back(SKeyMap(XK_U, KEY_KEY_U));
\r
1603 KeyMap.push_back(SKeyMap(XK_V, KEY_KEY_V));
\r
1604 KeyMap.push_back(SKeyMap(XK_W, KEY_KEY_W));
\r
1605 KeyMap.push_back(SKeyMap(XK_X, KEY_KEY_X));
\r
1606 KeyMap.push_back(SKeyMap(XK_Y, KEY_KEY_Y));
\r
1607 KeyMap.push_back(SKeyMap(XK_Z, KEY_KEY_Z));
\r
1608 KeyMap.push_back(SKeyMap(XK_bracketleft, KEY_OEM_4));
\r
1609 KeyMap.push_back(SKeyMap(XK_backslash, KEY_OEM_5));
\r
1610 KeyMap.push_back(SKeyMap(XK_bracketright, KEY_OEM_6));
\r
1611 KeyMap.push_back(SKeyMap(XK_asciicircum, KEY_OEM_5));
\r
1612 KeyMap.push_back(SKeyMap(XK_dead_circumflex, KEY_OEM_5));
\r
1613 KeyMap.push_back(SKeyMap(XK_degree, 0)); //?
\r
1614 KeyMap.push_back(SKeyMap(XK_underscore, KEY_MINUS)); //?
\r
1615 KeyMap.push_back(SKeyMap(XK_grave, KEY_OEM_3));
\r
1616 KeyMap.push_back(SKeyMap(XK_dead_grave, KEY_OEM_3));
\r
1617 KeyMap.push_back(SKeyMap(XK_acute, KEY_OEM_6));
\r
1618 KeyMap.push_back(SKeyMap(XK_dead_acute, KEY_OEM_6));
\r
1619 KeyMap.push_back(SKeyMap(XK_a, KEY_KEY_A));
\r
1620 KeyMap.push_back(SKeyMap(XK_b, KEY_KEY_B));
\r
1621 KeyMap.push_back(SKeyMap(XK_c, KEY_KEY_C));
\r
1622 KeyMap.push_back(SKeyMap(XK_d, KEY_KEY_D));
\r
1623 KeyMap.push_back(SKeyMap(XK_e, KEY_KEY_E));
\r
1624 KeyMap.push_back(SKeyMap(XK_f, KEY_KEY_F));
\r
1625 KeyMap.push_back(SKeyMap(XK_g, KEY_KEY_G));
\r
1626 KeyMap.push_back(SKeyMap(XK_h, KEY_KEY_H));
\r
1627 KeyMap.push_back(SKeyMap(XK_i, KEY_KEY_I));
\r
1628 KeyMap.push_back(SKeyMap(XK_j, KEY_KEY_J));
\r
1629 KeyMap.push_back(SKeyMap(XK_k, KEY_KEY_K));
\r
1630 KeyMap.push_back(SKeyMap(XK_l, KEY_KEY_L));
\r
1631 KeyMap.push_back(SKeyMap(XK_m, KEY_KEY_M));
\r
1632 KeyMap.push_back(SKeyMap(XK_n, KEY_KEY_N));
\r
1633 KeyMap.push_back(SKeyMap(XK_o, KEY_KEY_O));
\r
1634 KeyMap.push_back(SKeyMap(XK_p, KEY_KEY_P));
\r
1635 KeyMap.push_back(SKeyMap(XK_q, KEY_KEY_Q));
\r
1636 KeyMap.push_back(SKeyMap(XK_r, KEY_KEY_R));
\r
1637 KeyMap.push_back(SKeyMap(XK_s, KEY_KEY_S));
\r
1638 KeyMap.push_back(SKeyMap(XK_t, KEY_KEY_T));
\r
1639 KeyMap.push_back(SKeyMap(XK_u, KEY_KEY_U));
\r
1640 KeyMap.push_back(SKeyMap(XK_v, KEY_KEY_V));
\r
1641 KeyMap.push_back(SKeyMap(XK_w, KEY_KEY_W));
\r
1642 KeyMap.push_back(SKeyMap(XK_x, KEY_KEY_X));
\r
1643 KeyMap.push_back(SKeyMap(XK_y, KEY_KEY_Y));
\r
1644 KeyMap.push_back(SKeyMap(XK_z, KEY_KEY_Z));
\r
1645 KeyMap.push_back(SKeyMap(XK_ssharp, KEY_OEM_4));
\r
1646 KeyMap.push_back(SKeyMap(XK_adiaeresis, KEY_OEM_7));
\r
1647 KeyMap.push_back(SKeyMap(XK_odiaeresis, KEY_OEM_3));
\r
1648 KeyMap.push_back(SKeyMap(XK_udiaeresis, KEY_OEM_1));
\r
1649 KeyMap.push_back(SKeyMap(XK_Super_L, KEY_LWIN));
\r
1650 KeyMap.push_back(SKeyMap(XK_Super_R, KEY_RWIN));
\r
1656 bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
\r
1658 #if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
\r
1660 joystickInfo.clear();
\r
1663 for (joystick = 0; joystick < 32; ++joystick)
\r
1665 // The joystick device could be here...
\r
1666 core::stringc devName = "/dev/js";
\r
1667 devName += joystick;
\r
1669 SJoystickInfo returnInfo;
\r
1670 JoystickInfo info;
\r
1672 info.fd = open(devName.c_str(), O_RDONLY);
\r
1673 if (-1 == info.fd)
\r
1675 // ...but Ubuntu and possibly other distros
\r
1676 // create the devices in /dev/input
\r
1677 devName = "/dev/input/js";
\r
1678 devName += joystick;
\r
1679 info.fd = open(devName.c_str(), O_RDONLY);
\r
1680 if (-1 == info.fd)
\r
1683 devName = "/dev/joy";
\r
1684 devName += joystick;
\r
1685 info.fd = open(devName.c_str(), O_RDONLY);
\r
1689 if (-1 == info.fd)
\r
1692 #ifdef __FreeBSD__
\r
1696 ioctl( info.fd, JSIOCGAXES, &(info.axes) );
\r
1697 ioctl( info.fd, JSIOCGBUTTONS, &(info.buttons) );
\r
1698 fcntl( info.fd, F_SETFL, O_NONBLOCK );
\r
1701 (void)memset(&info.persistentData, 0, sizeof(info.persistentData));
\r
1702 info.persistentData.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
\r
1703 info.persistentData.JoystickEvent.Joystick = ActiveJoysticks.size();
\r
1705 // There's no obvious way to determine which (if any) axes represent a POV
\r
1706 // hat, so we'll just set it to "not used" and forget about it.
\r
1707 info.persistentData.JoystickEvent.POV = 65535;
\r
1709 ActiveJoysticks.push_back(info);
\r
1711 returnInfo.Joystick = joystick;
\r
1712 returnInfo.PovHat = SJoystickInfo::POV_HAT_UNKNOWN;
\r
1713 returnInfo.Axes = info.axes;
\r
1714 returnInfo.Buttons = info.buttons;
\r
1716 #ifndef __FreeBSD__
\r
1718 ioctl( info.fd, JSIOCGNAME(80), name);
\r
1719 returnInfo.Name = name;
\r
1722 joystickInfo.push_back(returnInfo);
\r
1725 for (joystick = 0; joystick < joystickInfo.size(); ++joystick)
\r
1727 char logString[256];
\r
1728 (void)sprintf(logString, "Found joystick %u, %u axes, %u buttons '%s'",
\r
1729 joystick, joystickInfo[joystick].Axes,
\r
1730 joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str());
\r
1731 os::Printer::log(logString, ELL_INFORMATION);
\r
1737 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
1741 void CIrrDeviceLinux::pollJoysticks()
\r
1743 #if defined (_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
\r
1744 if (0 == ActiveJoysticks.size())
\r
1747 for (u32 j= 0; j< ActiveJoysticks.size(); ++j)
\r
1749 JoystickInfo & info = ActiveJoysticks[j];
\r
1751 #ifdef __FreeBSD__
\r
1752 struct joystick js;
\r
1753 if (read(info.fd, &js, sizeof(js)) == sizeof(js))
\r
1755 info.persistentData.JoystickEvent.ButtonStates = js.b1 | (js.b2 << 1); /* should be a two-bit field */
\r
1756 info.persistentData.JoystickEvent.Axis[0] = js.x; /* X axis */
\r
1757 info.persistentData.JoystickEvent.Axis[1] = js.y; /* Y axis */
\r
1760 struct js_event event;
\r
1761 while (sizeof(event) == read(info.fd, &event, sizeof(event)))
\r
1763 switch(event.type & ~JS_EVENT_INIT)
\r
1765 case JS_EVENT_BUTTON:
\r
1767 info.persistentData.JoystickEvent.ButtonStates |= (1 << event.number);
\r
1769 info.persistentData.JoystickEvent.ButtonStates &= ~(1 << event.number);
\r
1772 case JS_EVENT_AXIS:
\r
1773 if (event.number < SEvent::SJoystickEvent::NUMBER_OF_AXES)
\r
1774 info.persistentData.JoystickEvent.Axis[event.number] = event.value;
\r
1783 // Send an irrlicht joystick event once per ::run() even if no new data were received.
\r
1784 (void)postEventFromUser(info.persistentData);
\r
1786 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
1790 //! Set the current Gamma Value for the Display
\r
1791 bool CIrrDeviceLinux::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast )
\r
1793 #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)
\r
1794 s32 eventbase, errorbase;
\r
1795 #ifdef _IRR_LINUX_X11_VIDMODE_
\r
1796 if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase))
\r
1798 XF86VidModeGamma gamma;
\r
1800 gamma.green=green;
\r
1802 XF86VidModeSetGamma(XDisplay, Screennr, &gamma);
\r
1806 #if defined(_IRR_LINUX_X11_VIDMODE_) && defined(_IRR_LINUX_X11_RANDR_)
\r
1809 #ifdef _IRR_LINUX_X11_RANDR_
\r
1810 if (XRRQueryExtension(XDisplay, &eventbase, &errorbase))
\r
1812 XRRQueryVersion(XDisplay, &eventbase, &errorbase); // major, minor
\r
1813 if (eventbase>=1 && errorbase>1)
\r
1815 #if (RANDR_MAJOR>1 || RANDR_MINOR>1)
\r
1816 XRRCrtcGamma *gamma = XRRGetCrtcGamma(XDisplay, Screennr);
\r
1819 *gamma->red=(u16)red;
\r
1820 *gamma->green=(u16)green;
\r
1821 *gamma->blue=(u16)blue;
\r
1822 XRRSetCrtcGamma(XDisplay, Screennr, gamma);
\r
1823 XRRFreeGamma(gamma);
\r
1835 //! Get the current Gamma Value for the Display
\r
1836 bool CIrrDeviceLinux::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast )
\r
1840 #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)
\r
1841 s32 eventbase, errorbase;
\r
1842 #ifdef _IRR_LINUX_X11_VIDMODE_
\r
1843 if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase))
\r
1845 XF86VidModeGamma gamma;
\r
1846 XF86VidModeGetGamma(XDisplay, Screennr, &gamma);
\r
1848 green = gamma.green;
\r
1849 blue = gamma.blue;
\r
1853 #if defined(_IRR_LINUX_X11_VIDMODE_) && defined(_IRR_LINUX_X11_RANDR_)
\r
1856 #ifdef _IRR_LINUX_X11_RANDR_
\r
1857 if (XRRQueryExtension(XDisplay, &eventbase, &errorbase))
\r
1859 XRRQueryVersion(XDisplay, &eventbase, &errorbase); // major, minor
\r
1860 if (eventbase>=1 && errorbase>1)
\r
1862 #if (RANDR_MAJOR>1 || RANDR_MINOR>1)
\r
1863 XRRCrtcGamma *gamma = XRRGetCrtcGamma(XDisplay, Screennr);
\r
1866 red = *gamma->red;
\r
1867 green = *gamma->green;
\r
1868 blue= *gamma->blue;
\r
1869 XRRFreeGamma(gamma);
\r
1881 //! gets text from the clipboard
\r
1882 //! \return Returns 0 if no string is in there.
\r
1883 const c8* CIrrDeviceLinux::getTextFromClipboard() const
\r
1885 #if defined(_IRR_COMPILE_WITH_X11_)
\r
1886 Window ownerWindow = XGetSelectionOwner (XDisplay, X_ATOM_CLIPBOARD);
\r
1887 if ( ownerWindow == XWindow )
\r
1889 return Clipboard.c_str();
\r
1892 if (ownerWindow != None )
\r
1894 XConvertSelection (XDisplay, X_ATOM_CLIPBOARD, XA_STRING, XA_PRIMARY, ownerWindow, CurrentTime);
\r
1895 XFlush (XDisplay);
\r
1900 unsigned long numItems, bytesLeft, dummy;
\r
1901 unsigned char *data;
\r
1902 XGetWindowProperty (XDisplay, ownerWindow,
\r
1903 XA_PRIMARY, // property name
\r
1905 0, // length (we only check for data, so 0)
\r
1906 0, // Delete 0==false
\r
1907 AnyPropertyType, // AnyPropertyType or property identifier
\r
1908 &type, // return type
\r
1909 &format, // return format
\r
1910 &numItems, // number items
\r
1911 &bytesLeft, // remaining bytes for partial reads
\r
1913 if ( bytesLeft > 0 )
\r
1915 // there is some data to get
\r
1916 int result = XGetWindowProperty (XDisplay, ownerWindow, XA_PRIMARY, 0,
\r
1917 bytesLeft, 0, AnyPropertyType, &type, &format,
\r
1918 &numItems, &dummy, &data);
\r
1919 if (result == Success)
\r
1920 Clipboard = (irr::c8*)data;
\r
1925 return Clipboard.c_str();
\r
1932 //! copies text to the clipboard
\r
1933 void CIrrDeviceLinux::copyToClipboard(const c8* text) const
\r
1935 #if defined(_IRR_COMPILE_WITH_X11_)
\r
1936 // Actually there is no clipboard on X but applications just say they own the clipboard and return text when asked.
\r
1937 // Which btw. also means that on X you lose clipboard content when closing applications.
\r
1939 XSetSelectionOwner (XDisplay, X_ATOM_CLIPBOARD, XWindow, CurrentTime);
\r
1940 XFlush (XDisplay);
\r
1944 #ifdef _IRR_COMPILE_WITH_X11_
\r
1945 // return true if the passed event has the type passed in parameter arg
\r
1946 Bool PredicateIsEventType(Display *display, XEvent *event, XPointer arg)
\r
1948 if ( event && event->type == *(int*)arg )
\r
1950 // os::Printer::log("remove event:", core::stringc((int)arg).c_str(), ELL_INFORMATION);
\r
1955 #endif //_IRR_COMPILE_WITH_X11_
\r
1957 //! Remove all messages pending in the system message loop
\r
1958 void CIrrDeviceLinux::clearSystemMessages()
\r
1960 #ifdef _IRR_COMPILE_WITH_X11_
\r
1961 if (CreationParams.DriverType != video::EDT_NULL)
\r
1964 int usrArg = ButtonPress;
\r
1965 while ( XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {}
\r
1966 usrArg = ButtonRelease;
\r
1967 while ( XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {}
\r
1968 usrArg = MotionNotify;
\r
1969 while ( XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {}
\r
1970 usrArg = KeyRelease;
\r
1971 while ( XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {}
\r
1972 usrArg = KeyPress;
\r
1973 while ( XCheckIfEvent(XDisplay, &event, PredicateIsEventType, XPointer(&usrArg)) == True ) {}
\r
1975 #endif //_IRR_COMPILE_WITH_X11_
\r
1978 void CIrrDeviceLinux::initXAtoms()
\r
1980 #ifdef _IRR_COMPILE_WITH_X11_
\r
1981 X_ATOM_CLIPBOARD = XInternAtom(XDisplay, "CLIPBOARD", False);
\r
1982 X_ATOM_TARGETS = XInternAtom(XDisplay, "TARGETS", False);
\r
1983 X_ATOM_UTF8_STRING = XInternAtom (XDisplay, "UTF8_STRING", False);
\r
1984 X_ATOM_TEXT = XInternAtom (XDisplay, "TEXT", False);
\r
1985 X_ATOM_NETWM_MAXIMIZE_VERT = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", true);
\r
1986 X_ATOM_NETWM_MAXIMIZE_HORZ = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", true);
\r
1987 X_ATOM_NETWM_STATE = XInternAtom(XDisplay, "_NET_WM_STATE", true);
\r
1992 #ifdef _IRR_COMPILE_WITH_X11_
\r
1994 Cursor CIrrDeviceLinux::TextureToMonochromeCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)
\r
1996 XImage * sourceImage = XCreateImage(XDisplay, VisualInfo->visual,
\r
1998 ZPixmap, // XYBitmap (depth=1), ZPixmap(depth=x)
\r
1999 0, 0, sourceRect.getWidth(), sourceRect.getHeight(),
\r
2000 32, // bitmap_pad,
\r
2001 0// bytes_per_line (0 means continuos in memory)
\r
2003 sourceImage->data = new char[sourceImage->height * sourceImage->bytes_per_line];
\r
2004 XImage * maskImage = XCreateImage(XDisplay, VisualInfo->visual,
\r
2007 0, 0, sourceRect.getWidth(), sourceRect.getHeight(),
\r
2008 32, // bitmap_pad,
\r
2009 0 // bytes_per_line
\r
2011 maskImage->data = new char[maskImage->height * maskImage->bytes_per_line];
\r
2013 // write texture into XImage
\r
2014 video::ECOLOR_FORMAT format = tex->getColorFormat();
\r
2015 u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8;
\r
2016 u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel;
\r
2017 u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel;
\r
2018 const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0);
\r
2019 data += sourceRect.UpperLeftCorner.Y*tex->getPitch();
\r
2020 for ( s32 y = 0; y < sourceRect.getHeight(); ++y )
\r
2022 data += bytesLeftGap;
\r
2023 for ( s32 x = 0; x < sourceRect.getWidth(); ++x )
\r
2025 video::SColor pixelCol;
\r
2026 pixelCol.setData((const void*)data, format);
\r
2027 data += bytesPerPixel;
\r
2029 if ( pixelCol.getAlpha() == 0 ) // transparent
\r
2031 XPutPixel(maskImage, x, y, 0);
\r
2032 XPutPixel(sourceImage, x, y, 0);
\r
2036 if ( pixelCol.getAverage() >= 127 )
\r
2037 XPutPixel(sourceImage, x, y, 1);
\r
2039 XPutPixel(sourceImage, x, y, 0);
\r
2040 XPutPixel(maskImage, x, y, 1);
\r
2043 data += bytesRightGap;
\r
2047 Pixmap sourcePixmap = XCreatePixmap(XDisplay, XWindow, sourceImage->width, sourceImage->height, sourceImage->depth);
\r
2048 Pixmap maskPixmap = XCreatePixmap(XDisplay, XWindow, maskImage->width, maskImage->height, maskImage->depth);
\r
2051 values.foreground = 1;
\r
2052 values.background = 1;
\r
2053 GC gc = XCreateGC( XDisplay, sourcePixmap, GCForeground | GCBackground, &values );
\r
2055 XPutImage(XDisplay, sourcePixmap, gc, sourceImage, 0, 0, 0, 0, sourceImage->width, sourceImage->height);
\r
2056 XPutImage(XDisplay, maskPixmap, gc, maskImage, 0, 0, 0, 0, maskImage->width, maskImage->height);
\r
2058 XFreeGC(XDisplay, gc);
\r
2059 XDestroyImage(sourceImage);
\r
2060 XDestroyImage(maskImage);
\r
2062 Cursor cursorResult = 0;
\r
2063 XColor foreground, background;
\r
2064 foreground.red = 65535;
\r
2065 foreground.green = 65535;
\r
2066 foreground.blue = 65535;
\r
2067 foreground.flags = DoRed | DoGreen | DoBlue;
\r
2068 background.red = 0;
\r
2069 background.green = 0;
\r
2070 background.blue = 0;
\r
2071 background.flags = DoRed | DoGreen | DoBlue;
\r
2073 cursorResult = XCreatePixmapCursor(XDisplay, sourcePixmap, maskPixmap, &foreground, &background, hotspot.X, hotspot.Y);
\r
2075 XFreePixmap(XDisplay, sourcePixmap);
\r
2076 XFreePixmap(XDisplay, maskPixmap);
\r
2078 return cursorResult;
\r
2081 #ifdef _IRR_LINUX_XCURSOR_
\r
2082 Cursor CIrrDeviceLinux::TextureToARGBCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)
\r
2084 XcursorImage * image = XcursorImageCreate (sourceRect.getWidth(), sourceRect.getHeight());
\r
2085 image->xhot = hotspot.X;
\r
2086 image->yhot = hotspot.Y;
\r
2088 // write texture into XcursorImage
\r
2089 video::ECOLOR_FORMAT format = tex->getColorFormat();
\r
2090 u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8;
\r
2091 u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel;
\r
2092 u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel;
\r
2093 XcursorPixel* target = image->pixels;
\r
2094 const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0);
\r
2095 data += sourceRect.UpperLeftCorner.Y*tex->getPitch();
\r
2096 for ( s32 y = 0; y < sourceRect.getHeight(); ++y )
\r
2098 data += bytesLeftGap;
\r
2099 for ( s32 x = 0; x < sourceRect.getWidth(); ++x )
\r
2101 video::SColor pixelCol;
\r
2102 pixelCol.setData((const void*)data, format);
\r
2103 data += bytesPerPixel;
\r
2105 *target = (XcursorPixel)pixelCol.color;
\r
2108 data += bytesRightGap;
\r
2112 Cursor cursorResult=XcursorImageLoadCursor(XDisplay, image);
\r
2114 XcursorImageDestroy(image);
\r
2117 return cursorResult;
\r
2119 #endif // #ifdef _IRR_LINUX_XCURSOR_
\r
2121 Cursor CIrrDeviceLinux::TextureToCursor(irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)
\r
2123 #ifdef _IRR_LINUX_XCURSOR_
\r
2124 return TextureToARGBCursor( tex, sourceRect, hotspot );
\r
2126 return TextureToMonochromeCursor( tex, sourceRect, hotspot );
\r
2129 #endif // _IRR_COMPILE_WITH_X11_
\r
2132 CIrrDeviceLinux::CCursorControl::CCursorControl(CIrrDeviceLinux* dev, bool null)
\r
2134 #ifdef _IRR_COMPILE_WITH_X11_
\r
2135 , PlatformBehavior(gui::ECPB_NONE), LastQuery(0)
\r
2137 , IsVisible(true), Null(null), UseReferenceRect(false)
\r
2138 , ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0)
\r
2140 #ifdef _IRR_COMPILE_WITH_X11_
\r
2144 unsigned long valuemask = 0;
\r
2148 // this code, for making the cursor invisible was sent in by
\r
2149 // Sirshane, thank your very much!
\r
2152 Pixmap invisBitmap = XCreatePixmap(Device->XDisplay, Device->XWindow, 32, 32, 1);
\r
2153 Pixmap maskBitmap = XCreatePixmap(Device->XDisplay, Device->XWindow, 32, 32, 1);
\r
2154 Colormap screen_colormap = DefaultColormap( Device->XDisplay, DefaultScreen( Device->XDisplay ) );
\r
2155 XAllocNamedColor( Device->XDisplay, screen_colormap, "black", &fg, &fg );
\r
2156 XAllocNamedColor( Device->XDisplay, screen_colormap, "white", &bg, &bg );
\r
2158 GC gc = XCreateGC( Device->XDisplay, invisBitmap, valuemask, &values );
\r
2160 XSetForeground( Device->XDisplay, gc, BlackPixel( Device->XDisplay, DefaultScreen( Device->XDisplay ) ) );
\r
2161 XFillRectangle( Device->XDisplay, invisBitmap, gc, 0, 0, 32, 32 );
\r
2162 XFillRectangle( Device->XDisplay, maskBitmap, gc, 0, 0, 32, 32 );
\r
2164 InvisCursor = XCreatePixmapCursor( Device->XDisplay, invisBitmap, maskBitmap, &fg, &bg, 1, 1 );
\r
2165 XFreeGC(Device->XDisplay, gc);
\r
2166 XFreePixmap(Device->XDisplay, invisBitmap);
\r
2167 XFreePixmap(Device->XDisplay, maskBitmap);
\r
2174 CIrrDeviceLinux::CCursorControl::~CCursorControl()
\r
2176 // Do not clearCursors here as the display is already closed
\r
2177 // TODO (cutealien): droping cursorcontrol earlier might work, not sure about reason why that's done in stub currently.
\r
2180 #ifdef _IRR_COMPILE_WITH_X11_
\r
2181 void CIrrDeviceLinux::CCursorControl::clearCursors()
\r
2184 XFreeCursor(Device->XDisplay, InvisCursor);
\r
2185 for ( u32 i=0; i < Cursors.size(); ++i )
\r
2187 for ( u32 f=0; f < Cursors[i].Frames.size(); ++f )
\r
2189 XFreeCursor(Device->XDisplay, Cursors[i].Frames[f].IconHW);
\r
2194 void CIrrDeviceLinux::CCursorControl::initCursors()
\r
2196 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_top_left_arrow)) ); // (or XC_arrow?)
\r
2197 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_crosshair)) );
\r
2198 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_hand2)) ); // (or XC_hand1? )
\r
2199 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_question_arrow)) );
\r
2200 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_xterm)) );
\r
2201 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_X_cursor)) ); // (or XC_pirate?)
\r
2202 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_watch)) ); // (or XC_clock?)
\r
2203 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_fleur)) );
\r
2204 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_top_right_corner)) ); // NESW not available in X11
\r
2205 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_top_left_corner)) ); // NWSE not available in X11
\r
2206 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_sb_v_double_arrow)) );
\r
2207 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_sb_h_double_arrow)) );
\r
2208 Cursors.push_back( CursorX11(XCreateFontCursor(Device->XDisplay, XC_sb_up_arrow)) ); // (or XC_center_ptr?)
\r
2211 void CIrrDeviceLinux::CCursorControl::update()
\r
2213 if ( (u32)ActiveIcon < Cursors.size() && !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime )
\r
2215 // update animated cursors. This could also be done by X11 in case someone wants to figure that out (this way was just easier to implement)
\r
2216 u32 now = Device->getTimer()->getRealTime();
\r
2217 u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size();
\r
2218 XDefineCursor(Device->XDisplay, Device->XWindow, Cursors[ActiveIcon].Frames[frame].IconHW);
\r
2223 //! Sets the active cursor icon
\r
2224 void CIrrDeviceLinux::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId)
\r
2226 #ifdef _IRR_COMPILE_WITH_X11_
\r
2227 if ( iconId >= (s32)Cursors.size() )
\r
2230 if ( Cursors[iconId].Frames.size() )
\r
2231 XDefineCursor(Device->XDisplay, Device->XWindow, Cursors[iconId].Frames[0].IconHW);
\r
2233 ActiveIconStartTime = Device->getTimer()->getRealTime();
\r
2234 ActiveIcon = iconId;
\r
2239 //! Add a custom sprite as cursor icon.
\r
2240 gui::ECURSOR_ICON CIrrDeviceLinux::CCursorControl::addIcon(const gui::SCursorSprite& icon)
\r
2242 #ifdef _IRR_COMPILE_WITH_X11_
\r
2243 if ( icon.SpriteId >= 0 )
\r
2246 cX11.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
\r
2247 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
\r
2249 irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
\r
2250 irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
\r
2251 irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
\r
2252 Cursor cursor = Device->TextureToCursor(icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
\r
2253 cX11.Frames.push_back( CursorFrameX11(cursor) );
\r
2256 Cursors.push_back( cX11 );
\r
2258 return (gui::ECURSOR_ICON)(Cursors.size() - 1);
\r
2261 return gui::ECI_NORMAL;
\r
2264 //! replace the given cursor icon.
\r
2265 void CIrrDeviceLinux::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon)
\r
2267 #ifdef _IRR_COMPILE_WITH_X11_
\r
2268 if ( iconId >= (s32)Cursors.size() )
\r
2271 for ( u32 i=0; i < Cursors[iconId].Frames.size(); ++i )
\r
2272 XFreeCursor(Device->XDisplay, Cursors[iconId].Frames[i].IconHW);
\r
2274 if ( icon.SpriteId >= 0 )
\r
2277 cX11.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
\r
2278 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
\r
2280 irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
\r
2281 irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
\r
2282 irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
\r
2283 Cursor cursor = Device->TextureToCursor(icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
\r
2284 cX11.Frames.push_back( CursorFrameX11(cursor) );
\r
2287 Cursors[iconId] = cX11;
\r
2292 irr::core::dimension2di CIrrDeviceLinux::CCursorControl::getSupportedIconSize() const
\r
2294 // this returns the closest match that is smaller or same size, so we just pass a value which should be large enough for cursors
\r
2295 unsigned int width=0, height=0;
\r
2296 #ifdef _IRR_COMPILE_WITH_X11_
\r
2297 XQueryBestCursor(Device->XDisplay, Device->XWindow, 64, 64, &width, &height);
\r
2299 return core::dimension2di(width, height);
\r
2302 } // end namespace
\r
2304 #endif // _IRR_COMPILE_WITH_X11_DEVICE_
\r